iop/apps/edge/internal/edgevalidate/validate_test.go
toki cc87db264b feat: sync edge module validation and E2E script updates
- Add mock resource activation for G06 review followup alignment
- Expand edgevalidate tests and refactor validation logic
- Update node mapper with improved handling
- Add integration and server test fixes
- Update Go config with new options
- Fix E2E scripts (cli-workspace, lemonade, ollama, vllm)
2026-07-07 04:38:31 +09:00

988 lines
27 KiB
Go

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)
}
}