iop/apps/node/internal/adapters/factory_internal_test.go
toki fefc198dfe refactor: antigravity CLI status 통합 및 문서 업데이트
- antigravity 기반 CLI status adapter 구현 (gemini 대체)
- milestone 파일명 통일 (接두어 제거)
- agent-ops roadmap/current.md 갱신
- edge/node README 및 설정 문서 업데이트
- e2e smoke 스크립트 개선
2026-05-21 21:39:09 +09:00

327 lines
8.7 KiB
Go

package adapters
import (
"testing"
"google.golang.org/protobuf/types/known/structpb"
iop "iop/proto/gen/iop"
)
func TestCLIConfFromProto_ProfileRuntimeOptions(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"claude": {
Command: "claude",
Args: []string{"-p"},
OutputFormat: "claude-json",
},
},
}
cfg := cliConfFromProto(m)
prof, ok := cfg.Profiles["claude"]
if !ok {
t.Fatal("expected claude profile")
}
if prof.Command != "claude" {
t.Fatalf("command: got %q", prof.Command)
}
if len(prof.Args) != 1 || prof.Args[0] != "-p" {
t.Fatalf("args: got %#v", prof.Args)
}
if prof.OutputFormat != "claude-json" {
t.Fatalf("output_format: got %q", prof.OutputFormat)
}
}
func TestCLIConfFromProto_ClaudeHeadlessBypassProfile(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"claude": {
Command: "claude",
Args: []string{"-p", "--dangerously-skip-permissions"},
},
},
}
cfg := cliConfFromProto(m)
prof, ok := cfg.Profiles["claude"]
if !ok {
t.Fatal("expected claude profile")
}
if len(prof.Args) != 2 || prof.Args[0] != "-p" || prof.Args[1] != "--dangerously-skip-permissions" {
t.Fatalf("args: got %#v", prof.Args)
}
if prof.Persistent || prof.Terminal {
t.Fatalf("expected persistent/terminal=false")
}
}
func TestCLIConfFromProto_AntigravityHeadlessProfile(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"antigravity": {
Command: "agy",
Args: []string{"--dangerously-skip-permissions", "--print"},
},
},
}
cfg := cliConfFromProto(m)
prof, ok := cfg.Profiles["antigravity"]
if !ok {
t.Fatal("expected antigravity profile")
}
if len(prof.Args) != 2 || prof.Args[0] != "--dangerously-skip-permissions" || prof.Args[1] != "--print" {
t.Fatalf("args: got %#v", prof.Args)
}
}
func TestCLIConfFromProto_ClineConfigProfile(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"cline-dgx": {
Command: "/config/.npm-global/bin/cline",
Args: []string{"-y", "--json", "--config", "/config/.cline/profiles/ollama-dgx"},
OutputFormat: "cline-json",
},
},
}
cfg := cliConfFromProto(m)
prof, ok := cfg.Profiles["cline-dgx"]
if !ok {
t.Fatal("expected cline-dgx profile")
}
if prof.Command != "/config/.npm-global/bin/cline" {
t.Fatalf("command: got %q", prof.Command)
}
if len(prof.Args) != 4 {
t.Fatalf("args: got %#v", prof.Args)
}
if prof.OutputFormat != "cline-json" {
t.Fatalf("output_format: got %q", prof.OutputFormat)
}
}
func TestCLIConfFromProto_ProfileCompletionMarker(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"codex": {
Command: "codex",
Persistent: true,
CompletionMarker: &iop.CLICompletionMarker{
Line: "[[DONE]]",
Regex: `^\[\[DONE\]\]$`,
},
},
},
}
cfg := cliConfFromProto(m)
prof := cfg.Profiles["codex"]
if prof.CompletionMarker.Line != "[[DONE]]" {
t.Fatalf("line: got %q", prof.CompletionMarker.Line)
}
if prof.CompletionMarker.Regex != `^\[\[DONE\]\]$` {
t.Fatalf("regex: got %q", prof.CompletionMarker.Regex)
}
}
func TestCLIConfFromProto_PersistentAndIdleTimeouts(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"codex": {
Command: "codex",
Persistent: true,
ResponseIdleTimeoutMs: 1500,
StartupIdleTimeoutMs: 300,
},
},
}
cfg := cliConfFromProto(m)
prof := cfg.Profiles["codex"]
if !prof.Persistent {
t.Fatal("persistent")
}
if prof.ResponseIdleTimeoutMS != 1500 {
t.Fatalf("response_idle_timeout_ms: got %d", prof.ResponseIdleTimeoutMS)
}
if prof.StartupIdleTimeoutMS != 300 {
t.Fatalf("startup_idle_timeout_ms: got %d", prof.StartupIdleTimeoutMS)
}
}
func TestCLIConfFromProto_NilSettings(t *testing.T) {
cfg := cliConfFromProto(&iop.CLIAdapterConfig{})
if !cfg.Enabled {
t.Fatal("expected enabled=true")
}
if cfg.Profiles == nil {
t.Fatal("profiles map should be initialized")
}
}
func TestCLIConfFromProto_OpencodeSSEMode(t *testing.T) {
m := &iop.CLIAdapterConfig{
Profiles: map[string]*iop.CLIProfileConfig{
"opencode": {
Command: "/usr/local/bin/opencode",
Args: []string{"--model", "m1", "--dangerously-skip-permissions"},
Mode: "opencode-sse",
},
},
}
cfg := cliConfFromProto(m)
prof, ok := cfg.Profiles["opencode"]
if !ok {
t.Fatal("expected opencode profile")
}
if prof.Mode != "opencode-sse" {
t.Errorf("mode: got %q", prof.Mode)
}
if len(prof.Args) != 3 {
t.Fatalf("args: got %#v", prof.Args)
}
}
func TestCLIConfFromStruct_OpencodeSSEModeLegacy(t *testing.T) {
st, err := structpb.NewStruct(map[string]any{
"profiles": map[string]any{
"opencode": map[string]any{
"command": "/usr/local/bin/opencode",
"args": []any{"--model", "m1"},
"mode": "opencode-sse",
},
},
})
if err != nil {
t.Fatalf("structpb: %v", err)
}
cfg := cliConfFromStruct(st)
prof, ok := cfg.Profiles["opencode"]
if !ok {
t.Fatal("expected opencode profile")
}
if prof.Mode != "opencode-sse" {
t.Errorf("mode: got %q", prof.Mode)
}
}
// Legacy structpb fallback regression tests — these exercise the path taken
// when an older edge sends AdapterConfig.settings instead of the typed oneof.
func TestOllamaConfFromStruct_LegacyPayload(t *testing.T) {
st, err := structpb.NewStruct(map[string]any{
"base_url": "http://legacy:11434",
"context_size": float64(262144),
})
if err != nil {
t.Fatalf("structpb: %v", err)
}
cfg := ollamaConfFromStruct(st)
if !cfg.Enabled {
t.Fatal("expected enabled=true")
}
if cfg.BaseURL != "http://legacy:11434" {
t.Fatalf("base_url: got %q", cfg.BaseURL)
}
if cfg.ContextSize != 262144 {
t.Fatalf("context_size: got %d", cfg.ContextSize)
}
}
func TestVllmConfFromStruct_LegacyPayload(t *testing.T) {
st, err := structpb.NewStruct(map[string]any{"endpoint": "http://legacy:8000"})
if err != nil {
t.Fatalf("structpb: %v", err)
}
cfg := vllmConfFromStruct(st)
if !cfg.Enabled {
t.Fatal("expected enabled=true")
}
if cfg.Endpoint != "http://legacy:8000" {
t.Fatalf("endpoint: got %q", cfg.Endpoint)
}
}
func TestCLIConfFromStruct_LegacyPayload(t *testing.T) {
st, err := structpb.NewStruct(map[string]any{
"profiles": map[string]any{
"codex": map[string]any{
"command": "codex",
"args": []any{"--legacy"},
"env": []any{"K=V"},
"persistent": true,
"terminal": false,
"response_idle_timeout_ms": 1500,
"startup_idle_timeout_ms": 300,
"output_format": "codex-json",
"completion_marker": map[string]any{
"line": "[[DONE]]",
"regex": `^\[\[DONE\]\]$`,
},
},
},
})
if err != nil {
t.Fatalf("structpb: %v", err)
}
cfg := cliConfFromStruct(st)
prof, ok := cfg.Profiles["codex"]
if !ok {
t.Fatal("expected codex profile")
}
if prof.Command != "codex" {
t.Fatalf("command: got %q", prof.Command)
}
if len(prof.Args) != 1 || prof.Args[0] != "--legacy" {
t.Fatalf("args: got %#v", prof.Args)
}
if len(prof.Env) != 1 || prof.Env[0] != "K=V" {
t.Fatalf("env: got %#v", prof.Env)
}
if !prof.Persistent {
t.Fatal("persistent")
}
if prof.ResponseIdleTimeoutMS != 1500 {
t.Fatalf("response_idle_timeout_ms: got %d", prof.ResponseIdleTimeoutMS)
}
if prof.StartupIdleTimeoutMS != 300 {
t.Fatalf("startup_idle_timeout_ms: got %d", prof.StartupIdleTimeoutMS)
}
if prof.OutputFormat != "codex-json" {
t.Fatalf("output_format: got %q", prof.OutputFormat)
}
if prof.CompletionMarker.Line != "[[DONE]]" || prof.CompletionMarker.Regex != `^\[\[DONE\]\]$` {
t.Fatalf("completion_marker: got %+v", prof.CompletionMarker)
}
}
// End-to-end fallback through BuildFromPayload: oneof empty, settings populated.
func TestBuildFromPayload_LegacySettingsFallback(t *testing.T) {
ollamaSt, _ := structpb.NewStruct(map[string]any{"base_url": "http://legacy:11434"})
vllmSt, _ := structpb.NewStruct(map[string]any{"endpoint": "http://legacy:8000"})
cliSt, _ := structpb.NewStruct(map[string]any{
"profiles": map[string]any{
"codex": map[string]any{
"command": "codex",
"args": []any{"--legacy"},
},
},
})
payload := &iop.NodeConfigPayload{
Adapters: []*iop.AdapterConfig{
{Type: "ollama", Enabled: true, Settings: ollamaSt},
{Type: "vllm", Enabled: true, Settings: vllmSt},
{Type: "cli", Enabled: true, Settings: cliSt},
},
}
reg, err := BuildFromPayload(payload, nil)
if err != nil {
t.Fatalf("build: %v", err)
}
for _, name := range []string{"ollama", "vllm", "cli"} {
if _, ok := reg.Get(name); !ok {
t.Fatalf("expected %s adapter registered from legacy settings", name)
}
}
}