feat: 新增启动参数设置页面,区分 desktop 可编辑与 server 只读
This commit is contained in:
223
backend/internal/handler/settings_handler.go
Normal file
223
backend/internal/handler/settings_handler.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"nex/backend/internal/config"
|
||||
appErrors "nex/backend/pkg/errors"
|
||||
)
|
||||
|
||||
type SettingsHandler struct {
|
||||
runtimeCfg *config.Config
|
||||
mode string
|
||||
editable bool
|
||||
configPath string
|
||||
}
|
||||
|
||||
func NewSettingsHandler(runtimeCfg *config.Config, mode string, editable bool, configPath string) *SettingsHandler {
|
||||
return &SettingsHandler{
|
||||
runtimeCfg: runtimeCfg,
|
||||
mode: mode,
|
||||
editable: editable,
|
||||
configPath: configPath,
|
||||
}
|
||||
}
|
||||
|
||||
type serverConfigDTO struct {
|
||||
Port int `json:"port"`
|
||||
ReadTimeout string `json:"read_timeout"`
|
||||
WriteTimeout string `json:"write_timeout"`
|
||||
}
|
||||
|
||||
type databaseConfigDTO struct {
|
||||
Driver string `json:"driver"`
|
||||
Path string `json:"path"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
DBName string `json:"dbname"`
|
||||
MaxIdleConns int `json:"max_idle_conns"`
|
||||
MaxOpenConns int `json:"max_open_conns"`
|
||||
ConnMaxLifetime string `json:"conn_max_lifetime"`
|
||||
}
|
||||
|
||||
type logConfigDTO struct {
|
||||
Level string `json:"level"`
|
||||
Path string `json:"path"`
|
||||
MaxSize int `json:"max_size"`
|
||||
MaxBackups int `json:"max_backups"`
|
||||
MaxAge int `json:"max_age"`
|
||||
Compress bool `json:"compress"`
|
||||
}
|
||||
|
||||
type startupSettingsDTO struct {
|
||||
Server serverConfigDTO `json:"server"`
|
||||
Database databaseConfigDTO `json:"database"`
|
||||
Log logConfigDTO `json:"log"`
|
||||
}
|
||||
|
||||
type startupSettingsResponse struct {
|
||||
Mode string `json:"mode"`
|
||||
Editable bool `json:"editable"`
|
||||
ConfigPath string `json:"config_path"`
|
||||
RestartRequired bool `json:"restart_required"`
|
||||
Config startupSettingsDTO `json:"config"`
|
||||
}
|
||||
|
||||
func configToDTO(cfg *config.Config) startupSettingsDTO {
|
||||
return startupSettingsDTO{
|
||||
Server: serverConfigDTO{
|
||||
Port: cfg.Server.Port,
|
||||
ReadTimeout: cfg.Server.ReadTimeout.String(),
|
||||
WriteTimeout: cfg.Server.WriteTimeout.String(),
|
||||
},
|
||||
Database: databaseConfigDTO{
|
||||
Driver: cfg.Database.Driver,
|
||||
Path: cfg.Database.Path,
|
||||
Host: cfg.Database.Host,
|
||||
Port: cfg.Database.Port,
|
||||
User: cfg.Database.User,
|
||||
Password: cfg.Database.Password,
|
||||
DBName: cfg.Database.DBName,
|
||||
MaxIdleConns: cfg.Database.MaxIdleConns,
|
||||
MaxOpenConns: cfg.Database.MaxOpenConns,
|
||||
ConnMaxLifetime: cfg.Database.ConnMaxLifetime.String(),
|
||||
},
|
||||
Log: logConfigDTO{
|
||||
Level: cfg.Log.Level,
|
||||
Path: cfg.Log.Path,
|
||||
MaxSize: cfg.Log.MaxSize,
|
||||
MaxBackups: cfg.Log.MaxBackups,
|
||||
MaxAge: cfg.Log.MaxAge,
|
||||
Compress: cfg.Log.Compress,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func dtoToConfig(dto startupSettingsDTO) (*config.Config, error) {
|
||||
readTimeout, err := time.ParseDuration(dto.Server.ReadTimeout)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "read_timeout 格式错误,例如 30s")
|
||||
}
|
||||
writeTimeout, err := time.ParseDuration(dto.Server.WriteTimeout)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "write_timeout 格式错误,例如 30s")
|
||||
}
|
||||
connMaxLifetime, err := time.ParseDuration(dto.Database.ConnMaxLifetime)
|
||||
if err != nil {
|
||||
return nil, appErrors.WithMessage(appErrors.ErrInvalidRequest, "conn_max_lifetime 格式错误,例如 1h")
|
||||
}
|
||||
|
||||
return &config.Config{
|
||||
Server: config.ServerConfig{
|
||||
Port: dto.Server.Port,
|
||||
ReadTimeout: readTimeout,
|
||||
WriteTimeout: writeTimeout,
|
||||
},
|
||||
Database: config.DatabaseConfig{
|
||||
Driver: dto.Database.Driver,
|
||||
Path: dto.Database.Path,
|
||||
Host: dto.Database.Host,
|
||||
Port: dto.Database.Port,
|
||||
User: dto.Database.User,
|
||||
Password: dto.Database.Password,
|
||||
DBName: dto.Database.DBName,
|
||||
MaxIdleConns: dto.Database.MaxIdleConns,
|
||||
MaxOpenConns: dto.Database.MaxOpenConns,
|
||||
ConnMaxLifetime: connMaxLifetime,
|
||||
},
|
||||
Log: config.LogConfig{
|
||||
Level: dto.Log.Level,
|
||||
Path: dto.Log.Path,
|
||||
MaxSize: dto.Log.MaxSize,
|
||||
MaxBackups: dto.Log.MaxBackups,
|
||||
MaxAge: dto.Log.MaxAge,
|
||||
Compress: dto.Log.Compress,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) GetStartupSettings(c *gin.Context) {
|
||||
var cfg *config.Config
|
||||
var configPath string
|
||||
|
||||
if h.mode == "desktop" {
|
||||
desktopCfg, err := config.LoadDesktopConfigAtPath(h.configPath)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
cfg = desktopCfg
|
||||
configPath = h.configPath
|
||||
} else {
|
||||
cfg = h.runtimeCfg
|
||||
configPath = h.configPath
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, startupSettingsResponse{
|
||||
Mode: h.mode,
|
||||
Editable: h.editable,
|
||||
ConfigPath: configPath,
|
||||
RestartRequired: h.editable,
|
||||
Config: configToDTO(cfg),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) SaveStartupSettings(c *gin.Context) {
|
||||
if !h.editable {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"error": "server 模式下不允许保存启动参数",
|
||||
"code": "forbidden",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Config startupSettingsDTO `json:"config"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "无效的请求格式",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := dtoToConfig(req.Config)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := cfg.Validate(); err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := config.SaveConfigToPath(cfg, h.configPath); err != nil {
|
||||
if errors.Is(err, appErrors.ErrInvalidRequest) {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
writeError(c, appErrors.Wrap(appErrors.ErrInternal, err))
|
||||
return
|
||||
}
|
||||
|
||||
savedCfg, err := config.LoadDesktopConfigAtPath(h.configPath)
|
||||
if err != nil {
|
||||
writeError(c, appErrors.Wrap(appErrors.ErrInternal, err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, startupSettingsResponse{
|
||||
Mode: h.mode,
|
||||
Editable: h.editable,
|
||||
ConfigPath: h.configPath,
|
||||
RestartRequired: true,
|
||||
Config: configToDTO(savedCfg),
|
||||
})
|
||||
}
|
||||
418
backend/internal/handler/settings_handler_test.go
Normal file
418
backend/internal/handler/settings_handler_test.go
Normal file
@@ -0,0 +1,418 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user