package config_test import ( "os" "path/filepath" "strings" "testing" "iop/packages/go/config" ) func TestLoadEdge_EdgeIdentity(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nedge:\n id: \"edge-dgx-group\"\n name: \"DGX Group\"\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Edge.ID != "edge-dgx-group" { t.Fatalf("expected edge.id=%q, got %q", "edge-dgx-group", cfg.Edge.ID) } if cfg.Edge.Name != "DGX Group" { t.Fatalf("expected edge.name=%q, got %q", "DGX Group", cfg.Edge.Name) } } func TestLoadEdge_EdgeIdentityEmptyByDefault(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Edge.ID != "" || cfg.Edge.Name != "" { t.Fatalf("expected empty edge identity by default, got id=%q name=%q", cfg.Edge.ID, cfg.Edge.Name) } } func TestLoadEdge_ConsoleTimeoutDefault(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.TimeoutSec != 120 { t.Fatalf("expected default timeout_sec=120, got %d", cfg.Console.TimeoutSec) } if cfg.Console.Adapter != "cli" { t.Fatalf("expected default console.adapter=%q, got %q", "cli", cfg.Console.Adapter) } if cfg.Console.ResolveTarget() != "claude" { t.Fatalf("expected default console.target=%q, got %q", "claude", cfg.Console.ResolveTarget()) } } func TestLoadEdge_OpenAIDefaults(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.OpenAI.Enabled { t.Fatal("expected openai.enabled=false by default") } if cfg.OpenAI.Listen != "0.0.0.0:18081" { t.Fatalf("expected openai.listen default, got %q", cfg.OpenAI.Listen) } if cfg.OpenAI.Adapter != "ollama" { t.Fatalf("expected openai.adapter=%q, got %q", "ollama", cfg.OpenAI.Adapter) } if cfg.OpenAI.SessionID != "openai" { t.Fatalf("expected openai.session_id=%q, got %q", "openai", cfg.OpenAI.SessionID) } if cfg.OpenAI.TimeoutSec != 120 { t.Fatalf("expected openai.timeout_sec=120, got %d", cfg.OpenAI.TimeoutSec) } if !cfg.OpenAI.StrictOutput { t.Fatal("expected openai.strict_output=true") } if cfg.OpenAI.StrictStreamBuffer { t.Fatal("expected openai.strict_stream_buffer=false") } if cfg.Metrics.Port != 19092 { t.Fatalf("expected metrics.port=19092, got %d", cfg.Metrics.Port) } } func TestLoadEdge_OpenAIOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" openai: enabled: true listen: "127.0.0.1:8088" node: "node0" adapter: "ollama" target: "llama-test" models: - "llama-test" session_id: "cline" timeout_sec: 45 strict_output: false strict_stream_buffer: true ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if !cfg.OpenAI.Enabled { t.Fatal("expected openai.enabled=true") } if cfg.OpenAI.Listen != "127.0.0.1:8088" || cfg.OpenAI.NodeRef != "node0" { t.Fatalf("unexpected openai routing config: %+v", cfg.OpenAI) } if cfg.OpenAI.Target != "llama-test" || len(cfg.OpenAI.Models) != 1 || cfg.OpenAI.Models[0] != "llama-test" { t.Fatalf("unexpected openai model config: %+v", cfg.OpenAI) } if cfg.OpenAI.SessionID != "cline" || cfg.OpenAI.TimeoutSec != 45 { t.Fatalf("unexpected openai execution config: %+v", cfg.OpenAI) } if cfg.OpenAI.StrictOutput { t.Fatalf("unexpected openai strict output config: %+v", cfg.OpenAI) } if !cfg.OpenAI.StrictStreamBuffer { t.Fatalf("unexpected openai strict stream buffer config: %+v", cfg.OpenAI) } } func TestLoadEdge_OllamaContextSize(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: ollama: enabled: true base_url: "http://192.168.0.91:11434" context_size: 262144 capacity: 3 max_queue: 8 queue_timeout_ms: 1500 request_timeout_ms: 30000 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } ollama := cfg.Nodes[0].Adapters.Ollama if !ollama.Enabled { t.Fatal("expected ollama.enabled=true") } if ollama.BaseURL != "http://192.168.0.91:11434" || ollama.ContextSize != 262144 { t.Fatalf("unexpected ollama config: %+v", ollama) } if ollama.Capacity != 3 || ollama.MaxQueue != 8 || ollama.QueueTimeoutMS != 1500 || ollama.RequestTimeoutMS != 30000 { t.Fatalf("unexpected ollama queue config: %+v", ollama) } } func TestLoadEdge_ConsoleSessionDefaults(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.SessionID != "default" { t.Fatalf("expected default session_id=%q, got %q", "default", cfg.Console.SessionID) } if cfg.Console.Background { t.Fatal("expected default background=false") } } func TestLoadEdge_ConsoleSessionOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nconsole:\n session_id: \"worker-1\"\n background: true\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.SessionID != "worker-1" { t.Fatalf("expected session_id=%q, got %q", "worker-1", cfg.Console.SessionID) } if !cfg.Console.Background { t.Fatal("expected background=true") } } func TestLoadEdge_ConsoleTimeoutOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nconsole:\n timeout_sec: 45\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.TimeoutSec != 45 { t.Fatalf("expected timeout_sec=45, got %d", cfg.Console.TimeoutSec) } } func TestLoadEdge_ConsoleTargetOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nconsole:\n target: \"codex\"\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.ResolveTarget() != "codex" { t.Fatalf("expected console.target to resolve to %q, got %q", "codex", cfg.Console.ResolveTarget()) } } func TestLoadEdge_ConsoleTargetFallbackFromLegacyAgent(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nconsole:\n agent: \"codex\"\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.ResolveTarget() != "codex" { t.Fatalf("expected legacy console.agent fallback to resolve to %q, got %q", "codex", cfg.Console.ResolveTarget()) } } func TestLoadEdge_ConsoleTargetFallbackFromLegacyModel(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nconsole:\n model: \"codex\"\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Console.ResolveTarget() != "codex" { t.Fatalf("expected legacy console.model fallback to resolve to %q, got %q", "codex", cfg.Console.ResolveTarget()) } } func TestLoadEdge_CodexProfile(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: codex: command: "codex" output_format: "codex-json" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } codex, ok := cfg.Nodes[0].Adapters.CLI.Profiles["codex"] if !ok { t.Fatal("expected codex profile") } if codex.Command != "codex" || codex.OutputFormat != "codex-json" { t.Errorf("unexpected codex profile: %+v", codex) } } func TestLoadEdge_AntigravityProfile(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: antigravity: command: "agy" args: - "--dangerously-skip-permissions" - "--print-timeout" - "10m" - "--print" resume_args: - "--dangerously-skip-permissions" - "--print-timeout" - "10m" - "--conversation" mode: "antigravity-print" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } agy, ok := cfg.Nodes[0].Adapters.CLI.Profiles["antigravity"] if !ok { t.Fatal("expected antigravity profile") } if agy.Command != "agy" { t.Errorf("expected command agy, got %q", agy.Command) } expectedArgs := []string{"--dangerously-skip-permissions", "--print-timeout", "10m", "--print"} if len(agy.Args) != len(expectedArgs) { t.Fatalf("expected %d args, got %d: %v", len(expectedArgs), len(agy.Args), agy.Args) } for i, v := range expectedArgs { if agy.Args[i] != v { t.Errorf("args[%d]: expected %q, got %q", i, v, agy.Args[i]) } } if agy.OutputFormat != "" { t.Errorf("expected empty output format, got %q", agy.OutputFormat) } if agy.Mode != "antigravity-print" { t.Errorf("expected mode antigravity-print, got %q", agy.Mode) } expectedResume := []string{"--dangerously-skip-permissions", "--print-timeout", "10m", "--conversation"} if len(agy.ResumeArgs) != len(expectedResume) { t.Fatalf("expected %d resume_args, got %d: %v", len(expectedResume), len(agy.ResumeArgs), agy.ResumeArgs) } for i, v := range expectedResume { if agy.ResumeArgs[i] != v { t.Errorf("resume_args[%d]: expected %q, got %q", i, v, agy.ResumeArgs[i]) } } } func TestCLIProfileConf_CompletionMarkerUnmarshal(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: marker-test: command: "mycli" completion_marker: line: "<>" regex: "^DONE \\d+$" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } profile, ok := cfg.Nodes[0].Adapters.CLI.Profiles["marker-test"] if !ok { t.Fatal("expected marker-test profile") } if profile.CompletionMarker.Line != "<>" { t.Errorf("expected Line=%q, got %q", "<>", profile.CompletionMarker.Line) } if profile.CompletionMarker.Regex != "^DONE \\d+$" { t.Errorf("expected Regex=%q, got %q", "^DONE \\d+$", profile.CompletionMarker.Regex) } } func TestCompletionMarkerConf_Empty(t *testing.T) { var empty config.CompletionMarkerConf if !empty.Empty() { t.Fatal("expected Empty() == true for zero value") } lineOnly := config.CompletionMarkerConf{Line: "<>"} if lineOnly.Empty() { t.Fatal("expected Empty() == false when Line is set") } regexOnly := config.CompletionMarkerConf{Regex: "^END$"} if regexOnly.Empty() { t.Fatal("expected Empty() == false when Regex is set") } bothSet := config.CompletionMarkerConf{Line: "<>", Regex: "^END$"} if bothSet.Empty() { t.Fatal("expected Empty() == false when both are set") } } func TestCompletionMarkerConf_LineOnlyUnmarshal(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: line-only: command: "mycli" completion_marker: line: "<>" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } profile, ok := cfg.Nodes[0].Adapters.CLI.Profiles["line-only"] if !ok { t.Fatal("expected line-only profile") } if profile.CompletionMarker.Line != "<>" { t.Errorf("expected Line=%q, got %q", "<>", profile.CompletionMarker.Line) } if profile.CompletionMarker.Regex != "" { t.Errorf("expected empty Regex, got %q", profile.CompletionMarker.Regex) } if profile.CompletionMarker.Empty() { t.Fatal("expected Empty() == false when only Line is set") } } func TestCompletionMarkerConf_RegexOnlyUnmarshal(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: regex-only: command: "mycli" completion_marker: regex: "^DONE \\d+$" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } profile, ok := cfg.Nodes[0].Adapters.CLI.Profiles["regex-only"] if !ok { t.Fatal("expected regex-only profile") } if profile.CompletionMarker.Regex != "^DONE \\d+$" { t.Errorf("expected Regex=%q, got %q", "^DONE \\d+$", profile.CompletionMarker.Regex) } if profile.CompletionMarker.Line != "" { t.Errorf("expected empty Line, got %q", profile.CompletionMarker.Line) } if profile.CompletionMarker.Empty() { t.Fatal("expected Empty() == false when only Regex is set") } } func TestLoadEdge_CLIProfileMode(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: codex: command: "codex" args: - "exec" - "--json" resume_args: - "exec" - "resume" - "--json" mode: "codex-exec" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } profile, ok := cfg.Nodes[0].Adapters.CLI.Profiles["codex"] if !ok { t.Fatal("expected codex profile") } if profile.Mode != "codex-exec" { t.Errorf("expected mode=%q, got %q", "codex-exec", profile.Mode) } expectedResume := []string{"exec", "resume", "--json"} if len(profile.ResumeArgs) != len(expectedResume) { t.Fatalf("expected %d resume_args, got %d: %v", len(expectedResume), len(profile.ResumeArgs), profile.ResumeArgs) } for i, v := range expectedResume { if profile.ResumeArgs[i] != v { t.Errorf("resume_args[%d]: expected %q, got %q", i, v, profile.ResumeArgs[i]) } } } func TestLoadEdge_OpencodeSSEProfile(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: opencode: command: "/usr/local/bin/opencode" args: - "--title" - "untitle" - "--model" - "ollama-dgx/qwen3.6:35b-a3b-bf16" - "--dangerously-skip-permissions" mode: "opencode-sse" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } prof, ok := cfg.Nodes[0].Adapters.CLI.Profiles["opencode"] if !ok { t.Fatal("expected opencode profile") } if prof.Mode != "opencode-sse" { t.Errorf("mode: got %q", prof.Mode) } expectedArgs := []string{"--title", "untitle", "--model", "ollama-dgx/qwen3.6:35b-a3b-bf16", "--dangerously-skip-permissions"} if len(prof.Args) != len(expectedArgs) { t.Fatalf("args len: got %d, want %d", len(prof.Args), len(expectedArgs)) } for i, want := range expectedArgs { if prof.Args[i] != want { t.Errorf("args[%d]: got %q, want %q", i, prof.Args[i], want) } } } func TestCLIProfileConf_CompletionMarkerEmpty(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: no-marker: command: "mycli" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } profile, ok := cfg.Nodes[0].Adapters.CLI.Profiles["no-marker"] if !ok { t.Fatal("expected no-marker profile") } if !profile.CompletionMarker.Empty() { t.Fatal("expected Empty() == true when completion_marker is not specified") } } func TestLoadEdge_AdvertiseHostAndArtifactDefaultsEmpty(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Server.AdvertiseHost != "" { t.Errorf("expected empty server.advertise_host by default, got %q", cfg.Server.AdvertiseHost) } if cfg.Bootstrap.ArtifactBaseURL != "" { t.Errorf("expected empty bootstrap.artifact_base_url by default, got %q", cfg.Bootstrap.ArtifactBaseURL) } if cfg.Logging.Path != "" { t.Errorf("expected empty logging.path by default, got %q", cfg.Logging.Path) } } func TestLoadEdge_AdvertiseHostAndArtifactExplicit(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := `server: listen: "0.0.0.0:9090" advertise_host: "edge.example.test" bootstrap: artifact_base_url: "http://edge.example.test:18080" logging: path: "/var/log/iop/edge.log" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Server.AdvertiseHost != "edge.example.test" { t.Errorf("server.advertise_host=%q", cfg.Server.AdvertiseHost) } if cfg.Bootstrap.ArtifactBaseURL != "http://edge.example.test:18080" { t.Errorf("bootstrap.artifact_base_url=%q", cfg.Bootstrap.ArtifactBaseURL) } if cfg.Logging.Path != "/var/log/iop/edge.log" { t.Errorf("logging.path=%q", cfg.Logging.Path) } } func TestLoadEdge_A2ADefaults(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.A2A.Enabled { t.Fatal("expected a2a.enabled=false by default") } if cfg.A2A.Listen != "0.0.0.0:8081" { t.Fatalf("expected a2a.listen default, got %q", cfg.A2A.Listen) } if cfg.A2A.Path != "/a2a" { t.Fatalf("expected a2a.path=%q, got %q", "/a2a", cfg.A2A.Path) } if cfg.A2A.Adapter != "cli" { t.Fatalf("expected a2a.adapter=%q, got %q", "cli", cfg.A2A.Adapter) } if cfg.A2A.SessionID != "a2a" { t.Fatalf("expected a2a.session_id=%q, got %q", "a2a", cfg.A2A.SessionID) } if cfg.A2A.TimeoutSec != 120 { t.Fatalf("expected a2a.timeout_sec=120, got %d", cfg.A2A.TimeoutSec) } if cfg.A2A.BearerToken != "" { t.Fatalf("expected a2a.bearer_token empty by default, got %q", cfg.A2A.BearerToken) } } func TestCompletionMarkerConf_RegexAndLineUsage(t *testing.T) { lineOnly := config.CompletionMarkerConf{Line: "<>"} if !strings.Contains(lineOnly.Line, "<>") { t.Errorf("expected Line to contain <>, got %q", lineOnly.Line) } regexOnly := config.CompletionMarkerConf{Regex: "^DONE \\d+$"} if !strings.Contains(regexOnly.Regex, "DONE") { t.Errorf("expected Regex to contain DONE, got %q", regexOnly.Regex) } both := config.CompletionMarkerConf{Line: "<>", Regex: "^DONE \\d+$"} if both.Line != "<>" || both.Regex != "^DONE \\d+$" { t.Errorf("expected both fields set, got %+v", both) } if both.Empty() { t.Fatal("expected Empty() == false when both are set") } } func TestLoadEdge_A2AOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" a2a: enabled: true listen: "127.0.0.1:8082" path: "/agent" node: "node0" adapter: "cli" target: "claude" session_id: "nomad" timeout_sec: 60 bearer_token: "secret-token" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if !cfg.A2A.Enabled { t.Fatal("expected a2a.enabled=true") } if cfg.A2A.Listen != "127.0.0.1:8082" { t.Fatalf("expected a2a.listen=%q, got %q", "127.0.0.1:8082", cfg.A2A.Listen) } if cfg.A2A.Path != "/agent" { t.Fatalf("expected a2a.path=%q, got %q", "/agent", cfg.A2A.Path) } if cfg.A2A.NodeRef != "node0" { t.Fatalf("expected a2a.node=%q, got %q", "node0", cfg.A2A.NodeRef) } if cfg.A2A.Target != "claude" { t.Fatalf("expected a2a.target=%q, got %q", "claude", cfg.A2A.Target) } if cfg.A2A.SessionID != "nomad" { t.Fatalf("expected a2a.session_id=%q, got %q", "nomad", cfg.A2A.SessionID) } if cfg.A2A.TimeoutSec != 60 { t.Fatalf("expected a2a.timeout_sec=60, got %d", cfg.A2A.TimeoutSec) } if cfg.A2A.BearerToken != "secret-token" { t.Fatalf("expected a2a.bearer_token=%q, got %q", "secret-token", cfg.A2A.BearerToken) } } func TestLoadEdge_NodeAgentKindGeneric(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := `server: listen: "0.0.0.0:9090" nodes: - alias: "node-local" token: "token-node" agent_kind: "generic-node" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } if cfg.Nodes[0].AgentKind != config.AgentKindGenericNode { t.Fatalf("expected agent_kind=%q, got %q", config.AgentKindGenericNode, cfg.Nodes[0].AgentKind) } } func TestLoadEdge_NodeAgentKindDefault(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := `server: listen: "0.0.0.0:9090" nodes: - alias: "node-local" token: "token-node" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } if cfg.Nodes[0].AgentKind != config.AgentKindGenericNode { t.Fatalf("expected default agent_kind=%q, got %q", config.AgentKindGenericNode, cfg.Nodes[0].AgentKind) } } func TestLoadEdge_NodeAgentKindRejectsInvalid(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "bad-local" token: "token-bad" agent_kind: "not-a-kind" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected invalid agent_kind error") } if !strings.Contains(err.Error(), "agent_kind") { t.Fatalf("expected error to mention agent_kind, got %v", err) } } func TestLoadEdge_ControlPlaneDefaults(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte("server:\n listen: \"0.0.0.0:9090\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.ControlPlane.Enabled { t.Fatal("expected control_plane.enabled=false by default") } if cfg.ControlPlane.WireAddr != "" { t.Fatalf("expected control_plane.wire_addr empty by default, got %q", cfg.ControlPlane.WireAddr) } if cfg.ControlPlane.ReconnectIntervalSec != 5 { t.Fatalf("expected control_plane.reconnect_interval_sec=5, got %d", cfg.ControlPlane.ReconnectIntervalSec) } } func TestLoadEdge_MultiOllamaInstances(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "multi" adapters: ollama_instances: - name: "local" enabled: true base_url: "http://127.0.0.1:11434" context_size: 131072 capacity: 2 max_queue: 4 queue_timeout_ms: 1000 request_timeout_ms: 20000 - name: "dgx" enabled: true base_url: "http://192.168.0.91:11434" context_size: 262144 capacity: 6 max_queue: 12 queue_timeout_ms: 2000 request_timeout_ms: 60000 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } insts := cfg.Nodes[0].Adapters.OllamaInstances if len(insts) != 2 { t.Fatalf("expected 2 ollama instances, got %d", len(insts)) } if insts[0].Name != "local" || insts[0].BaseURL != "http://127.0.0.1:11434" || insts[0].ContextSize != 131072 { t.Errorf("unexpected instance[0]: %+v", insts[0]) } if insts[0].Capacity != 2 || insts[0].MaxQueue != 4 || insts[0].QueueTimeoutMS != 1000 || insts[0].RequestTimeoutMS != 20000 { t.Errorf("unexpected instance[0] queue config: %+v", insts[0]) } if insts[1].Name != "dgx" || insts[1].BaseURL != "http://192.168.0.91:11434" || insts[1].ContextSize != 262144 { t.Errorf("unexpected instance[1]: %+v", insts[1]) } if insts[1].Capacity != 6 || insts[1].MaxQueue != 12 || insts[1].QueueTimeoutMS != 2000 || insts[1].RequestTimeoutMS != 60000 { t.Errorf("unexpected instance[1] queue config: %+v", insts[1]) } } func TestLoadEdge_MultiVllmInstances(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "multi-vllm" adapters: vllm_instances: - name: "a100" enabled: true endpoint: "http://10.0.0.5:8000" capacity: 4 max_queue: 10 queue_timeout_ms: 1500 request_timeout_ms: 45000 - name: "h100" enabled: true endpoint: "http://10.0.0.6:8000" capacity: 8 max_queue: 16 queue_timeout_ms: 2500 request_timeout_ms: 90000 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } insts := cfg.Nodes[0].Adapters.VllmInstances if len(insts) != 2 { t.Fatalf("expected 2 vllm instances, got %d", len(insts)) } if insts[0].Name != "a100" || insts[0].Endpoint != "http://10.0.0.5:8000" { t.Errorf("unexpected instance[0]: %+v", insts[0]) } if insts[0].Capacity != 4 || insts[0].MaxQueue != 10 || insts[0].QueueTimeoutMS != 1500 || insts[0].RequestTimeoutMS != 45000 { t.Errorf("unexpected instance[0] queue config: %+v", insts[0]) } if insts[1].Name != "h100" || insts[1].Endpoint != "http://10.0.0.6:8000" { t.Errorf("unexpected instance[1]: %+v", insts[1]) } if insts[1].Capacity != 8 || insts[1].MaxQueue != 16 || insts[1].QueueTimeoutMS != 2500 || insts[1].RequestTimeoutMS != 90000 { t.Errorf("unexpected instance[1] queue config: %+v", insts[1]) } } func TestLoadEdge_LegacyOllamaPromotedToInstances(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: ollama: enabled: true base_url: "http://192.168.0.91:11434" context_size: 262144 capacity: 5 max_queue: 9 queue_timeout_ms: 1700 request_timeout_ms: 55000 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } insts := cfg.Nodes[0].Adapters.OllamaInstances if len(insts) != 1 { t.Fatalf("expected 1 ollama instance from legacy field, got %d", len(insts)) } if insts[0].Name != "ollama" { t.Errorf("expected instance name %q, got %q", "ollama", insts[0].Name) } if insts[0].BaseURL != "http://192.168.0.91:11434" { t.Errorf("expected base_url %q, got %q", "http://192.168.0.91:11434", insts[0].BaseURL) } if insts[0].Capacity != 5 || insts[0].MaxQueue != 9 || insts[0].QueueTimeoutMS != 1700 || insts[0].RequestTimeoutMS != 55000 { t.Errorf("unexpected promoted queue config: %+v", insts[0]) } } func TestLoadEdge_DuplicateOllamaInstanceNameRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "dup" adapters: ollama_instances: - name: "same" enabled: true base_url: "http://127.0.0.1:11434" - name: "same" enabled: true base_url: "http://127.0.0.2:11434" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate ollama instance name") } } func TestLoadEdge_ProviderQueueConfigRejectsNegative(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "bad-queue" adapters: ollama_instances: - name: "local" enabled: true base_url: "http://127.0.0.1:11434" capacity: -1 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected negative provider queue config error") } if !strings.Contains(err.Error(), "capacity") || !strings.Contains(err.Error(), "non-negative") { t.Fatalf("expected error to mention capacity non-negative, got %v", err) } } func TestLoadEdge_OpenAIRouteCatalog(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" openai: enabled: true listen: "0.0.0.0:18081" adapter: "ollama" model_routes: - model: "model-a" adapter: "ollama" target: "llama3" node: "node-01" session_id: "sess-a" timeout_sec: 30 - model: "model-b" adapter: "vllm" target: "qwen" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.OpenAI.ModelRoutes) != 2 { t.Fatalf("expected 2 model_routes, got %d", len(cfg.OpenAI.ModelRoutes)) } r0 := cfg.OpenAI.ModelRoutes[0] if r0.Model != "model-a" || r0.Adapter != "ollama" || r0.Target != "llama3" { t.Errorf("route[0] mismatch: %+v", r0) } if r0.NodeRef != "node-01" || r0.SessionID != "sess-a" || r0.TimeoutSec != 30 { t.Errorf("route[0] optional fields mismatch: %+v", r0) } if r0.WorkspaceRequired { t.Errorf("route[0] workspace_required should default to false: %+v", r0) } r1 := cfg.OpenAI.ModelRoutes[1] if r1.Model != "model-b" || r1.Adapter != "vllm" || r1.Target != "qwen" { t.Errorf("route[1] mismatch: %+v", r1) } if r1.WorkspaceRequired { t.Errorf("route[1] workspace_required should default to false: %+v", r1) } } func TestLoadEdge_OpenAIRouteCatalogWorkspaceRequired(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" openai: enabled: true model_routes: - model: "codex" adapter: "cli" target: "codex" workspace_required: true - model: "llama3" adapter: "ollama" target: "llama3:8b" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.OpenAI.ModelRoutes) != 2 { t.Fatalf("expected 2 model_routes, got %d", len(cfg.OpenAI.ModelRoutes)) } agent := cfg.OpenAI.ModelRoutes[0] if agent.Model != "codex" || agent.Adapter != "cli" || agent.Target != "codex" { t.Errorf("agent route mismatch: %+v", agent) } if !agent.WorkspaceRequired { t.Errorf("agent route workspace_required should be true: %+v", agent) } inference := cfg.OpenAI.ModelRoutes[1] if inference.Model != "llama3" || inference.Adapter != "ollama" || inference.Target != "llama3:8b" { t.Errorf("inference route mismatch: %+v", inference) } if inference.WorkspaceRequired { t.Errorf("inference route workspace_required should be false: %+v", inference) } } func TestLoadEdge_OpenAIRouteCatalogDuplicateModelRejects(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" openai: model_routes: - model: "model-a" adapter: "ollama" target: "llama3" - model: "model-a" adapter: "vllm" target: "qwen" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for duplicate model route") } if !strings.Contains(err.Error(), "model_routes") || !strings.Contains(err.Error(), "model-a") { t.Fatalf("expected error mentioning model_routes and model-a, got %v", err) } } func TestLoadEdge_OpenAIRouteCatalogEmptyModelRejects(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" openai: model_routes: - model: "" target: "llama3" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatal("expected error for empty model in route catalog") } if !strings.Contains(err.Error(), "model_routes") { t.Fatalf("expected error mentioning model_routes, got %v", err) } } // NormalizeAdapters regression tests func TestNormalizeAdapters_OllamaIdempotent(t *testing.T) { a := config.AdaptersConf{ Ollama: config.OllamaConf{Enabled: true, BaseURL: "http://127.0.0.1:11434", ContextSize: 4096}, } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("first normalize: %v", err) } if len(a.OllamaInstances) != 1 { t.Fatalf("expected 1 instance after first normalize, got %d", len(a.OllamaInstances)) } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("second normalize (idempotent): %v", err) } if len(a.OllamaInstances) != 1 { t.Fatalf("expected still 1 instance after second normalize, got %d", len(a.OllamaInstances)) } } func TestNormalizeAdapters_VllmIdempotent(t *testing.T) { a := config.AdaptersConf{ Vllm: config.VllmConf{Enabled: true, Endpoint: "http://127.0.0.1:8000"}, } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("first normalize: %v", err) } if len(a.VllmInstances) != 1 { t.Fatalf("expected 1 instance after first normalize, got %d", len(a.VllmInstances)) } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("second normalize (idempotent): %v", err) } if len(a.VllmInstances) != 1 { t.Fatalf("expected still 1 instance after second normalize, got %d", len(a.VllmInstances)) } } func TestNormalizeAdapters_OllamaConflictErrors(t *testing.T) { a := config.AdaptersConf{ Ollama: config.OllamaConf{Enabled: true, BaseURL: "http://127.0.0.1:11434"}, OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://other-host:11434"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for conflicting legacy ollama and explicit instance with same name") } } func TestNormalizeAdapters_VllmConflictErrors(t *testing.T) { a := config.AdaptersConf{ Vllm: config.VllmConf{Enabled: true, Endpoint: "http://127.0.0.1:8000"}, VllmInstances: []config.VllmInstanceConf{ {Name: "vllm", Enabled: true, Endpoint: "http://other-host:8000"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for conflicting legacy vllm and explicit instance with same name") } } func TestNormalizeAdapters_OllamaDisabledSameNameErrors(t *testing.T) { a := config.AdaptersConf{ Ollama: config.OllamaConf{Enabled: true, BaseURL: "http://127.0.0.1:11434"}, OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: false, BaseURL: "http://127.0.0.1:11434"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for legacy enabled ollama conflicting with same-name disabled explicit instance") } } func TestNormalizeAdapters_VllmDisabledSameNameErrors(t *testing.T) { a := config.AdaptersConf{ Vllm: config.VllmConf{Enabled: true, Endpoint: "http://127.0.0.1:8000"}, VllmInstances: []config.VllmInstanceConf{ {Name: "vllm", Enabled: false, Endpoint: "http://127.0.0.1:8000"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for legacy enabled vllm conflicting with same-name disabled explicit instance") } } func TestLoadEdge_CodexAppServerDefaultProfile(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: cli: enabled: true profiles: codex: command: "codex" args: - "app-server" mode: "codex-app-server" codex-exec: command: "codex" args: - "exec" - "--json" resume_args: - "exec" - "resume" - "--json" output_format: "codex-json" mode: "codex-exec" ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } profiles := cfg.Nodes[0].Adapters.CLI.Profiles codex, ok := profiles["codex"] if !ok { t.Fatal("expected codex profile") } if codex.Mode != "codex-app-server" { t.Errorf("codex.Mode = %q, want %q", codex.Mode, "codex-app-server") } if len(codex.Args) != 1 || codex.Args[0] != "app-server" { t.Errorf("codex.Args = %v, want [app-server]", codex.Args) } exec, ok := profiles["codex-exec"] if !ok { t.Fatal("expected codex-exec profile") } if exec.Mode != "codex-exec" { t.Errorf("codex-exec.Mode = %q, want %q", exec.Mode, "codex-exec") } if exec.OutputFormat != "codex-json" { t.Errorf("codex-exec.OutputFormat = %q, want %q", exec.OutputFormat, "codex-json") } expectedResume := []string{"exec", "resume", "--json"} if len(exec.ResumeArgs) != len(expectedResume) { t.Fatalf("codex-exec.ResumeArgs = %v, want %v", exec.ResumeArgs, expectedResume) } for i, v := range expectedResume { if exec.ResumeArgs[i] != v { t.Errorf("codex-exec.ResumeArgs[%d] = %q, want %q", i, exec.ResumeArgs[i], v) } } } func TestLoadEdge_ControlPlaneOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" control_plane: enabled: true wire_addr: "cp.example.test:7070" reconnect_interval_sec: 10 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if !cfg.ControlPlane.Enabled { t.Fatal("expected control_plane.enabled=true") } if cfg.ControlPlane.WireAddr != "cp.example.test:7070" { t.Fatalf("expected control_plane.wire_addr=%q, got %q", "cp.example.test:7070", cfg.ControlPlane.WireAddr) } if cfg.ControlPlane.ReconnectIntervalSec != 10 { t.Fatalf("expected control_plane.reconnect_interval_sec=10, got %d", cfg.ControlPlane.ReconnectIntervalSec) } } func TestLoadEdge_OpenAICompatInstances(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "lemonade-node" adapters: openai_compat_instances: - name: "lemonade" enabled: true provider: "lemonade" endpoint: "http://127.0.0.1:13305" headers: Authorization: "Bearer test-key" capacity: 4 max_queue: 10 queue_timeout_ms: 1500 request_timeout_ms: 30000 ` if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } if len(cfg.Nodes) == 0 { t.Fatal("expected 1 node") } insts := cfg.Nodes[0].Adapters.OpenAICompatInstances if len(insts) != 1 { t.Fatalf("expected 1 openai_compat instance, got %d", len(insts)) } inst := insts[0] if inst.Name != "lemonade" || inst.Provider != "lemonade" || inst.Endpoint != "http://127.0.0.1:13305" { t.Errorf("unexpected instance config: %+v", inst) } if inst.Headers["authorization"] != "Bearer test-key" { t.Errorf("expected header authorization Bearer test-key, got %q", inst.Headers["authorization"]) } if inst.Capacity != 4 || inst.MaxQueue != 10 || inst.QueueTimeoutMS != 1500 || inst.RequestTimeoutMS != 30000 { t.Errorf("unexpected queue config: %+v", inst) } } func TestNormalizeAdapters_OpenAICompatIdempotent(t *testing.T) { a := config.AdaptersConf{ OpenAICompat: config.OpenAICompatConf{ Enabled: true, Provider: "lemonade", Endpoint: "http://127.0.0.1:13305", Headers: map[string]string{"X-Test": "val"}, }, } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("first normalize: %v", err) } if len(a.OpenAICompatInstances) != 1 { t.Fatalf("expected 1 instance after first normalize, got %d", len(a.OpenAICompatInstances)) } if err := config.NormalizeAdapters(&a); err != nil { t.Fatalf("second normalize (idempotent): %v", err) } if len(a.OpenAICompatInstances) != 1 { t.Fatalf("expected still 1 instance after second normalize, got %d", len(a.OpenAICompatInstances)) } } func TestNormalizeAdapters_OpenAICompatConflictErrors(t *testing.T) { a := config.AdaptersConf{ OpenAICompat: config.OpenAICompatConf{Enabled: true, Endpoint: "http://127.0.0.1:13305"}, OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "openai_compat", Enabled: true, Endpoint: "http://other-host:13305"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for conflicting legacy openai_compat and explicit instance with same name") } } func TestNormalizeAdapters_OpenAICompatDuplicateNameRejects(t *testing.T) { a := config.AdaptersConf{ OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "same", Enabled: true, Endpoint: "http://127.0.0.1:13305"}, {Name: "same", Enabled: true, Endpoint: "http://127.0.0.2:13305"}, }, } if err := config.NormalizeAdapters(&a); err == nil { t.Fatal("expected error for duplicate openai_compat instance name") } } func TestNormalizeAdapters_OpenAICompatQueueValidation(t *testing.T) { a := config.AdaptersConf{ OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "test", Enabled: true, Endpoint: "http://127.0.0.1:13305", Capacity: -1}, }, } err := config.NormalizeAdapters(&a) if err == nil { t.Fatal("expected negative provider queue config error") } if !strings.Contains(err.Error(), "capacity") { t.Fatalf("expected error to mention capacity, got %v", err) } }