myxce/src/frontend/advisor/internal/config/config_test.go
lei.chen ab12f49256 feat(advisor): agent loop, decision log, runbook, run/once CLI
- internal/agent: observe-mode loop — periodic scan + SSE job-event pull
  (events only pull the next scan earlier, debounced 5s; job.finished
  feeds exit_burst). Provider chain: primary (LLM) → echo fallback on
  failure, recorded as degraded. VerifyEvidence firewall runs on every
  LLM answer. Observe-only by construction: no write path reachable.
- internal/declog: JSONL decision log (scenario, trigger, provider, model,
  latency, tokens, findings, raw output, state snapshot + digest,
  degraded flag), size-rotated.
- internal/runbook: incident-pattern seed (embedded YAML) from the
  cluster's real debugging history (bug-1494 stale config, IPC ABI skew,
  bug-1513 rejoin crashes, bug-1521 reason race, first-fit bias,
  dispatch-fail repend family), rendered into the provider prompt.
- cmd: advisor run (signal-handled observe loop) and advisor once
  (single round, JSON report to stdout, no decision log).
- internal/config tests; full suite CGO_ENABLED=0 go test ./... clean.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-19 03:42:01 +00:00

70 lines
1.9 KiB
Go

package config
import (
"testing"
"time"
)
func setenvs(t *testing.T, kv map[string]string) {
t.Helper()
for _, k := range []string{"XCE_API_KEY", "XCE_API_URL", "ADVISOR_LLM_BASE_URL", "ADVISOR_LLM_MODEL",
"ADVISOR_INTERVAL", "ADVISOR_LLM_TIMEOUT", "ADVISOR_LOG", "ADVISOR_RUNBOOK"} {
t.Setenv(k, "") // clear first
}
for k, v := range kv {
t.Setenv(k, v)
}
}
func TestFromEnv_Minimal(t *testing.T) {
setenvs(t, map[string]string{"XCE_API_KEY": "xce_ak_x"})
c, err := FromEnv()
if err != nil {
t.Fatalf("FromEnv: %v", err)
}
if c.APIURL != defaultAPIURL {
t.Errorf("default APIURL = %q", c.APIURL)
}
if c.LLMEnabled() {
t.Errorf("LLM should be disabled by default")
}
if c.Interval != defaultInterval {
t.Errorf("default interval = %v", c.Interval)
}
}
func TestFromEnv_MissingKey(t *testing.T) {
setenvs(t, nil)
if _, err := FromEnv(); err == nil {
t.Fatal("missing XCE_API_KEY must error")
}
}
func TestFromEnv_LLMRequiresModel(t *testing.T) {
setenvs(t, map[string]string{"XCE_API_KEY": "k", "ADVISOR_LLM_BASE_URL": "http://llm"})
if _, err := FromEnv(); err == nil {
t.Fatal("BASE_URL without MODEL must error")
}
setenvs(t, map[string]string{
"XCE_API_KEY": "k", "ADVISOR_LLM_BASE_URL": "http://llm", "ADVISOR_LLM_MODEL": "glm-4-flash",
})
c, err := FromEnv()
if err != nil || !c.LLMEnabled() || c.LLMModel != "glm-4-flash" {
t.Fatalf("LLM config failed: %v %+v", err, c)
}
}
func TestFromEnv_Durations(t *testing.T) {
setenvs(t, map[string]string{"XCE_API_KEY": "k", "ADVISOR_INTERVAL": "45s", "ADVISOR_LLM_TIMEOUT": "10s"})
c, err := FromEnv()
if err != nil {
t.Fatalf("FromEnv: %v", err)
}
if c.Interval != 45*time.Second || c.LLMTimeout != 10*time.Second {
t.Errorf("durations = %v %v", c.Interval, c.LLMTimeout)
}
setenvs(t, map[string]string{"XCE_API_KEY": "k", "ADVISOR_INTERVAL": "bogus"})
if _, err := FromEnv(); err == nil {
t.Fatal("bad interval must error")
}
}