Files
AetherForge/server/config_test.go

228 lines
6.2 KiB
Go

package main
import (
"encoding/json"
"os"
"path/filepath"
"testing"
)
func applyMergeFromJSON(t *testing.T, dst *Config, payload string) {
t.Helper()
var incoming Config
if err := json.Unmarshal([]byte(payload), &incoming); err != nil {
t.Fatalf("unmarshal incoming: %v", err)
}
var present map[string]json.RawMessage
if err := json.Unmarshal([]byte(payload), &present); err != nil {
t.Fatalf("unmarshal present keys: %v", err)
}
mergeConfigExplicit(dst, &incoming, present)
}
func TestDefaultConfigServerDefaults(t *testing.T) {
cfg := DefaultConfig()
if cfg.Port != 8989 {
t.Fatalf("port default: got %d", cfg.Port)
}
if cfg.Pool.Host != "pool.supportxmr.com" || !cfg.Pool.UseTLS {
t.Fatalf("pool defaults wrong: %+v", cfg.Pool)
}
if cfg.Server.StatsRetentionHours != 168 {
t.Fatalf("stats retention default: got %d", cfg.Server.StatsRetentionHours)
}
if cfg.Server.MaxAgents != 256 {
t.Fatalf("max agents default: got %d", cfg.Server.MaxAgents)
}
if !cfg.Server.LogAgentConnections {
t.Fatal("log_agent_connections should default true")
}
if cfg.Server.DashboardSubtitle != "security is just an emotion" {
t.Fatalf("dashboard subtitle default wrong: %q", cfg.Server.DashboardSubtitle)
}
if cfg.DefaultAgent.Threads != 4 {
t.Fatalf("default agent threads: got %d", cfg.DefaultAgent.Threads)
}
}
func TestMergeConfigExplicitPortOnlyPreservesPoolTLS(t *testing.T) {
dst := DefaultConfig()
dst.Pool.UseTLS = true
applyMergeFromJSON(t, dst, `{"port":9000}`)
if dst.Port != 9000 {
t.Fatalf("port not merged")
}
if !dst.Pool.UseTLS {
t.Fatal("partial PUT with port only must not reset pool.use_tls")
}
}
func TestMergeConfigExplicitNestedServerPartialPreservesBooleans(t *testing.T) {
dst := DefaultConfig()
dst.Server.LogAgentConnections = true
dst.Server.OpenFirewallOnStart = true
dst.Server.DashboardSubtitle = "keep-me"
applyMergeFromJSON(t, dst, `{"server":{"dashboard_subtitle":"updated"}}`)
if dst.Server.DashboardSubtitle != "updated" {
t.Fatalf("subtitle not updated: %q", dst.Server.DashboardSubtitle)
}
if !dst.Server.LogAgentConnections {
t.Fatal("nested partial PUT must not reset log_agent_connections")
}
if !dst.Server.OpenFirewallOnStart {
t.Fatal("nested partial PUT must not reset open_firewall_on_start")
}
}
func TestMergeConfigExplicitNestedPoolPartialPreservesUseTLS(t *testing.T) {
dst := DefaultConfig()
dst.Pool.UseTLS = true
dst.Pool.Host = "original.pool"
applyMergeFromJSON(t, dst, `{"pool":{"host":"new.pool.example"}}`)
if dst.Pool.Host != "new.pool.example" {
t.Fatalf("host not updated: %q", dst.Pool.Host)
}
if !dst.Pool.UseTLS {
t.Fatal("nested partial pool PUT must preserve use_tls")
}
}
func TestMergeConfigExplicitExplicitBooleanFalse(t *testing.T) {
dst := DefaultConfig()
if !dst.Pool.UseTLS {
t.Fatal("precondition: default pool TLS true")
}
applyMergeFromJSON(t, dst, `{"pool":{"use_tls":false}}`)
if dst.Pool.UseTLS {
t.Fatal("explicit use_tls:false must be applied")
}
}
func TestMergeConfigExplicitAbsentSectionUntouched(t *testing.T) {
dst := DefaultConfig()
dst.Wallet.Address = "48keep"
applyMergeFromJSON(t, dst, `{"port":7777}`)
if dst.Wallet.Address != "48keep" {
t.Fatalf("wallet should be untouched: %q", dst.Wallet.Address)
}
}
func TestMergeConfigExplicitNilPresentKeysFallsBack(t *testing.T) {
dst := DefaultConfig()
dst.Pool.UseTLS = true
src := &Config{Port: 9000}
mergeConfigExplicit(dst, src, nil)
if dst.Port != 9000 {
t.Fatalf("port not merged via fallback")
}
// mergeConfig fallback still overwrites bools — documented legacy path
if dst.Pool.UseTLS {
t.Log("mergeConfig fallback resets UseTLS when presentKeys nil (LoadConfig uses mergeConfig)")
}
}
func TestMergeConfigExplicitDefaultAgentConfigKey(t *testing.T) {
dst := DefaultConfig()
dst.DefaultAgent.AdaptToHardware = true
dst.DefaultAgent.Threads = 8
applyMergeFromJSON(t, dst, `{"default_agent_config":{"threads":2}}`)
if dst.DefaultAgent.Threads != 2 {
t.Fatalf("threads not updated: %d", dst.DefaultAgent.Threads)
}
if !dst.DefaultAgent.AdaptToHardware {
t.Fatal("partial default_agent_config must preserve adapt_to_hardware")
}
}
func TestMergeConfigExplicitBackgroundPartial(t *testing.T) {
dst := DefaultConfig()
dst.Background.AutoStart = true
dst.Background.SilentMode = true
applyMergeFromJSON(t, dst, `{"background":{"auto_start":false}}`)
if dst.Background.AutoStart {
t.Fatal("explicit auto_start:false must apply")
}
if !dst.Background.SilentMode {
t.Fatal("partial background PUT must preserve silent_mode")
}
}
func TestMergeConfigExplicitAlertsEmailEnabled(t *testing.T) {
dst := DefaultConfig()
dst.Alerts.EmailEnabled = false
applyMergeFromJSON(t, dst, `{"alerts":{"email_enabled":true}}`)
if !dst.Alerts.EmailEnabled {
t.Fatal("explicit email_enabled:true must apply")
}
}
func TestMergeConfigPreservesPoolTLSWhenPartialUpdate(t *testing.T) {
dst := DefaultConfig()
dst.Pool.UseTLS = true
src := &Config{Port: 9000}
mergeConfig(dst, src)
if dst.Port != 9000 {
t.Fatalf("port not merged")
}
// mergeConfig (file load path) still resets bools — known legacy behaviour
if !dst.Pool.UseTLS {
t.Log("mergeConfig resets UseTLS on partial update — file load uses mergeConfig not mergeConfigExplicit")
}
}
func TestConfigJSONRoundTrip(t *testing.T) {
cfg := DefaultConfig()
cfg.Wallet.Address = "48testwallet"
data, err := json.Marshal(cfg)
if err != nil {
t.Fatal(err)
}
var decoded Config
if err := json.Unmarshal(data, &decoded); err != nil {
t.Fatal(err)
}
if decoded.Wallet.Address != cfg.Wallet.Address {
t.Fatalf("wallet mismatch")
}
}
func TestDefaultConfigPort(t *testing.T) {
cfg := DefaultConfig()
if cfg.Port != 8989 {
t.Fatalf("expected port 8989, got %d", cfg.Port)
}
}
func TestLoadConfigFromFile(t *testing.T) {
dir := t.TempDir()
cfgPath := filepath.Join(dir, "config.json")
data, err := json.Marshal(DefaultConfig())
if err != nil {
t.Fatal(err)
}
if err := os.WriteFile(cfgPath, data, 0644); err != nil {
t.Fatal(err)
}
raw, err := os.ReadFile(cfgPath)
if err != nil {
t.Fatal(err)
}
var loaded Config
if err := json.Unmarshal(raw, &loaded); err != nil {
t.Fatal(err)
}
if loaded.Port != 8989 {
t.Fatalf("expected port 8989, got %d", loaded.Port)
}
}