package config_test import ( "fmt" "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 TestEdgeRefreshDefaults(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.Refresh.Enabled { t.Fatalf("expected refresh.enabled=false by default, got true") } if cfg.Refresh.Listen != "127.0.0.1:19093" { t.Fatalf("expected refresh.listen=%q by default, got %q", "127.0.0.1:19093", cfg.Refresh.Listen) } } func TestEdgeRefreshUnmarshal(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := "server:\n listen: \"0.0.0.0:9090\"\nrefresh:\n enabled: true\n listen: \"127.0.0.1:0\"\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.Refresh.Enabled { t.Fatalf("expected refresh.enabled=true") } if cfg.Refresh.Listen != "127.0.0.1:0" { t.Fatalf("expected refresh.listen=%q, got %q", "127.0.0.1:0", cfg.Refresh.Listen) } } 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.BearerToken != "" { t.Fatalf("expected openai.bearer_token empty by default, got %q", cfg.OpenAI.BearerToken) } 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) } if cfg.LongContextThresholdTokens != 100000 { t.Fatalf("expected long_context_threshold_tokens=100000 by default, got %d", cfg.LongContextThresholdTokens) } } func TestLoadEdge_LongContextThresholdOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" long_context_threshold_tokens: 120000 ` 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.LongContextThresholdTokens != 120000 { t.Fatalf("expected long_context_threshold_tokens=120000, got %d", cfg.LongContextThresholdTokens) } } func TestLoadEdge_LongContextThresholdRejectsNonPositive(t *testing.T) { for _, tc := range []struct { name string value int }{ {name: "zero", value: 0}, {name: "negative", value: -1}, } { t.Run(tc.name, func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := fmt.Sprintf(` server: listen: "0.0.0.0:9090" long_context_threshold_tokens: %d `, tc.value) 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 non-positive long_context_threshold_tokens") } if !strings.Contains(err.Error(), "long_context_threshold_tokens must be positive") { t.Fatalf("expected error mentioning positive threshold, got %v", err) } }) } } 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" bearer_token: "secret-token" 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.BearerToken != "secret-token" { t.Fatalf("expected openai.bearer_token=%q, got %q", "secret-token", cfg.OpenAI.BearerToken) } 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_NodeProviderGlobalUniqueness(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "node-a" providers: - id: "shared-provider" type: "ollama" category: "cli" models: - "model-a" - alias: "node-b" providers: - id: "shared-provider" type: "vllm" category: "api" models: - "model-b" ` 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 duplicate provider id error across nodes") } if !strings.Contains(err.Error(), "shared-provider") { t.Fatalf("expected error to mention 'shared-provider', got %v", err) } } func TestLoadEdge_NodeProviderEnabledDefaultsTrue(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "node-a" token: "tok-a" adapters: vllm: enabled: true endpoint: "http://127.0.0.1:8000/v1" providers: - id: "prov-default" type: "vllm" category: "api" adapter: "vllm" models: ["model-x"] capacity: 2 - id: "prov-explicit-true" type: "vllm" category: "api" adapter: "vllm" models: ["model-y"] capacity: 2 enabled: true - id: "prov-explicit-false" type: "vllm" category: "api" adapter: "vllm" models: ["model-z"] capacity: 2 enabled: false ` 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) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } provs := cfg.Nodes[0].Providers if len(provs) != 3 { t.Fatalf("expected 3 providers, got %d", len(provs)) } byID := map[string]config.NodeProviderConf{} for _, p := range provs { byID[p.ID] = p } // prov-default: Enabled is nil → ProviderEnabled returns true. def := byID["prov-default"] if def.Enabled != nil { t.Errorf("prov-default: expected Enabled=nil (omitted), got %v", def.Enabled) } if !config.ProviderEnabled(def) { t.Error("prov-default: ProviderEnabled must be true when Enabled is nil") } // prov-explicit-true: Enabled is *true → ProviderEnabled returns true. exTrue := byID["prov-explicit-true"] if exTrue.Enabled == nil || !*exTrue.Enabled { t.Errorf("prov-explicit-true: expected Enabled=*true, got %v", exTrue.Enabled) } if !config.ProviderEnabled(exTrue) { t.Error("prov-explicit-true: ProviderEnabled must be true when Enabled=true") } // prov-explicit-false: Enabled is *false → ProviderEnabled returns false. exFalse := byID["prov-explicit-false"] if exFalse.Enabled == nil || *exFalse.Enabled { t.Errorf("prov-explicit-false: expected Enabled=*false, got %v", exFalse.Enabled) } if config.ProviderEnabled(exFalse) { t.Error("prov-explicit-false: ProviderEnabled must be false when Enabled=false") } } 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 max_queue: 10 queue_timeout_ms: 5000 - 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.MaxQueue != 10 || r0.QueueTimeoutMS != 5000 { t.Errorf("route[0] queue policy mismatch: max_queue=%d, queue_timeout_ms=%d", r0.MaxQueue, r0.QueueTimeoutMS) } 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.MaxQueue != 0 || r1.QueueTimeoutMS != 0 { t.Errorf("route[1] queue policy should default to 0: max_queue=%d, queue_timeout_ms=%d", r1.MaxQueue, r1.QueueTimeoutMS) } 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) } } func TestLoadEdge_OpenAIRouteCatalogQueuePolicyRejectsNegative(t *testing.T) { dir := t.TempDir() // Test negative max_queue f1 := filepath.Join(dir, "edge_neg_max.yaml") yaml1 := ` server: listen: "0.0.0.0:9090" openai: model_routes: - model: "model-a" target: "llama3" max_queue: -1 ` if err := os.WriteFile(f1, []byte(yaml1), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f1) if err == nil { t.Fatal("expected error for negative max_queue") } if !strings.Contains(err.Error(), "max_queue must be non-negative") { t.Fatalf("expected error mentioning max_queue must be non-negative, got %v", err) } // Test negative queue_timeout_ms f2 := filepath.Join(dir, "edge_neg_timeout.yaml") yaml2 := ` server: listen: "0.0.0.0:9090" openai: model_routes: - model: "model-a" target: "llama3" queue_timeout_ms: -500 ` if err := os.WriteFile(f2, []byte(yaml2), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err = config.LoadEdge(f2) if err == nil { t.Fatal("expected error for negative queue_timeout_ms") } if !strings.Contains(err.Error(), "queue_timeout_ms must be non-negative") { t.Fatalf("expected error mentioning queue_timeout_ms must be non-negative, 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) } } // S02 REVIEW_VLLM_CONFIG: vLLM OpenAI-compatible route + instance fixture // verifies that alias/target/provider/endpoint/no-headers/timeout/queue are // preserved through config load and mapper/factory contract. // Provider pool schema validation tests (G06) func TestLoadEdge_ModelCatalogBasicHappyPath(t *testing.T) { // Happy path: models[].providers values must match nodes[].providers[].models. dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" display_name: "Qwen 3.6 35B" context_window_tokens: 262144 default_max_tokens: 32768 min_max_tokens: 32768 default_thinking_token_budget: 8192 providers: vllm-gpu: "nvidia/Qwen3.6-35B-A3B-NVFP4" ollama-local: "qwen3.6:35b" nodes: - id: "node-gpu-01" alias: "gpu-node" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B-A3B-NVFP4" capacity: 4 - id: "ollama-local" type: "ollama" category: "local_inference" models: - "qwen3.6:35b" capacity: 2 ` 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.Models) != 1 { t.Fatalf("expected 1 model catalog entry, got %d", len(cfg.Models)) } m := cfg.Models[0] if m.ID != "qwen3.6:35b" { t.Errorf("models[0].ID = %q, want %q", m.ID, "qwen3.6:35b") } if m.DisplayName != "Qwen 3.6 35B" { t.Errorf("models[0].DisplayName = %q, want %q", m.DisplayName, "Qwen 3.6 35B") } if m.ContextWindowTokens != 262144 { t.Errorf("models[0].ContextWindowTokens = %d, want 262144", m.ContextWindowTokens) } if m.DefaultMaxTokens != 32768 { t.Errorf("models[0].DefaultMaxTokens = %d, want 32768", m.DefaultMaxTokens) } if m.MinMaxTokens != 32768 { t.Errorf("models[0].MinMaxTokens = %d, want 32768", m.MinMaxTokens) } if m.DefaultThinkingTokenBudget != 8192 { t.Errorf("models[0].DefaultThinkingTokenBudget = %d, want 8192", m.DefaultThinkingTokenBudget) } if len(m.Providers) != 2 { t.Fatalf("expected 2 providers, got %d", len(m.Providers)) } if m.Providers["vllm-gpu"] != "nvidia/Qwen3.6-35B-A3B-NVFP4" { t.Errorf("providers[vllm-gpu] = %q, want %q", m.Providers["vllm-gpu"], "nvidia/Qwen3.6-35B-A3B-NVFP4") } if m.Providers["ollama-local"] != "qwen3.6:35b" { t.Errorf("providers[ollama-local] = %q, want %q", m.Providers["ollama-local"], "qwen3.6:35b") } if len(cfg.Nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } if len(cfg.Nodes[0].Providers) != 2 { t.Fatalf("expected 2 node providers, got %d", len(cfg.Nodes[0].Providers)) } // Check category resolution. for _, p := range cfg.Nodes[0].Providers { if p.ID == "vllm-gpu" && p.Category != config.CategoryAPI { t.Errorf("providers[vllm-gpu].Category = %q, want %q", p.Category, config.CategoryAPI) } if p.ID == "ollama-local" && p.Category != config.CategoryLocalInference { t.Errorf("providers[ollama-local].Category = %q, want %q", p.Category, config.CategoryLocalInference) } } } func TestLoadEdge_ModelCatalogEmptyModelIDRejected(t *testing.T) { // No models[] on node, so serve model check is skipped (legacy compat). dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "" providers: vllm-gpu: "model-a" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" ` 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 id") } if !strings.Contains(err.Error(), "models[0]") || !strings.Contains(err.Error(), "id must not be empty") { t.Fatalf("expected error mentioning models[0] and id must not be empty, got %v", err) } } func TestLoadEdge_ModelCatalogDuplicateModelIDRejected(t *testing.T) { // serve model membership fail → 다른 error로 먼저 실패해야 하지만 duplicate 체크가 // 먼저 발생하므로 models validation 전에 seen check가 먼저 통과하는 fixture. dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: vllm-gpu: "model-a" - id: "qwen3.6:35b" providers: ollama: "qwen3.6" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "model-a" - id: "ollama" type: "ollama" category: "local_inference" models: - "qwen3.6" ` 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 id") } if !strings.Contains(err.Error(), "duplicate model id") { t.Fatalf("expected error mentioning duplicate model id, got %v", err) } } func TestLoadEdge_ModelCatalogEmptyProvidersRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: {} nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" ` 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 providers") } if !strings.Contains(err.Error(), "providers must not be empty") { t.Fatalf("expected error mentioning providers must not be empty, got %v", err) } } func TestLoadEdge_ModelCatalogContextWindowRejectsNegative(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" context_window_tokens: -1 providers: vllm-gpu: "model-a" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "model-a" ` 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 negative context_window_tokens") } if !strings.Contains(err.Error(), "context_window_tokens must be non-negative") { t.Fatalf("expected error mentioning context_window_tokens, got %v", err) } } func TestLoadEdge_ModelCatalogServedModelMembershipMissing(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: vllm-gpu: "typo-model" nodes: - id: "node-gpu-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B-A3B-NVFP4" ` 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 served model not in provider's models list") } if !strings.Contains(err.Error(), "typo-model") || !strings.Contains(err.Error(), "vllm-gpu") { t.Fatalf("expected error mentioning typo-model and vllm-gpu, got %v", err) } } func TestLoadEdge_ModelCatalogUnresolvedProviderRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: non-existent: "model-a" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" ` 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 unresolved provider id") } if !strings.Contains(err.Error(), "does not resolve") || !strings.Contains(err.Error(), "non-existent") { t.Fatalf("expected error mentioning does not resolve and non-existent, got %v", err) } } func TestLoadEdge_ModelCatalogEmptyProviderIDRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: "": "model-a" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" ` 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 provider id in models[].providers") } if !strings.Contains(err.Error(), "provider id must not be empty") { t.Fatalf("expected error mentioning provider id must not be empty, got %v", err) } } func TestLoadEdge_ModelCatalogEmptyServedModelRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" providers: vllm-gpu: "" nodes: - id: "node-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" ` 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 served model name") } if !strings.Contains(err.Error(), "served model name must not be empty") { t.Fatalf("expected error mentioning served model name must not be empty, got %v", err) } } func TestLoadEdge_NodeProviderConfEmptyIDRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "" type: "vllm" category: "api" ` 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 node provider id") } if !strings.Contains(err.Error(), "providers[].id must not be empty") { t.Fatalf("expected error mentioning providers[].id must not be empty, got %v", err) } } func TestLoadEdge_NodeProviderConfEmptyTypeRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "p1" type: "" category: "api" ` 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 provider type") } if !strings.Contains(err.Error(), "type must not be empty") { t.Fatalf("expected error mentioning type must not be empty, got %v", err) } } func TestLoadEdge_NodeProviderConfInvalidCategoryRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "p1" type: "vllm" category: "invalid_category" ` 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 invalid provider category") } if !strings.Contains(err.Error(), "invalid provider category") { t.Fatalf("expected error mentioning invalid provider category, got %v", err) } } func TestLoadEdge_NodeProviderConfDuplicateIDRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "p1" type: "vllm" category: "api" - id: "p1" type: "ollama" category: "local_inference" ` 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 provider id within a node") } if !strings.Contains(err.Error(), "duplicate provider id") { t.Fatalf("expected error mentioning duplicate provider id, got %v", err) } } func TestLoadEdge_NodeProviderConfNegativeCapacityRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "p1" type: "vllm" category: "api" 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 error for negative provider capacity") } if !strings.Contains(err.Error(), "capacity must be non-negative") { t.Fatalf("expected error mentioning capacity must be non-negative, got %v", err) } } func TestLoadEdge_NodeProviderConfEmptyServedModelRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-01" providers: - id: "p1" type: "vllm" category: "api" models: - "" - "real-model" ` 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 served model in provider models list") } if !strings.Contains(err.Error(), "served model name must not be empty") { t.Fatalf("expected error mentioning served model name must not be empty, got %v", err) } } func TestModelCatalogEntry_Validate(t *testing.T) { providerIDs := map[string]struct{}{ "vllm-gpu": {}, "ollama-loc": {}, } // Happy path with serveModels serveModels := map[string]map[string]struct{}{ "vllm-gpu": {"nvidia/Qwen3.6-35B": {}}, "ollama-loc": {"qwen3.6:35b": {}}, } e := config.ModelCatalogEntry{ ID: "qwen3.6:35b", DisplayName: "Qwen 3.6 35B", ContextWindowTokens: 262144, DefaultMaxTokens: 32768, MinMaxTokens: 32768, DefaultThinkingTokenBudget: 8192, Providers: map[string]string{ "vllm-gpu": "nvidia/Qwen3.6-35B", "ollama-loc": "qwen3.6:35b", }, } if err := e.Validate(providerIDs, serveModels); err != nil { t.Fatalf("expected no error, got: %v", err) } // Happy path without serveModels (legacy behavior) e5 := config.ModelCatalogEntry{ ID: "test", Providers: map[string]string{"vllm-gpu": "m"}, } if err := e5.Validate(providerIDs, nil); err != nil { t.Fatalf("expected no error with nil serveModels, got: %v", err) } // Trimmed empty ID e2 := config.ModelCatalogEntry{ ID: " ", Providers: map[string]string{"vllm-gpu": "m"}, } if err := e2.Validate(providerIDs, serveModels); err == nil { t.Fatal("expected error for trimmed empty ID") } // Empty providers map e3 := config.ModelCatalogEntry{ ID: "test", Providers: map[string]string{}, } if err := e3.Validate(providerIDs, serveModels); err == nil { t.Fatal("expected error for empty providers map") } // Unresolved provider e4 := config.ModelCatalogEntry{ ID: "test", Providers: map[string]string{ "unknown-provider": "m", }, } if err := e4.Validate(providerIDs, serveModels); err == nil { t.Fatal("expected error for unresolved provider") } // Negative and inconsistent generation policy for _, tc := range []struct { name string entry config.ModelCatalogEntry }{ { name: "negative context window tokens", entry: config.ModelCatalogEntry{ ID: "test", ContextWindowTokens: -1, Providers: map[string]string{"vllm-gpu": "m"}, }, }, { name: "negative default max tokens", entry: config.ModelCatalogEntry{ ID: "test", DefaultMaxTokens: -1, Providers: map[string]string{"vllm-gpu": "m"}, }, }, { name: "negative min max tokens", entry: config.ModelCatalogEntry{ ID: "test", MinMaxTokens: -1, Providers: map[string]string{"vllm-gpu": "m"}, }, }, { name: "negative thinking budget", entry: config.ModelCatalogEntry{ ID: "test", DefaultThinkingTokenBudget: -1, Providers: map[string]string{"vllm-gpu": "m"}, }, }, { name: "default below min", entry: config.ModelCatalogEntry{ ID: "test", DefaultMaxTokens: 8, MinMaxTokens: 16, Providers: map[string]string{"vllm-gpu": "m"}, }, }, } { t.Run(tc.name, func(t *testing.T) { if err := tc.entry.Validate(providerIDs, nil); err == nil { t.Fatal("expected error for invalid generation policy") } }) } } func TestNodeProviderConf_Validate(t *testing.T) { // Happy path p := config.NodeProviderConf{ ID: "p1", Type: "vllm", Category: config.CategoryAPI, Models: []string{"model-a", "model-b"}, Capacity: 4, } if err := p.Validate(); err != nil { t.Fatalf("expected no error, got: %v", err) } // Empty ID p2 := config.NodeProviderConf{ID: "", Type: "vllm", Category: config.CategoryAPI} if err := p2.Validate(); err == nil { t.Fatal("expected error for empty ID") } // Empty Type p3 := config.NodeProviderConf{ID: "p1", Type: "", Category: config.CategoryAPI} if err := p3.Validate(); err == nil { t.Fatal("expected error for empty Type") } // Invalid Category p4 := config.NodeProviderConf{ID: "p1", Type: "vllm", Category: "invalid"} if err := p4.Validate(); err == nil { t.Fatal("expected error for invalid category") } // Empty model in models list p5 := config.NodeProviderConf{ ID: "p1", Type: "vllm", Category: config.CategoryAPI, Models: []string{"", "real"}, } if err := p5.Validate(); err == nil { t.Fatal("expected error for empty model in list") } // Negative capacity p6 := config.NodeProviderConf{ ID: "p1", Type: "vllm", Category: config.CategoryAPI, Capacity: -1, } if err := p6.Validate(); err == nil { t.Fatal("expected error for negative capacity") } // Negative max_queue p7 := config.NodeProviderConf{ ID: "p1", Type: "vllm", Category: config.CategoryAPI, MaxQueue: -1, } if err := p7.Validate(); err == nil { t.Fatal("expected error for negative max_queue") } // Negative queue_timeout_ms p8 := config.NodeProviderConf{ ID: "p1", Type: "vllm", Category: config.CategoryAPI, QueueTimeoutMS: -1, } if err := p8.Validate(); err == nil { t.Fatal("expected error for negative queue_timeout_ms") } } func TestLoadEdge_ProviderPoolLegacyCompatibility(t *testing.T) { // Legacy openai.model_routes must still work alongside the new models[]/providers[]. 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 models: - id: "qwen3.6:35b" providers: vllm-gpu: "nvidia/Qwen3.6-35B" nodes: - id: "node-gpu-01" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B" ` 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) != 1 { t.Fatalf("expected 1 legacy route, got %d", len(cfg.OpenAI.ModelRoutes)) } if len(cfg.Models) != 1 { t.Fatalf("expected 1 models[] entry, got %d", len(cfg.Models)) } } // S02 REVIEW_VLLM_CONFIG: vLLM OpenAI-compatible route + instance fixture // verifies that alias/target/provider/endpoint/no-headers/timeout/queue are // preserved through config load and mapper/factory contract. func TestLoadEdge_VLLMOpenAIRouteAndInstance(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: "qwen3.6:35b" adapter: "openai_compat" target: "nvidia/Qwen3.6-35B-A3B-NVFP4" node: "node-vllm-01" max_queue: 10 queue_timeout_ms: 30000 - model: "codex-agent" adapter: "cli" target: "codex" workspace_required: true nodes: - id: "node-vllm-01" alias: "vllm-gpu-node" token: "" adapters: openai_compat_instances: - name: "vllm-gpu" enabled: true provider: "vllm" endpoint: "http://127.0.0.1:8000/v1" capacity: 4 max_queue: 16 queue_timeout_ms: 30000 request_timeout_ms: 120000 cli: enabled: true profiles: codex: command: "codex" 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) } // Verify model_routes: vLLM route has no provider field (only adapter/target). if len(cfg.OpenAI.ModelRoutes) != 2 { t.Fatalf("expected 2 model_routes, got %d", len(cfg.OpenAI.ModelRoutes)) } vllmRoute := cfg.OpenAI.ModelRoutes[0] if vllmRoute.Model != "qwen3.6:35b" { t.Errorf("model: got %q, want %q", vllmRoute.Model, "qwen3.6:35b") } if vllmRoute.Adapter != "openai_compat" { t.Errorf("adapter: got %q, want %q", vllmRoute.Adapter, "openai_compat") } if vllmRoute.Target != "nvidia/Qwen3.6-35B-A3B-NVFP4" { t.Errorf("target: got %q, want %q", vllmRoute.Target, "nvidia/Qwen3.6-35B-A3B-NVFP4") } if vllmRoute.NodeRef != "node-vllm-01" { t.Errorf("node: got %q, want %q", vllmRoute.NodeRef, "node-vllm-01") } if vllmRoute.MaxQueue != 10 || vllmRoute.QueueTimeoutMS != 30000 { t.Errorf("queue policy mismatch: max_queue=%d, queue_timeout_ms=%d", vllmRoute.MaxQueue, vllmRoute.QueueTimeoutMS) } // Codex agent route: workspace_required=true. agentRoute := cfg.OpenAI.ModelRoutes[1] if agentRoute.Model != "codex-agent" || agentRoute.Adapter != "cli" || agentRoute.Target != "codex" { t.Errorf("agent route mismatch: %+v", agentRoute) } if !agentRoute.WorkspaceRequired { t.Error("agent route workspace_required should be true") } // Verify openai_compat_instances: provider="vllm", endpoint, no headers, queue policy. nodes := cfg.Nodes if len(nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(nodes)) } insts := 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 != "vllm-gpu" { t.Errorf("instance name: got %q, want %q", inst.Name, "vllm-gpu") } if inst.Provider != "vllm" { t.Errorf("provider: got %q, want %q", inst.Provider, "vllm") } if inst.Endpoint != "http://127.0.0.1:8000/v1" { t.Errorf("endpoint: got %q, want %q", inst.Endpoint, "http://127.0.0.1:8000/v1") } if len(inst.Headers) != 0 { t.Errorf("expected no headers for vLLM, got %+v", inst.Headers) } if inst.Capacity != 4 || inst.MaxQueue != 16 || inst.QueueTimeoutMS != 30000 || inst.RequestTimeoutMS != 120000 { t.Errorf("queue config mismatch: %+v", inst) } } func TestLoad_NodeReconnectDefaults(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "node.yaml") if err := os.WriteFile(f, []byte("transport:\n edge_addr: \"localhost:9090\"\n token: \"tok\"\n"), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.Load(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Reconnect.IntervalSec != 10 { t.Fatalf("expected reconnect.interval_sec=10, got %d", cfg.Reconnect.IntervalSec) } if cfg.Reconnect.MaxAttempts != 10 { t.Fatalf("expected reconnect.max_attempts=10, got %d", cfg.Reconnect.MaxAttempts) } } func TestLoad_NodeReconnectOverride(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "node.yaml") yaml := "transport:\n edge_addr: \"localhost:9090\"\n token: \"tok\"\nreconnect:\n interval_sec: 30\n max_attempts: 5\n" if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.Load(f) if err != nil { t.Fatalf("load: %v", err) } if cfg.Reconnect.IntervalSec != 30 { t.Fatalf("expected reconnect.interval_sec=30, got %d", cfg.Reconnect.IntervalSec) } if cfg.Reconnect.MaxAttempts != 5 { t.Fatalf("expected reconnect.max_attempts=5, got %d", cfg.Reconnect.MaxAttempts) } } func TestLoadEdge_ProviderFirstNodeProvidersHappyPath(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "gpu-node" providers: - id: "openai-provider" type: "openai_compat" category: "api" endpoint: "http://127.0.0.1:8000/v1" headers: Authorization: "Bearer test" capacity: 5 - id: "ollama-provider" type: "ollama" category: "local_inference" base_url: "http://127.0.0.1:11434" context_size: 4096 capacity: 2 - id: "cli-provider" type: "cli" category: "cli" command: "python" args: ["-m", "cli"] capacity: 1 ` 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) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } providers := cfg.Nodes[0].Providers if len(providers) != 3 { t.Fatalf("expected 3 providers, got %d", len(providers)) } // Verify openai-provider p1 := providers[0] if p1.ID != "openai-provider" || p1.Type != "openai_compat" || p1.Endpoint != "http://127.0.0.1:8000/v1" { t.Errorf("unexpected openai-provider fields: %+v", p1) } if p1.Headers["Authorization"] != "Bearer test" && p1.Headers["authorization"] != "Bearer test" { t.Errorf("expected Authorization header, got %v", p1.Headers) } // Verify ollama-provider p2 := providers[1] if p2.ID != "ollama-provider" || p2.Type != "ollama" || p2.BaseURL != "http://127.0.0.1:11434" || p2.ContextSize != 4096 { t.Errorf("unexpected ollama-provider fields: %+v", p2) } // Verify cli-provider p3 := providers[2] if p3.ID != "cli-provider" || p3.Type != "cli" || p3.Command != "python" || len(p3.Args) != 2 { t.Errorf("unexpected cli-provider fields: %+v", p3) } } func TestLoadEdge_RejectWhitespaceProviderType(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" providers: - id: "whitespace-provider" type: " " category: "api" endpoint: "http://127.0.0.1:8000/v1" ` 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 whitespace provider type, got nil") } if !strings.Contains(err.Error(), "type must not be empty") { t.Fatalf("expected error containing 'type must not be empty', got %v", err) } } // REVIEW_REVIEW_COMPAT-1: TestLoadEdge_LegacyOnlyConfigRegression // verifies that a pure legacy-only config (adapters only, no providers) // still loads successfully and the node has an empty Providers list. func TestLoadEdge_LegacyOnlyConfigRegression(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://127.0.0.1:11434" ` 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("LoadEdge should succeed for pure legacy-only config: %v", err) } if len(cfg.Nodes) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } if len(cfg.Nodes[0].Providers) != 0 { t.Fatalf("expected empty Providers list for legacy-only config, got %d providers", len(cfg.Nodes[0].Providers)) } } // COMPAT-1: TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed verifies that // provider-first resources and legacy adapters with matching fields coexist // without errors when the key (provider id == adapter instance name) is shared. func TestLoadEdge_ProviderFirstLegacyIdenticalMixedAllowed(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://127.0.0.1:11434" context_size: 4096 capacity: 2 providers: - id: "ollama" type: "ollama" category: "local_inference" base_url: "http://127.0.0.1:11434" models: - "llama3:8b" capacity: 2 ` 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("LoadEdge should succeed for identical mixed config: %v", err) } if len(cfg.Nodes) != 1 || len(cfg.Nodes[0].Providers) != 1 { t.Fatalf("expected 1 node with 1 provider, got %d nodes", len(cfg.Nodes)) } } // COMPAT-1: TestLoadEdge_ProviderFirstLegacyConflictRejected verifies that // provider-first resources and legacy adapters with different field values // for the same key produce a validation error. func TestLoadEdge_ProviderFirstLegacyConflictRejected(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://127.0.0.1:11434" capacity: 2 providers: - id: "ollama" type: "ollama" category: "local_inference" base_url: "http://other-host:11434" models: - "llama3:8b" capacity: 2 ` 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 conflicting provider-first and legacy ollama config") } if !strings.Contains(err.Error(), "conflicts with adapters") { t.Fatalf("expected error containing 'conflicts with adapters', got %v", err) } } // REVIEW_COMPAT-1: TestLoadEdge_ProviderFirstLegacyCapacityMismatchZeroProvider // verifies that same-key provider-first/legacy mixed config is rejected when // provider capacity is 0 (not-dispatchable) and legacy capacity is > 0. func TestLoadEdge_ProviderFirstLegacyCapacityMismatchZeroProvider(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://127.0.0.1:11434" capacity: 2 providers: - id: "ollama" type: "ollama" category: "local_inference" base_url: "http://127.0.0.1:11434" models: - "llama3:8b" capacity: 0 ` 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 provider capacity 0 / legacy capacity 2 conflict") } if !strings.Contains(err.Error(), "conflicts with adapters") || !strings.Contains(err.Error(), "capacity mismatch") { t.Fatalf("expected error containing 'conflicts with adapters' and 'capacity mismatch', got %v", err) } } // REVIEW_COMPAT-1: TestLoadEdge_ProviderFirstLegacyCapacityMismatchOmittedProvider // verifies that same-key provider-first/legacy mixed config is rejected when // provider capacity is omitted (defaults to 0) and legacy capacity is > 0. func TestLoadEdge_ProviderFirstLegacyCapacityMismatchOmittedProvider(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://127.0.0.1:11434" capacity: 3 providers: - id: "ollama" type: "ollama" category: "local_inference" base_url: "http://127.0.0.1:11434" models: - "llama3:8b" ` 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 omitted provider capacity / legacy capacity 3 conflict") } if !strings.Contains(err.Error(), "conflicts with adapters") || !strings.Contains(err.Error(), "capacity mismatch") { t.Fatalf("expected error containing 'conflicts with adapters' and 'capacity mismatch', got %v", err) } } // REVIEW_COMPAT-1: TestLoadEdge_ProviderFirstLegacyCapacityMismatchVllm // verifies capacity mismatch rejection for vllm/openai_compat provider type. func TestLoadEdge_ProviderFirstLegacyCapacityMismatchVllm(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "local" adapters: openai_compat_instances: - name: "vllm-gpu" enabled: true endpoint: "http://127.0.0.1:8000/v1" capacity: 4 providers: - id: "vllm-gpu" type: "vllm" category: "api" endpoint: "http://127.0.0.1:8000/v1" models: - "model-a" capacity: 0 ` 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 vllm provider capacity 0 / legacy capacity 4 conflict") } if !strings.Contains(err.Error(), "conflicts with adapters") || !strings.Contains(err.Error(), "capacity mismatch") { t.Fatalf("expected error containing 'conflicts with adapters' and 'capacity mismatch', got %v", err) } } // TestLoadEdge_NodeProviderPriorityOmittedDefaultsZero verifies that when // priority is omitted from a provider entry, it defaults to zero. func TestLoadEdge_NodeProviderPriorityOmittedDefaultsZero(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-p" alias: "n-p" token: "tok-p" providers: - id: "prov-p" type: "vllm" category: "api" endpoint: "http://127.0.0.1:8000/v1" models: - "model-a" capacity: 2 ` 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) != 1 { t.Fatalf("expected 1 node, got %d", len(cfg.Nodes)) } if len(cfg.Nodes[0].Providers) != 1 { t.Fatalf("expected 1 provider, got %d", len(cfg.Nodes[0].Providers)) } if cfg.Nodes[0].Providers[0].Priority != 0 { t.Fatalf("expected default priority=0, got %d", cfg.Nodes[0].Providers[0].Priority) } } // TestLoadEdge_NodeProviderPriorityExplicitLoads verifies that an explicit // priority value is loaded correctly. func TestLoadEdge_NodeProviderPriorityExplicitLoads(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-p2" alias: "n-p2" token: "tok-p2" providers: - id: "prov-p2" type: "vllm" category: "api" endpoint: "http://127.0.0.1:8000/v1" models: - "model-a" capacity: 2 priority: 5 ` 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.Nodes[0].Providers[0].Priority != 5 { t.Fatalf("expected priority=5, got %d", cfg.Nodes[0].Providers[0].Priority) } } // TestLoadEdge_NodeProviderNegativePriorityRejected verifies that a negative // priority value is rejected during config load. func TestLoadEdge_NodeProviderNegativePriorityRejected(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - id: "node-p3" alias: "n-p3" token: "tok-p3" providers: - id: "prov-p3" type: "vllm" category: "api" endpoint: "http://127.0.0.1:8000/v1" models: - "model-a" capacity: 2 priority: -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 error for negative priority") } if !strings.Contains(err.Error(), "priority must be non-negative") { t.Fatalf("expected error mentioning priority non-negative, got %v", err) } } // TestLoadEdgeProviderLongContextCapacityValidation covers the provider-level // long-context fields: a valid config loads the values, and the field-level // invariants (non-negative, and total>0 when long_context_capacity>0) are enforced. func TestLoadEdgeProviderLongContextCapacityValidation(t *testing.T) { validYAML := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" context_window_tokens: 262144 providers: vllm-gpu: "nvidia/Qwen3.6-35B" nodes: - id: "node-gpu-01" alias: "gpu-node" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B" capacity: 4 total_context_tokens: 524288 long_context_capacity: 2 ` t.Run("valid", func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") if err := os.WriteFile(f, []byte(validYAML), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } cfg, err := config.LoadEdge(f) if err != nil { t.Fatalf("load: %v", err) } prov := cfg.Nodes[0].Providers[0] if prov.TotalContextTokens != 524288 { t.Errorf("total_context_tokens = %d, want 524288", prov.TotalContextTokens) } if prov.LongContextCapacity != 2 { t.Errorf("long_context_capacity = %d, want 2", prov.LongContextCapacity) } }) cases := []struct { name string total string long string wantMsg string }{ {"negative total", "total_context_tokens: -1", "long_context_capacity: 0", "total_context_tokens must be non-negative"}, {"negative long", "total_context_tokens: 524288", "long_context_capacity: -1", "long_context_capacity must be non-negative"}, {"long without total", "total_context_tokens: 0", "long_context_capacity: 2", "total_context_tokens must be positive when long_context_capacity"}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := fmt.Sprintf(` server: listen: "0.0.0.0:9090" nodes: - id: "node-gpu-01" alias: "gpu-node" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B" capacity: 4 %s %s `, tc.total, tc.long) if err := os.WriteFile(f, []byte(yaml), 0o600); err != nil { t.Fatalf("write yaml: %v", err) } _, err := config.LoadEdge(f) if err == nil { t.Fatalf("expected error for %s", tc.name) } if !strings.Contains(err.Error(), tc.wantMsg) { t.Fatalf("expected error mentioning %q, got %v", tc.wantMsg, err) } }) } } // TestLoadEdgeRejectsProviderLongContextBudgetBelowModelWindow verifies the // cross-entry budget rule: a provider referenced by a model group must have // total_context_tokens >= context_window_tokens * long_context_capacity. func TestLoadEdgeRejectsProviderLongContextBudgetBelowModelWindow(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") // 262144 * 2 = 524288 required, but total is only 262144. yaml := ` server: listen: "0.0.0.0:9090" models: - id: "qwen3.6:35b" context_window_tokens: 262144 providers: vllm-gpu: "nvidia/Qwen3.6-35B" nodes: - id: "node-gpu-01" alias: "gpu-node" providers: - id: "vllm-gpu" type: "vllm" category: "api" models: - "nvidia/Qwen3.6-35B" capacity: 4 total_context_tokens: 262144 long_context_capacity: 2 ` 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 insufficient total context budget") } if !strings.Contains(err.Error(), "total_context_tokens") || !strings.Contains(err.Error(), "long_context_capacity") { t.Fatalf("expected budget error mentioning total_context_tokens and long_context_capacity, got %v", err) } } func TestLoadEdge_MockConfigExplicitEnabled(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "test-node" token: "token-test" adapters: mock: enabled: 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.Nodes[0].Adapters.Mock.Enabled { t.Fatal("expected mock.enabled=true") } } func TestLoadEdge_MockConfigOmittedDefaultsFalse(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "test-node" token: "token-test" adapters: cli: enabled: true profiles: default: command: "echo" ` 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.Nodes[0].Adapters.Mock.Enabled { t.Fatal("expected mock.enabled=false when omitted") } } func TestLoadEdge_MockConfigExplicitDisabled(t *testing.T) { dir := t.TempDir() f := filepath.Join(dir, "edge.yaml") yaml := ` server: listen: "0.0.0.0:9090" nodes: - alias: "test-node" token: "token-test" adapters: mock: enabled: false ` 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.Nodes[0].Adapters.Mock.Enabled { t.Fatal("expected mock.enabled=false when explicitly disabled") } }