iop/apps/edge/internal/configrefresh/provider_stall_timeout_test.go
toki fef1f7a9dc feat(liveness): provider 실행 stall 관측을 구현한다
Node의 provider progress 기반 stall timeout, watchdog fencing과 bounded health probe evidence를 실행 경로에 반영한다. Edge-Node 계약과 구현 스펙, 테스트 및 Milestone 완료 evidence를 현재 상태와 맞춘다.
2026-08-05 09:45:14 +09:00

71 lines
1.9 KiB
Go

package configrefresh_test
import (
"os"
"path/filepath"
"strings"
"testing"
configrefresh "iop/apps/edge/internal/configrefresh"
)
func TestProviderResponseStallTimeoutRefreshClassification(t *testing.T) {
base := `server:
listen: "0.0.0.0:9090"
nodes:
- id: "node-1"
token: "tok-1"
adapters:
vllm:
enabled: true
endpoint: "http://127.0.0.1:8000/v1"
providers:
- id: "prov-a"
type: "vllm"
category: "api"
adapter: "vllm"
endpoint: "http://127.0.0.1:8000/v1"
models: ["m"]
capacity: 2
`
dir := t.TempDir()
currentPath, candidatePath := filepath.Join(dir, "current.yaml"), filepath.Join(dir, "candidate.yaml")
if err := os.WriteFile(currentPath, []byte(base), 0o600); err != nil {
t.Fatal(err)
}
current, err := configrefresh.LoadCandidate(currentPath)
if err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
name string
raw string
want bool
}{
{name: "positive is restart required", raw: "60000", want: true},
{name: "explicit zero matches omitted", raw: "0"},
} {
t.Run(tc.name, func(t *testing.T) {
candidateYAML := strings.Replace(base, "capacity: 2\n", "capacity: 2\n response_stall_timeout_ms: "+tc.raw+"\n", 1)
if err := os.WriteFile(candidatePath, []byte(candidateYAML), 0o600); err != nil {
t.Fatal(err)
}
candidate, err := configrefresh.LoadCandidate(candidatePath)
if err != nil {
t.Fatal(err)
}
found := false
for _, change := range configrefresh.Classify(current, candidate).Changes {
if change.Path == `nodes[].providers["prov-a"].response_stall_timeout_ms` {
found = true
if change.Class != configrefresh.StatusRestartRequired {
t.Errorf("change class = %v", change.Class)
}
}
}
if found != tc.want {
t.Errorf("change found = %t, want %t", found, tc.want)
}
})
}
}