package configserver import ( "os" "path/filepath" "testing" ) func TestParseConfigDefaults(t *testing.T) { cfg, err := ParseConfig([]byte(`{"servers":[{"alias":"a","base_url":"http://h:5005","username":"u","password":"p"}]}`)) if err != nil { t.Fatalf("ParseConfig: %v", err) } if !cfg.ReadOnly { t.Fatalf("read_only должен по умолчанию быть true (fail-safe)") } if cfg.Default != "a" { t.Fatalf("default = %q, ожидалось a", cfg.Default) } srv, err := cfg.Server("") if err != nil { t.Fatalf("Server: %v", err) } if srv.TimeoutSec != DefaultTimeoutSec || srv.MaxOutputBytes != DefaultMaxOutputBytes { t.Fatalf("дефолты лимитов не применены: %+v", srv) } } func TestSingleServerShorthand(t *testing.T) { cfg, err := ParseConfig([]byte(`{"base_url":"http://h:5005","username":"u","password":"p"}`)) if err != nil { t.Fatalf("ParseConfig: %v", err) } if len(cfg.Servers) != 1 || cfg.Servers[0].Alias != "default" { t.Fatalf("shorthand не сработал: %+v", cfg.Servers) } if cfg.Default != "default" { t.Fatalf("default = %q", cfg.Default) } } func TestUnresolvedVarFails(t *testing.T) { t.Setenv("OMNI_PRESENT", "x") _ = os.Unsetenv("OMNI_MISSING") _, err := ParseConfig([]byte(`{"servers":[{"alias":"a","base_url":"${OMNI_MISSING}","username":"u","password":"p"}]}`)) if err == nil { t.Fatal("ожидалась ошибка о незаданной переменной") } } func TestUnknownFieldFails(t *testing.T) { _, err := ParseConfig([]byte(`{"servers":[{"alias":"a","base_url":"http://h:5005"}],"typo_field":1}`)) if err == nil { t.Fatal("ожидалась ошибка строгого разбора неизвестного поля") } } func TestHostAllowlist(t *testing.T) { _, err := ParseConfig([]byte(`{"servers":[{"alias":"a","base_url":"http://evil:5005"}],"allow_hosts":["good"]}`)) if err == nil { t.Fatal("ожидалась ошибка: хост вне allow_hosts") } } func TestServerUnknownAlias(t *testing.T) { cfg, err := ParseConfig([]byte(`{"servers":[{"alias":"a","base_url":"http://h:5005"}]}`)) if err != nil { t.Fatal(err) } if _, err := cfg.Server("nope"); err == nil { t.Fatal("ожидалась ошибка неизвестного алиаса") } } func TestLoadFileMergesLocal(t *testing.T) { dir := t.TempDir() main := filepath.Join(dir, "config.json") local := filepath.Join(dir, "config.local.json") if err := os.WriteFile(main, []byte(`{ "servers":[{"alias":"prod","base_url":"http://example:5005","username":"u","password":"p"}], "read_only": true }`), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(local, []byte(`{ "servers":[{"alias":"prod","base_url":"http://127.0.0.1:5005","password":"secret"}], "read_only": false }`), 0o600); err != nil { t.Fatal(err) } cfg, err := LoadFile(main) if err != nil { t.Fatalf("LoadFile: %v", err) } if cfg.ReadOnly { t.Fatal("read_only из local не применён") } srv := cfg.Servers[0] if srv.BaseURL != "http://127.0.0.1:5005" { t.Fatalf("base_url не переопределён: %q", srv.BaseURL) } if srv.Username != "u" { t.Fatalf("username из main потерян: %q", srv.Username) } if srv.Password != "secret" { t.Fatalf("password из local не применён: %q", srv.Password) } }