package node_test import ( "testing" edgenode "iop/apps/edge/internal/node" "iop/packages/go/config" iop "iop/proto/gen/iop" ) func TestBuildConfigPayload_OllamaEnabled(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "test", Token: "token", Adapters: config.AdaptersConf{ Ollama: config.OllamaConf{ Enabled: true, BaseURL: "http://localhost:11434", ContextSize: 262144, }, }, Runtime: config.RuntimeConf{ Concurrency: 4, WorkspaceRoot: "/tmp/ws", }, } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed: %v", err) } if payload.Runtime == nil { t.Fatal("expected runtime config, got nil") } if payload.Runtime.Concurrency != 4 { t.Errorf("expected concurrency 4, got %d", payload.Runtime.Concurrency) } if len(payload.Adapters) < 2 { t.Fatalf("expected at least 2 adapters, got %d", len(payload.Adapters)) } mockFound := false ollamaFound := false for _, a := range payload.Adapters { if a.Type == "mock" { mockFound = true } if a.Type == "ollama" { ollamaFound = true ollamaCfg := a.GetOllama() if ollamaCfg == nil { t.Fatal("expected ollama adapter config") } if ollamaCfg.BaseUrl != "http://localhost:11434" { t.Errorf("expected ollama base url %q, got %q", "http://localhost:11434", ollamaCfg.BaseUrl) } if ollamaCfg.ContextSize != 262144 { t.Errorf("expected ollama context size %d, got %d", 262144, ollamaCfg.ContextSize) } } } if !mockFound { t.Fatal("expected mock adapter") } if !ollamaFound { t.Fatal("expected ollama adapter when enabled") } } func TestBuildConfigPayload_CLIProfiles(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "test", Token: "token", Adapters: config.AdaptersConf{ CLI: config.CLIConf{ Enabled: true, Profiles: map[string]config.CLIProfileConf{ "default": { Command: "echo", Args: []string{"hello"}, Env: []string{"FOO=bar"}, Persistent: false, Terminal: true, ResponseIdleTimeoutMS: 5000, StartupIdleTimeoutMS: 10000, OutputFormat: "plain", Mode: "implicit", ResumeArgs: []string{"--resume"}, CompletionMarker: config.CompletionMarkerConf{ Line: "DONE", Regex: "^DONE$", }, }, }, }, }, Runtime: config.RuntimeConf{ WorkspaceRoot: "/tmp/ws", }, } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed: %v", err) } cliFound := false for _, a := range payload.Adapters { if a.Type == "cli" { cliFound = true cliCfg := a.GetCli() if cliCfg == nil { t.Fatal("expected cli adapter config") } if len(cliCfg.Profiles) != 1 { t.Fatalf("expected 1 cli profile, got %d", len(cliCfg.Profiles)) } p, ok := cliCfg.Profiles["default"] if !ok { t.Fatal("expected default profile") } if p.Command != "echo" { t.Errorf("expected command %q, got %q", "echo", p.Command) } if len(p.Args) != 1 || p.Args[0] != "hello" { t.Errorf("expected args [hello], got %v", p.Args) } if p.OutputFormat != "plain" { t.Errorf("expected format %q, got %q", "plain", p.OutputFormat) } if cm := p.CompletionMarker; cm == nil || cm.Line != "DONE" { t.Errorf("expected completion marker line %q, got %v", "DONE", cm) } } } if !cliFound { t.Fatal("expected cli adapter when enabled") } } func TestBuildConfigPayload_CLIProfileOpencodeSSEMode(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "test", Token: "token", Adapters: config.AdaptersConf{ CLI: config.CLIConf{ Enabled: true, Profiles: map[string]config.CLIProfileConf{ "opencode": { Command: "/usr/local/bin/opencode", Args: []string{"--model", "m"}, Mode: "opencode-sse", }, }, }, }, Runtime: config.RuntimeConf{WorkspaceRoot: "/tmp/ws"}, } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed: %v", err) } var found bool for _, a := range payload.Adapters { if a.Type != "cli" { continue } cli := a.GetCli() if cli == nil { t.Fatal("expected cli config") } p, ok := cli.Profiles["opencode"] if !ok { t.Fatal("expected opencode profile in payload") } if p.Mode != "opencode-sse" { t.Errorf("mode: got %q, want %q", p.Mode, "opencode-sse") } if len(p.Args) != 2 || p.Args[0] != "--model" || p.Args[1] != "m" { t.Errorf("args: got %v", p.Args) } found = true } if !found { t.Fatal("expected cli adapter in payload") } } func TestBuildConfigPayload_GenericRecordWithoutAdapters(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "generic", Token: "token", AgentKind: config.AgentKindGenericNode, } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed for generic record: %v", err) } if payload.GetRuntime() == nil { t.Fatal("expected runtime config, got nil") } if len(payload.GetAdapters()) < 1 || payload.GetAdapters()[0].GetType() != "mock" { t.Fatalf("expected mock adapter for generic record, got %+v", payload.GetAdapters()) } } func TestBuildConfigPayload_MockAlwaysPresent(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "test", Token: "token", Adapters: config.AdaptersConf{ Ollama: config.OllamaConf{Enabled: false}, Vllm: config.VllmConf{Enabled: false}, CLI: config.CLIConf{Enabled: false}, }, Runtime: config.RuntimeConf{ WorkspaceRoot: "/tmp/ws", }, } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed: %v", err) } if len(payload.Adapters) < 1 { t.Fatalf("expected at least 1 adapter, got %d", len(payload.Adapters)) } first := payload.Adapters[0] if first.Type != "mock" { t.Errorf("expected first adapter type %q, got %q", "mock", first.Type) } } func TestBuildConfigPayload_MockUsesTypedConfig(t *testing.T) { rec := &edgenode.NodeRecord{ ID: "node-1", Alias: "test", Token: "token", } payload, err := edgenode.BuildConfigPayload(rec) if err != nil { t.Fatalf("BuildConfigPayload failed: %v", err) } var mockAdapter *iop.AdapterConfig for _, a := range payload.Adapters { if a.GetType() == "mock" { mockAdapter = a break } } if mockAdapter == nil { t.Fatal("expected mock adapter in payload") } if mockAdapter.GetSettings() != nil { t.Fatalf("mock adapter must not populate legacy Settings, got %v", mockAdapter.GetSettings()) } if mockAdapter.GetMock() == nil { t.Fatal("mock adapter must use typed MockAdapterConfig oneof") } }