419 lines
12 KiB
Go
419 lines
12 KiB
Go
package handler
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
"nex/backend/internal/config"
|
|
)
|
|
|
|
func init() {
|
|
gin.SetMode(gin.TestMode)
|
|
}
|
|
|
|
func createTestConfig(t *testing.T) (*config.Config, string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
configPath := filepath.Join(dir, "config.yaml")
|
|
|
|
cfg := config.DefaultConfig()
|
|
cfg.Database.Path = filepath.Join(dir, "test.db")
|
|
cfg.Log.Path = filepath.Join(dir, "log")
|
|
data, err := yaml.Marshal(cfg)
|
|
require.NoError(t, err)
|
|
require.NoError(t, os.WriteFile(configPath, data, 0o600))
|
|
|
|
return cfg, configPath
|
|
}
|
|
|
|
func TestSettingsHandler_GetStartupSettings_Desktop(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/api/settings/startup", nil)
|
|
|
|
h.GetStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, "desktop", resp.Mode)
|
|
assert.True(t, resp.Editable)
|
|
assert.True(t, resp.RestartRequired)
|
|
assert.Equal(t, configPath, resp.ConfigPath)
|
|
assert.Equal(t, cfg.Server.Port, resp.Config.Server.Port)
|
|
assert.Equal(t, "30s", resp.Config.Server.ReadTimeout)
|
|
assert.Equal(t, cfg.Database.Driver, resp.Config.Database.Driver)
|
|
}
|
|
|
|
func TestSettingsHandler_GetStartupSettings_Server(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "server", false, configPath)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/api/settings/startup", nil)
|
|
|
|
h.GetStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, "server", resp.Mode)
|
|
assert.False(t, resp.Editable)
|
|
assert.False(t, resp.RestartRequired)
|
|
assert.Equal(t, configPath, resp.ConfigPath)
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Desktop(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
newPort := 9999
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": newPort,
|
|
"read_timeout": "30s",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "sqlite",
|
|
"path": filepath.Join(t.TempDir(), "new.db"),
|
|
"port": 3306,
|
|
"dbname": "nex",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": filepath.Join(t.TempDir(), "log"),
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, newPort, resp.Config.Server.Port)
|
|
assert.True(t, resp.Editable)
|
|
assert.True(t, resp.RestartRequired)
|
|
|
|
savedCfg, err := config.LoadDesktopConfigAtPath(configPath)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, newPort, savedCfg.Server.Port)
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Server_Forbidden(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "server", false, configPath)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": 9999,
|
|
"read_timeout": "30s",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "sqlite",
|
|
"path": "/tmp/test.db",
|
|
"port": 3306,
|
|
"dbname": "nex",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": "/tmp/log",
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 403, w.Code)
|
|
assert.Contains(t, w.Body.String(), "不允许保存")
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Desktop_InvalidConfig(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
originalData, err := os.ReadFile(configPath)
|
|
require.NoError(t, err)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": 0,
|
|
"read_timeout": "30s",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "sqlite",
|
|
"path": "/tmp/test.db",
|
|
"port": 3306,
|
|
"dbname": "nex",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": "/tmp/log",
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 400, w.Code)
|
|
|
|
currentData, err := os.ReadFile(configPath)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, originalData, currentData)
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Desktop_InvalidDuration(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": 9826,
|
|
"read_timeout": "not-a-duration",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "sqlite",
|
|
"path": "/tmp/test.db",
|
|
"port": 3306,
|
|
"dbname": "nex",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": "/tmp/log",
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 400, w.Code)
|
|
assert.Contains(t, w.Body.String(), "read_timeout")
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Desktop_CreatesConfigFile(t *testing.T) {
|
|
cfg := config.DefaultConfig()
|
|
dir := t.TempDir()
|
|
configPath := filepath.Join(dir, "nex", "config.yaml")
|
|
|
|
_, err := os.Stat(configPath)
|
|
assert.True(t, os.IsNotExist(err))
|
|
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": 9826,
|
|
"read_timeout": "30s",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "sqlite",
|
|
"path": filepath.Join(dir, "test.db"),
|
|
"port": 3306,
|
|
"dbname": "nex",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": filepath.Join(dir, "log"),
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
_, err = os.Stat(configPath)
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_Desktop_PasswordIncluded(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
body, _ := json.Marshal(map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"server": map[string]interface{}{
|
|
"port": 9826,
|
|
"read_timeout": "30s",
|
|
"write_timeout": "30s",
|
|
},
|
|
"database": map[string]interface{}{
|
|
"driver": "mysql",
|
|
"host": "localhost",
|
|
"port": 3306,
|
|
"user": "root",
|
|
"password": "secret123",
|
|
"dbname": "nex",
|
|
"path": "",
|
|
"max_idle_conns": 10,
|
|
"max_open_conns": 100,
|
|
"conn_max_lifetime": "1h",
|
|
},
|
|
"log": map[string]interface{}{
|
|
"level": "info",
|
|
"path": filepath.Join(t.TempDir(), "log"),
|
|
"max_size": 100,
|
|
"max_backups": 10,
|
|
"max_age": 30,
|
|
"compress": true,
|
|
},
|
|
},
|
|
})
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader(body))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, "secret123", resp.Config.Database.Password)
|
|
}
|
|
|
|
func TestSettingsHandler_GetStartupSettings_DesktopReadsConfigFile(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
|
|
savedCfg := config.DefaultConfig()
|
|
savedCfg.Server.Port = 5555
|
|
data, err := yaml.Marshal(savedCfg)
|
|
require.NoError(t, err)
|
|
require.NoError(t, os.WriteFile(configPath, data, 0o600))
|
|
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/api/settings/startup", nil)
|
|
|
|
h.GetStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, 5555, resp.Config.Server.Port)
|
|
}
|
|
|
|
func TestSettingsHandler_GetStartupSettings_ServerReturnsRuntime(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
cfg.Server.Port = 7777
|
|
|
|
h := NewSettingsHandler(cfg, "server", false, configPath)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/api/settings/startup", nil)
|
|
|
|
h.GetStartupSettings(c)
|
|
|
|
assert.Equal(t, 200, w.Code)
|
|
|
|
var resp startupSettingsResponse
|
|
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
|
assert.Equal(t, 7777, resp.Config.Server.Port)
|
|
}
|
|
|
|
func TestSettingsHandler_SaveStartupSettings_InvalidJSON(t *testing.T) {
|
|
cfg, configPath := createTestConfig(t)
|
|
h := NewSettingsHandler(cfg, "desktop", true, configPath)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("PUT", "/api/settings/startup", bytes.NewReader([]byte("{invalid")))
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
h.SaveStartupSettings(c)
|
|
|
|
assert.Equal(t, 400, w.Code)
|
|
}
|