iop/apps/edge/internal/node/mapper_test.go
toki 3d6af1ac8c refactor(edge)!: OTO 전용 경로를 제거한다
Edge의 등록과 설정 표면을 generic node 기준으로 단순화하고, OTO 전용 bootstrap과 capability 분기 계약을 더 이상 노출하지 않도록 한다.

BREAKING CHANGE: iop-edge agent register, agent_kind=oto-agent, bootstrap OTO URL 필드를 제거한다.
2026-06-05 21:06:22 +09:00

243 lines
6 KiB
Go

package node_test
import (
"testing"
edgenode "iop/apps/edge/internal/node"
"iop/packages/go/config"
)
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)
}
}