iop/apps/edge/internal/configrefresh/node_runtime_classify_test.go
toki 01dc2ef78b refactor: readability baseline 및 테스트 구조 개선
- agent-readable-repository-refactor 완료: 기존 테스트 파일 아카이브 이동
- 새 테스트 파일 추가 (edge, node, client, config, readability)
- readability_audit 스크립트 및 baseline 추가
- roadmap/SDD 문서 갱신
- agent-client/pi/extensions/openai-sampling-parameters 추가
2026-07-17 16:02:12 +09:00

238 lines
6.1 KiB
Go

package configrefresh_test
import (
"context"
"testing"
"iop/apps/edge/internal/configrefresh"
)
// TestClassifyNodeRuntimeConcurrencyApplied verifies S15: node runtime
// concurrency is applied live.
func TestClassifyNodeRuntimeConcurrencyApplied(t *testing.T) {
dir := t.TempDir()
currentYAML := `
server:
listen: "0.0.0.0:9090"
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
runtime:
concurrency: 2
`
currentPath := writeYAML(t, dir, "current.yaml", currentYAML)
concurrencyOnlyYAML := `
server:
listen: "0.0.0.0:9090"
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
runtime:
concurrency: 4
`
concurrencyOnlyPath := writeYAML(t, dir, "concurrency.yaml", concurrencyOnlyYAML)
current := buildNormalizedCurrent(t, currentPath)
ctx := context.Background()
// concurrency-only change → applied.
result, _, err := configrefresh.Evaluate(ctx, current, configrefresh.Request{
Mode: configrefresh.ModeDryRun,
ConfigPath: concurrencyOnlyPath,
RequestID: "test-s15-conc",
})
if err != nil {
t.Fatalf("Evaluate concurrency: %v", err)
}
if result.Status != configrefresh.StatusApplied {
t.Fatalf("expected concurrency change status=applied, got %q (summary: %s)", result.Status, result.Summary)
}
foundConc := false
for _, c := range result.Changes {
if c.Path == `nodes["node-1"].runtime.concurrency` {
foundConc = true
if c.Class != configrefresh.StatusApplied {
t.Errorf("expected concurrency class=applied, got %q", c.Class)
}
}
if c.Class == configrefresh.StatusRestartRequired {
t.Errorf("unexpected restart_required change for concurrency-only diff: %s", c.Path)
}
}
if !foundConc {
t.Errorf("concurrency change path not found in: %+v", result.Changes)
}
}
func TestClassifyModelCatalogProviderMappingApplied(t *testing.T) {
dir := t.TempDir()
currentYAML := `
server:
listen: "0.0.0.0:9090"
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
providers:
- id: "prov-a"
type: "ollama"
category: "local_inference"
adapter: "cli"
models: ["llama3.1"]
capacity: 2
- id: "prov-b"
type: "ollama"
category: "local_inference"
adapter: "cli"
models: ["llama3.1"]
capacity: 2
models:
- id: "qwen3.6:35b"
display_name: "Qwen"
context_window_tokens: 131072
default_max_tokens: 8192
min_max_tokens: 8192
providers:
prov-a: "llama3.1"
`
candidateYAML := `
server:
listen: "0.0.0.0:9090"
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
providers:
- id: "prov-a"
type: "ollama"
category: "local_inference"
adapter: "cli"
models: ["llama3.1"]
capacity: 2
- id: "prov-b"
type: "ollama"
category: "local_inference"
adapter: "cli"
models: ["llama3.1"]
capacity: 2
models:
- id: "qwen3.6:35b"
display_name: "Qwen"
context_window_tokens: 262144
default_max_tokens: 32768
min_max_tokens: 32768
default_thinking_token_budget: 8192
providers:
prov-b: "llama3.1"
`
currentPath := writeYAML(t, dir, "current.yaml", currentYAML)
candidatePath := writeYAML(t, dir, "candidate.yaml", candidateYAML)
current := buildNormalizedCurrent(t, currentPath)
result, _, err := configrefresh.Evaluate(context.Background(), current, configrefresh.Request{
Mode: configrefresh.ModeDryRun,
ConfigPath: candidatePath,
RequestID: "test-model-catalog",
})
if err != nil {
t.Fatalf("Evaluate: %v", err)
}
if result.Status != configrefresh.StatusApplied {
t.Fatalf("expected status=%q, got %q changes=%+v", configrefresh.StatusApplied, result.Status, result.Changes)
}
found := map[string]bool{}
for _, change := range result.Changes {
if change.Class == configrefresh.StatusApplied {
found[change.Path] = true
}
}
for _, path := range []string{
`models["qwen3.6:35b"].context_window_tokens`,
`models["qwen3.6:35b"].default_max_tokens`,
`models["qwen3.6:35b"].min_max_tokens`,
`models["qwen3.6:35b"].default_thinking_token_budget`,
`models["qwen3.6:35b"].providers`,
} {
if !found[path] {
t.Fatalf("model catalog change %s not found in %+v", path, result.Changes)
}
}
}
func TestClassifyLongContextThresholdApplied(t *testing.T) {
dir := t.TempDir()
currentYAML := `
server:
listen: "0.0.0.0:9090"
long_context_threshold_tokens: 100000
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
`
candidateYAML := `
server:
listen: "0.0.0.0:9090"
long_context_threshold_tokens: 120000
nodes:
- id: "node-1"
alias: "n1"
token: "tok-1"
adapters:
cli:
enabled: true
`
currentPath := writeYAML(t, dir, "current.yaml", currentYAML)
candidatePath := writeYAML(t, dir, "candidate.yaml", candidateYAML)
current := buildNormalizedCurrent(t, currentPath)
result, _, err := configrefresh.Evaluate(context.Background(), current, configrefresh.Request{
Mode: configrefresh.ModeDryRun,
ConfigPath: candidatePath,
RequestID: "test-long-threshold",
})
if err != nil {
t.Fatalf("Evaluate: %v", err)
}
if result.Status != configrefresh.StatusApplied {
t.Fatalf("expected status=%q, got %q changes=%+v", configrefresh.StatusApplied, result.Status, result.Changes)
}
found := false
for _, change := range result.Changes {
if change.Path == "long_context_threshold_tokens" {
found = true
if change.Class != configrefresh.StatusApplied {
t.Errorf("threshold class: got %q, want applied", change.Class)
}
if change.Previous != "100000" || change.Next != "120000" {
t.Errorf("threshold diff: got %s→%s", change.Previous, change.Next)
}
}
if change.Class == configrefresh.StatusRestartRequired {
t.Errorf("unexpected restart_required threshold change: %s", change.Path)
}
}
if !found {
t.Fatalf("long_context_threshold_tokens change not found in %+v", result.Changes)
}
}