package edgevalidate import ( "strings" "testing" "iop/packages/go/config" ) func TestValidateEdgeConfigProviderAdapterReferences(t *testing.T) { tests := []struct { name string node config.NodeDefinition wantErr string }{ { name: "valid exact openai compat instance", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "vllm-gpu", Enabled: true, Endpoint: "http://127.0.0.1:8000/v1"}, }, }, Providers: []config.NodeProviderConf{ {ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Adapter: "vllm-gpu"}, }, }, }, { name: "valid single type route", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "vllm-gpu", Enabled: true, Endpoint: "http://127.0.0.1:8000/v1"}, }, }, Providers: []config.NodeProviderConf{ {ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Adapter: "openai_compat"}, }, }, }, { name: "missing adapter rejected", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, }, Providers: []config.NodeProviderConf{ {ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Adapter: "missing"}, }, }, wantErr: "does not resolve", }, { name: "disabled instance rejected", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "vllm-gpu", Enabled: false, Endpoint: "http://127.0.0.1:8000/v1"}, }, }, Providers: []config.NodeProviderConf{ {ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Adapter: "vllm-gpu"}, }, }, wantErr: "does not resolve", }, { name: "ambiguous type route rejected", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OpenAICompatInstances: []config.OpenAICompatInstanceConf{ {Name: "vllm-a", Enabled: true, Endpoint: "http://127.0.0.1:8000/v1"}, {Name: "vllm-b", Enabled: true, Endpoint: "http://127.0.0.1:8001/v1"}, }, }, Providers: []config.NodeProviderConf{ {ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Adapter: "openai_compat"}, }, }, wantErr: "ambiguous", }, { name: "cli resource requires enabled cli", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama-local", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, Providers: []config.NodeProviderConf{ {ID: "cli-codex", Type: "cli", Category: config.CategoryCLI, Adapter: "cli"}, }, }, wantErr: "category cli requires enabled cli adapter", }, { name: "valid cli resource", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, }, Providers: []config.NodeProviderConf{ {ID: "cli-codex", Type: "cli", Category: config.CategoryCLI, Adapter: "cli"}, }, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{tc.node}}) if tc.wantErr == "" { if err != nil { t.Fatalf("ValidateEdgeConfig: %v", err) } return } if err == nil { t.Fatalf("expected error containing %q", tc.wantErr) } if !strings.Contains(err.Error(), tc.wantErr) { t.Fatalf("expected error containing %q, got %v", tc.wantErr, err) } }) } } func TestValidateEdgeConfigProviderAdapterEmptyRejected(t *testing.T) { cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{ { ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, }, Providers: []config.NodeProviderConf{ {ID: "prov-empty", Type: "cli", Category: config.CategoryCLI, Adapter: " "}, }, }, }, } err := ValidateEdgeConfig(cfg) if err == nil { t.Fatal("expected empty adapter error") } if !strings.Contains(err.Error(), "adapter must not be empty") { t.Fatalf("expected adapter empty error, got %v", err) } } func TestValidateEdgeConfig_ProviderFirstWithoutAdapterAllowed(t *testing.T) { tests := []struct { name string node config.NodeDefinition wantErr string }{ { name: "valid adapter-less provider-first openai_compat", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai", Type: "openai_compat", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, }, { name: "valid adapter-less provider-first ollama", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-ollama", Type: "ollama", Category: config.CategoryLocalInference, BaseURL: "http://127.0.0.1:11434", }, }, }, }, { name: "valid adapter-less provider-first cli", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-cli", Type: "cli", Category: config.CategoryCLI, Command: "echo", }, }, }, }, { name: "invalid adapter-less provider-first openai_compat (missing endpoint)", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai", Type: "openai_compat", Category: config.CategoryAPI, }, }, }, wantErr: "adapter must not be empty", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{tc.node}}) if tc.wantErr == "" { if err != nil { t.Fatalf("ValidateEdgeConfig: %v", err) } return } if err == nil { t.Fatalf("expected error containing %q", tc.wantErr) } if !strings.Contains(err.Error(), tc.wantErr) { t.Fatalf("expected error containing %q, got %v", tc.wantErr, err) } }) } } func TestValidateEdgeConfig_ProviderFirstRejectsMissingTypeFields(t *testing.T) { tests := []struct { name string node config.NodeDefinition wantErr string }{ { name: "missing endpoint for openai_compat", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai", Type: "openai_compat", Category: config.CategoryAPI, }, }, }, wantErr: "adapter must not be empty", }, { name: "missing base_url for ollama", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-ollama", Type: "ollama", Category: config.CategoryLocalInference, }, }, }, wantErr: "adapter must not be empty", }, { name: "missing command for cli", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-cli", Type: "cli", Category: config.CategoryCLI, }, }, }, wantErr: "adapter must not be empty", }, { name: "openai_compat with base_url only", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai", Type: "openai_compat", Category: config.CategoryAPI, BaseURL: "http://127.0.0.1:11434", }, }, }, wantErr: "openai_compat provider endpoint must not be empty", }, { name: "ollama with command only", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-ollama", Type: "ollama", Category: config.CategoryLocalInference, Command: "echo", }, }, }, wantErr: "ollama provider base_url must not be empty", }, { name: "cli with endpoint only", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-cli", Type: "cli", Category: config.CategoryCLI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, wantErr: "cli provider command must not be empty", }, { name: "whitespace type", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-whitespace", Type: " ", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, wantErr: "type must not be empty", }, { name: "openai_compat with wrong-field base_url", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai", Type: "openai_compat", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", BaseURL: "http://127.0.0.1:11434", }, }, }, wantErr: "openai_compat provider must not set base_url or command", }, { name: "supported aliases vllm valid", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-vllm", Type: "vllm", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, }, { name: "supported aliases lemonade valid", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-lemonade", Type: "lemonade", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, }, { name: "supported aliases openai_api valid", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-openai-api", Type: "openai_api", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, }, { name: "supported aliases sglang valid", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-sglang", Type: "sglang", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, }, { name: "unknown provider type rejected", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Providers: []config.NodeProviderConf{ { ID: "prov-unknown", Type: "unknown_provider", Category: config.CategoryAPI, Endpoint: "http://127.0.0.1:8000/v1", }, }, }, wantErr: "unknown provider type", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{tc.node}}) if tc.wantErr == "" { if err != nil { t.Fatalf("ValidateEdgeConfig: %v", err) } return } if err == nil { t.Fatalf("expected error containing %q", tc.wantErr) } if !strings.Contains(err.Error(), tc.wantErr) { t.Fatalf("expected error containing %q, got %v", tc.wantErr, err) } }) } } // COMPAT-1: ValidateEdgeConfig edgevalidate entrypoint also rejects mixed config conflicts. func TestValidateEdgeConfig_ProviderLegacyConflictViaValidate(t *testing.T) { node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, Providers: []config.NodeProviderConf{ { ID: "ollama", Type: "ollama", Category: config.CategoryLocalInference, BaseURL: "http://other-host:11434", Models: []string{"llama3:8b"}, }, }, } err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{node}}) if err == nil { t.Fatal("expected conflict error from ValidateEdgeConfig") } if !strings.Contains(err.Error(), "conflicts with adapters") { t.Fatalf("expected error containing 'conflicts with adapters', got %v", err) } } // REVIEW_COMPAT-1: ValidateEdgeConfig capacity mismatch rejects same-key provider-first/legacy // when provider capacity is 0 and legacy capacity > 0. func TestValidateEdgeConfig_ProviderLegacyCapacityMismatchViaValidate(t *testing.T) { tests := []struct { name string adapterName string providerID string providerType string providerCap int legacyCap int legacyOpts func(*config.AdaptersConf) providerOpts func(*config.NodeProviderConf) }{ { name: "ollama provider capacity 0 vs legacy capacity 2", adapterName: "ollama", providerID: "ollama", providerType: "ollama", providerCap: 0, legacyCap: 2, legacyOpts: func(a *config.AdaptersConf) { a.OllamaInstances = []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434", Capacity: 2}, } }, providerOpts: func(p *config.NodeProviderConf) { p.BaseURL = "http://127.0.0.1:11434" p.Models = []string{"llama3:8b"} }, }, { name: "vllm provider capacity 0 vs legacy capacity 4", adapterName: "vllm-gpu", providerID: "vllm-gpu", providerType: "vllm", providerCap: 0, legacyCap: 4, legacyOpts: func(a *config.AdaptersConf) { a.OpenAICompatInstances = []config.OpenAICompatInstanceConf{ {Name: "vllm-gpu", Enabled: true, Endpoint: "http://127.0.0.1:8000/v1", Capacity: 4}, } }, providerOpts: func(p *config.NodeProviderConf) { p.Endpoint = "http://127.0.0.1:8000/v1" p.Models = []string{"model-a"} }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{}, Providers: []config.NodeProviderConf{ { ID: tc.providerID, Type: tc.providerType, Category: config.CategoryLocalInference, Capacity: tc.providerCap, }, }, } tc.legacyOpts(&node.Adapters) tc.providerOpts(&node.Providers[0]) err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{node}}) if err == nil { t.Fatal("expected capacity mismatch error from ValidateEdgeConfig") } if !strings.Contains(err.Error(), "conflicts with adapters") { t.Fatalf("expected error containing 'conflicts with adapters', got %v", err) } if !strings.Contains(err.Error(), "capacity mismatch") { t.Fatalf("expected error containing 'capacity mismatch', got %v", err) } }) } } func TestValidateEdgeConfig_DisabledProviderUnknownTypeRejected(t *testing.T) { disabled := false tests := []struct { name string node config.NodeDefinition wantErr string }{ { name: "disabled provider with unknown type is rejected", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, }, Providers: []config.NodeProviderConf{ // enabled provider so the node passes the "at least one adapter" check {ID: "prov-active", Type: "cli", Category: config.CategoryCLI, Adapter: "cli"}, // disabled provider with unknown type must be rejected {ID: "prov-disabled", Type: "unknown_provider", Category: config.CategoryAPI, Enabled: &disabled}, }, }, wantErr: "unknown provider type", }, { name: "disabled provider with valid type and missing adapter passes", node: config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ CLI: config.CLIConf{Enabled: true}, }, Providers: []config.NodeProviderConf{ {ID: "prov-active", Type: "cli", Category: config.CategoryCLI, Adapter: "cli"}, // disabled provider: valid type, missing adapter reference must be skipped {ID: "prov-disabled", Type: "openai_compat", Category: config.CategoryAPI, Adapter: "ghost-adapter", Enabled: &disabled}, }, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{tc.node}}) if tc.wantErr == "" { if err != nil { t.Fatalf("ValidateEdgeConfig: %v", err) } return } if err == nil { t.Fatalf("expected error containing %q", tc.wantErr) } if !strings.Contains(err.Error(), tc.wantErr) { t.Fatalf("expected error containing %q, got %v", tc.wantErr, err) } }) } } func TestValidateEdgeConfig_DisabledProviderSkipsAdapterRefCheck(t *testing.T) { disabled := false node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ VllmInstances: []config.VllmInstanceConf{ {Name: "vllm-gpu", Enabled: true, Endpoint: "http://127.0.0.1:8000/v1"}, }, }, Providers: []config.NodeProviderConf{ {ID: "prov-active", Type: "vllm", Category: config.CategoryAPI, Adapter: "vllm-gpu", Models: []string{"model-a"}, Capacity: 2}, // disabled: adapter "ghost-adapter" doesn't exist but must not error {ID: "prov-ghost", Type: "vllm", Category: config.CategoryAPI, Adapter: "ghost-adapter", Models: []string{"model-b"}, Enabled: &disabled}, }, } if err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{node}}); err != nil { t.Fatalf("disabled provider with missing adapter should pass validation, got: %v", err) } } // REVIEW_MOCK: mock-only node passes "at least one adapter" when explicitly enabled. func TestValidateEdgeConfig_MockOnlyNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok-mock", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{node}}) if err != nil { t.Fatalf("mock-only node with explicit enabled should pass, got: %v", err) } } // REVIEW_MOCK: node with only mock config disabled should fail "at least one adapter". func TestValidateEdgeConfig_MockDisabledFails(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok-mock", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: false}, }, } err := ValidateEdgeConfig(&config.EdgeConfig{Nodes: []config.NodeDefinition{node}}) if err == nil { t.Fatal("expected 'at least one adapter' error for mock-disabled node") } if !strings.Contains(err.Error(), "at least one adapter") { t.Fatalf("expected error mentioning 'at least one adapter', got: %v", err) } } // REVIEW_REVIEW_MOCK-2: console.adapter references mock without any mock-enabled node fails. func TestValidateEdgeConfig_MockSurfaceConsoleNoMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, Console: config.EdgeConsoleConf{Adapter: "mock"}, } err := ValidateEdgeConfig(cfg) if err == nil { t.Fatal("expected error for console.adapter: mock without mock-enabled node") } if !strings.Contains(err.Error(), "mock") || !strings.Contains(err.Error(), "explicit mock") { t.Fatalf("expected error mentioning mock, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: console.adapter references mock with mock-enabled node succeeds. func TestValidateEdgeConfig_MockSurfaceConsoleWithMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, Console: config.EdgeConsoleConf{Adapter: "mock"}, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai.model_routes[].adapter references mock with node ref to mock-enabled node succeeds. func TestValidateEdgeConfig_MockSurfaceOpenAIRouteWithMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, ModelRoutes: []config.OpenAIRouteEntry{ { Model: "mock-model", NodeRef: "node-mock", Adapter: "mock", Target: "mock-target", }, }, }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai.model_routes[].adapter references mock with node ref to non-mock node fails. func TestValidateEdgeConfig_MockSurfaceOpenAIRouteNoMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-ollama", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, ModelRoutes: []config.OpenAIRouteEntry{ { Model: "mock-model", NodeRef: "node-ollama", Adapter: "mock", Target: "mock-target", }, }, }, } err := ValidateEdgeConfig(cfg) if err == nil { t.Fatal("expected error for openai.model_routes[].adapter: mock with non-mock node ref") } if !strings.Contains(err.Error(), "mock") || !strings.Contains(err.Error(), "explicit mock") { t.Fatalf("expected error mentioning mock, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: a2a.adapter references mock with mock-enabled node ref succeeds. func TestValidateEdgeConfig_MockSurfaceA2AWithMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, A2A: config.EdgeA2AConf{ Enabled: true, NodeRef: "node-mock", Adapter: "mock", }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: a2a.adapter references mock without mock-enabled node fails. func TestValidateEdgeConfig_MockSurfaceA2ANoMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, A2A: config.EdgeA2AConf{ Enabled: true, NodeRef: "node-1", Adapter: "mock", }, } err := ValidateEdgeConfig(cfg) if err == nil { t.Fatal("expected error for a2a.adapter: mock without mock-enabled node") } if !strings.Contains(err.Error(), "mock") || !strings.Contains(err.Error(), "explicit mock") { t.Fatalf("expected error mentioning mock, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai top-level adapter references mock with node ref to mock-enabled node succeeds. func TestValidateEdgeConfig_MockSurfaceOpenAITopLevelWithMockNode(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, NodeRef: "node-mock", Adapter: "mock", Target: "mock-target", Models: []string{"mock-model"}, SessionID: "test", }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai top-level adapter references mock without node ref but hasAnyMock succeeds. func TestValidateEdgeConfig_MockSurfaceOpenAITopLevelNoNodeRefWithHasAnyMock(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, Adapter: "mock", Target: "mock-target", Models: []string{"mock-model"}, SessionID: "test", }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai top-level adapter references mock with alias-based node ref succeeds. func TestValidateEdgeConfig_MockSurfaceOpenAITopLevelAliasRef(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Alias: "mock-alias", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, NodeRef: "mock-alias", Adapter: "mock", Target: "mock-target", Models: []string{"mock-model"}, SessionID: "test", }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success with alias ref, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: a2a adapter references mock without node ref but hasAnyMock succeeds. func TestValidateEdgeConfig_MockSurfaceA2ANoNodeRefWithHasAnyMock(t *testing.T) { node := config.NodeDefinition{ ID: "node-mock", Token: "tok", Adapters: config.AdaptersConf{ Mock: config.MockConf{Enabled: true}, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, A2A: config.EdgeA2AConf{ Enabled: true, Adapter: "mock", }, } if err := ValidateEdgeConfig(cfg); err != nil { t.Fatalf("expected success, got: %v", err) } } // REVIEW_REVIEW_MOCK-2: openai top-level adapter references mock without node ref and no mock node fails. func TestValidateEdgeConfig_MockSurfaceOpenAITopLevelNoNodeRefNoMock(t *testing.T) { node := config.NodeDefinition{ ID: "node-1", Token: "tok", Adapters: config.AdaptersConf{ OllamaInstances: []config.OllamaInstanceConf{ {Name: "ollama", Enabled: true, BaseURL: "http://127.0.0.1:11434"}, }, }, } cfg := &config.EdgeConfig{ Nodes: []config.NodeDefinition{node}, OpenAI: config.EdgeOpenAIConf{ Enabled: true, Adapter: "mock", Target: "mock-target", Models: []string{"mock-model"}, SessionID: "test", }, } err := ValidateEdgeConfig(cfg) if err == nil { t.Fatal("expected error for openai top-level adapter: mock with no node ref and no mock-enabled node") } if !strings.Contains(err.Error(), "mock") || !strings.Contains(err.Error(), "explicit mock") { t.Fatalf("expected error mentioning mock, got: %v", err) } }