From 71fb0ff90453ed87719fa4fd04d83f5707fd7283 Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:39:57 -0400 Subject: [PATCH 01/10] [quality] add tests for config_compat.go delegation functions Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/config_compat_test.go | 100 ++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 pkg/agent/config_compat_test.go diff --git a/pkg/agent/config_compat_test.go b/pkg/agent/config_compat_test.go new file mode 100644 index 0000000000..d47afed069 --- /dev/null +++ b/pkg/agent/config_compat_test.go @@ -0,0 +1,100 @@ +package agent + +import ( + "testing" +) + +func TestGetConfigManager(t *testing.T) { + // GetConfigManager should return a non-nil *ConfigManager singleton + cm := GetConfigManager() + if cm == nil { + t.Fatal("GetConfigManager() returned nil") + } + + // Calling again should return the same singleton + cm2 := GetConfigManager() + if cm != cm2 { + t.Error("GetConfigManager() did not return the same singleton on second call") + } +} + +func TestGetBaseURLEnvKeyForProvider(t *testing.T) { + tests := []struct { + provider string + wantNon bool // expect non-empty result + }{ + {"ollama", true}, + {"llamacpp", true}, + {"localai", true}, + {"vllm", true}, + {"lmstudio", true}, + {"nonexistent-provider", false}, + } + + for _, tt := range tests { + t.Run(tt.provider, func(t *testing.T) { + got := getBaseURLEnvKeyForProvider(tt.provider) + if tt.wantNon && got == "" { + t.Errorf("getBaseURLEnvKeyForProvider(%q) = empty, want non-empty", tt.provider) + } + if !tt.wantNon && got != "" { + t.Errorf("getBaseURLEnvKeyForProvider(%q) = %q, want empty", tt.provider, got) + } + }) + } +} + +func TestGetEnvKeyForProvider(t *testing.T) { + tests := []struct { + provider string + wantNon bool + }{ + {"claude", true}, + {"openai", true}, + {"gemini", true}, + {"nonexistent-provider", false}, + } + + for _, tt := range tests { + t.Run(tt.provider, func(t *testing.T) { + got := getEnvKeyForProvider(tt.provider) + if tt.wantNon && got == "" { + t.Errorf("getEnvKeyForProvider(%q) = empty, want non-empty", tt.provider) + } + if !tt.wantNon && got != "" { + t.Errorf("getEnvKeyForProvider(%q) = %q, want empty", tt.provider, got) + } + }) + } +} + +func TestGetModelEnvKeyForProvider(t *testing.T) { + tests := []struct { + provider string + wantNon bool + }{ + {"ollama", true}, + {"openai", true}, + {"nonexistent-provider", false}, + } + + for _, tt := range tests { + t.Run(tt.provider, func(t *testing.T) { + got := getModelEnvKeyForProvider(tt.provider) + if tt.wantNon && got == "" { + t.Errorf("getModelEnvKeyForProvider(%q) = empty, want non-empty", tt.provider) + } + if !tt.wantNon && got != "" { + t.Errorf("getModelEnvKeyForProvider(%q) = %q, want empty", tt.provider, got) + } + }) + } +} + +func TestIsolateConfigManager(t *testing.T) { + // isolateConfigManager should return a non-nil *ConfigManager for test isolation + cm := isolateConfigManager(t) + if cm == nil { + t.Fatal("isolateConfigManager(t) returned nil") + } +} From 2173aec67d92feb8098d5947a84230e540bccbe0 Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:40:14 -0400 Subject: [PATCH 02/10] [quality] add tests for providers_compat.go re-exports and functions Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/providers_compat_test.go | 105 +++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 pkg/agent/providers_compat_test.go diff --git a/pkg/agent/providers_compat_test.go b/pkg/agent/providers_compat_test.go new file mode 100644 index 0000000000..f56e1a490a --- /dev/null +++ b/pkg/agent/providers_compat_test.go @@ -0,0 +1,105 @@ +package agent + +import ( + "testing" + "time" +) + +func TestProviderConstants(t *testing.T) { + // Verify re-exported provider key constants are non-empty + constants := map[string]string{ + "ProviderKeyOllama": ProviderKeyOllama, + "ProviderKeyLlamaCpp": ProviderKeyLlamaCpp, + "ProviderKeyLocalAI": ProviderKeyLocalAI, + "ProviderKeyVLLM": ProviderKeyVLLM, + "ProviderKeyLMStudio": ProviderKeyLMStudio, + "ProviderKeyRHAIIS": ProviderKeyRHAIIS, + } + + for name, val := range constants { + if val == "" { + t.Errorf("constant %s is empty", name) + } + } +} + +func TestProviderVars(t *testing.T) { + // Verify re-exported URL defaults are non-empty + if defaultOllamaURL == "" { + t.Error("defaultOllamaURL is empty") + } + if defaultLMStudioURL == "" { + t.Error("defaultLMStudioURL is empty") + } + if claudeAPIVersion == "" { + t.Error("claudeAPIVersion is empty") + } + if geminiAPIBaseURL == "" { + t.Error("geminiAPIBaseURL is empty") + } +} + +func TestGroqValidationURL(t *testing.T) { + url := groqValidationURL() + if url == "" { + t.Error("groqValidationURL() returned empty string") + } + if len(url) < 10 { + t.Errorf("groqValidationURL() too short: %q", url) + } +} + +func TestTruncateString(t *testing.T) { + tests := []struct { + name string + input string + maxLen int + want string + }{ + {"empty", "", 10, ""}, + {"within limit", "hello", 10, "hello"}, + {"at limit", "hello", 5, "hello"}, + {"over limit", "hello world", 5, "hello"}, + {"zero max", "hello", 0, ""}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := truncateString(tt.input, tt.maxLen) + if got != tt.want { + t.Errorf("truncateString(%q, %d) = %q, want %q", tt.input, tt.maxLen, got, tt.want) + } + }) + } +} + +func TestNewRestrictedAIProviderHTTPClient(t *testing.T) { + client := newRestrictedAIProviderHTTPClient(30 * time.Second) + if client == nil { + t.Fatal("newRestrictedAIProviderHTTPClient returned nil") + } + if client.Timeout != 30*time.Second { + t.Errorf("expected timeout 30s, got %v", client.Timeout) + } + + // Verify transport has restricted dial (doesn't allow private networks) + if client.Transport == nil { + t.Error("expected non-nil Transport with restricted dialer") + } +} + +func TestMaxLLMResponseBytes(t *testing.T) { + // Should be a reasonable value (> 0, < 100MB) + if maxLLMResponseBytes <= 0 { + t.Error("maxLLMResponseBytes should be > 0") + } + if maxLLMResponseBytes > 100*1024*1024 { + t.Errorf("maxLLMResponseBytes unexpectedly large: %d", maxLLMResponseBytes) + } +} + +func TestSetAllowLoopbackForTests(t *testing.T) { + // Should not panic + SetAllowLoopbackForTests(true) + SetAllowLoopbackForTests(false) +} From 1c5292dfad3e1a4e1b163d7e81657da2956cc1f5 Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:40:23 -0400 Subject: [PATCH 03/10] [quality] add tests for procgroup_compat.go process group configuration Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/procgroup_compat_test.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 pkg/agent/procgroup_compat_test.go diff --git a/pkg/agent/procgroup_compat_test.go b/pkg/agent/procgroup_compat_test.go new file mode 100644 index 0000000000..3be2f45343 --- /dev/null +++ b/pkg/agent/procgroup_compat_test.go @@ -0,0 +1,26 @@ +package agent + +import ( + "os/exec" + "testing" +) + +func TestConfigureProcessGroup(t *testing.T) { + // configureProcessGroup should not panic on a valid Cmd + cmd := exec.Command("echo", "test") + configureProcessGroup(cmd) + + // Verify SysProcAttr was set (on Unix, this sets Setpgid) + if cmd.SysProcAttr == nil { + t.Error("configureProcessGroup did not set SysProcAttr") + } +} + +func TestConfigureProcessGroupNilFields(t *testing.T) { + // Should handle a freshly created Cmd without panicking + cmd := &exec.Cmd{Path: "/bin/echo"} + configureProcessGroup(cmd) + if cmd.SysProcAttr == nil { + t.Error("configureProcessGroup did not set SysProcAttr on bare Cmd") + } +} From 4a816b32f740ae377fd1c8c52865335f6c0e6068 Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:40:36 -0400 Subject: [PATCH 04/10] [quality] add tests for workers_compat.go type aliases and constructors Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/workers_compat_test.go | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 pkg/agent/workers_compat_test.go diff --git a/pkg/agent/workers_compat_test.go b/pkg/agent/workers_compat_test.go new file mode 100644 index 0000000000..8292aff2f2 --- /dev/null +++ b/pkg/agent/workers_compat_test.go @@ -0,0 +1,67 @@ +package agent + +import ( + "testing" + "time" +) + +func TestWorkerTypeAliases(t *testing.T) { + // Verify constructor vars are non-nil (prove delegation wiring is intact) + if NewPredictionWorker == nil { + t.Error("NewPredictionWorker is nil") + } + if NewInsightWorker == nil { + t.Error("NewInsightWorker is nil") + } + if NewDeviceTracker == nil { + t.Error("NewDeviceTracker is nil") + } + if NewMetricsHistory == nil { + t.Error("NewMetricsHistory is nil") + } + if GetMetricsHandler == nil { + t.Error("GetMetricsHandler is nil") + } +} + +func TestWorkerConstants(t *testing.T) { + // InsightEnrichmentCacheTTL should be a positive duration + if InsightEnrichmentCacheTTL <= 0 { + t.Errorf("InsightEnrichmentCacheTTL = %v, want > 0", InsightEnrichmentCacheTTL) + } + if InsightEnrichmentCacheTTL > 24*time.Hour { + t.Errorf("InsightEnrichmentCacheTTL = %v, unexpectedly large", InsightEnrichmentCacheTTL) + } + + // InsightEnrichmentTimeout should be reasonable (< 5min) + if InsightEnrichmentTimeout <= 0 { + t.Errorf("InsightEnrichmentTimeout = %v, want > 0", InsightEnrichmentTimeout) + } + if InsightEnrichmentTimeout > 5*time.Minute { + t.Errorf("InsightEnrichmentTimeout = %v, unexpectedly large", InsightEnrichmentTimeout) + } +} + +func TestPredictionSettingsZeroValue(t *testing.T) { + // Verify PredictionSettings type alias compiles and can be instantiated + var ps PredictionSettings + _ = ps +} + +func TestInsightSummaryZeroValue(t *testing.T) { + // Verify InsightSummary type alias compiles and can be instantiated + var is InsightSummary + _ = is +} + +func TestDeviceAlertZeroValue(t *testing.T) { + // Verify DeviceAlert type alias compiles and can be instantiated + var da DeviceAlert + _ = da +} + +func TestMetricsSnapshotZeroValue(t *testing.T) { + // Verify MetricsSnapshot type alias compiles and can be instantiated + var ms MetricsSnapshot + _ = ms +} From 2c3f6c98d07cb4bee3a51048b4a8af1cfa83e30e Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:40:51 -0400 Subject: [PATCH 05/10] [quality] add tests for provider.go type aliases, constants, and MixedModeConfig Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/provider_test.go | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 pkg/agent/provider_test.go diff --git a/pkg/agent/provider_test.go b/pkg/agent/provider_test.go new file mode 100644 index 0000000000..7730c9b283 --- /dev/null +++ b/pkg/agent/provider_test.go @@ -0,0 +1,72 @@ +package agent + +import ( + "testing" +) + +func TestProviderTypeAliases(t *testing.T) { + // Verify the capability constants are correctly re-exported + if CapabilityChat == 0 { + t.Error("CapabilityChat should be non-zero") + } + if CapabilityToolExec == 0 { + t.Error("CapabilityToolExec should be non-zero") + } + if CapabilityChat == CapabilityToolExec { + t.Error("CapabilityChat and CapabilityToolExec should be distinct") + } +} + +func TestMaxStderrBytes(t *testing.T) { + // maxStderrBytes should be 1MB + if maxStderrBytes != 1<<20 { + t.Errorf("maxStderrBytes = %d, want %d (1MB)", maxStderrBytes, 1<<20) + } +} + +func TestMixedModeConfigZeroValue(t *testing.T) { + // MixedModeConfig should be usable with zero values + var cfg MixedModeConfig + if cfg.Enabled { + t.Error("zero-value MixedModeConfig should have Enabled=false") + } + if cfg.ThinkingAgent != "" { + t.Error("zero-value MixedModeConfig should have empty ThinkingAgent") + } + if cfg.ExecutionAgent != "" { + t.Error("zero-value MixedModeConfig should have empty ExecutionAgent") + } +} + +func TestMixedModeConfigFields(t *testing.T) { + cfg := MixedModeConfig{ + ThinkingAgent: "claude", + ExecutionAgent: "codex", + Enabled: true, + } + if cfg.ThinkingAgent != "claude" { + t.Errorf("ThinkingAgent = %q, want %q", cfg.ThinkingAgent, "claude") + } + if cfg.ExecutionAgent != "codex" { + t.Errorf("ExecutionAgent = %q, want %q", cfg.ExecutionAgent, "codex") + } + if !cfg.Enabled { + t.Error("Enabled should be true") + } +} + +func TestChatRequestZeroValue(t *testing.T) { + // ChatRequest type alias should compile and instantiate + var req ChatRequest + if req.Messages != nil { + t.Error("zero-value ChatRequest should have nil Messages") + } +} + +func TestChatResponseZeroValue(t *testing.T) { + // ChatResponse type alias should compile and instantiate + var resp ChatResponse + if resp.Content != "" { + t.Error("zero-value ChatResponse should have empty Content") + } +} From f5f47390d42dd4bef2edb4ef886f321669c6d06c Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:41:05 -0400 Subject: [PATCH 06/10] [quality] add tests for kagent_compat.go GVR delegations and type aliases Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/kagent_compat_test.go | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 pkg/agent/kagent_compat_test.go diff --git a/pkg/agent/kagent_compat_test.go b/pkg/agent/kagent_compat_test.go new file mode 100644 index 0000000000..9dd4e80713 --- /dev/null +++ b/pkg/agent/kagent_compat_test.go @@ -0,0 +1,62 @@ +package agent + +import ( + "testing" + + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestKagentGVRsNonEmpty(t *testing.T) { + // All kagent GVR delegations should resolve to non-empty GroupVersionResource + gvrs := map[string]schema.GroupVersionResource{ + "agentGVR": agentGVR, + "modelConfigGVR": modelConfigGVR, + "modelProviderConfigGVR": modelProviderConfigGVR, + "toolServerGVR": toolServerGVR, + "remoteMCPServerGVR": remoteMCPServerGVR, + "memoryGVR": memoryGVR, + } + + for name, gvr := range gvrs { + t.Run(name, func(t *testing.T) { + if gvr.Group == "" { + t.Errorf("%s has empty Group", name) + } + if gvr.Version == "" { + t.Errorf("%s has empty Version", name) + } + if gvr.Resource == "" { + t.Errorf("%s has empty Resource", name) + } + }) + } +} + +func TestKagentTypeAliases(t *testing.T) { + // Verify type aliases compile and can hold zero values + var agent kagentCRDAgent + if agent.Name != "" { + t.Error("zero-value kagentCRDAgent should have empty Name") + } + + var tool kagentCRDTool + _ = tool + + var model kagentCRDModel + _ = model + + var memory kagentCRDMemory + _ = memory + + var iAgent kagentiAgent + _ = iAgent + + var build kagentiBuild + _ = build + + var card kagentiCard + _ = card + + var iTool kagentiTool + _ = iTool +} From 8d19385e0f4a38f7924a0769d6e56da110a3e37b Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:42:41 -0400 Subject: [PATCH 07/10] =?UTF-8?q?[quality]=20fix=20provider=5Ftest.go=20?= =?UTF-8?q?=E2=80=94=20use=20correct=20ChatRequest=20fields=20(History=20n?= =?UTF-8?q?ot=20Messages)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/provider_test.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/agent/provider_test.go b/pkg/agent/provider_test.go index 7730c9b283..ef2c906468 100644 --- a/pkg/agent/provider_test.go +++ b/pkg/agent/provider_test.go @@ -17,6 +17,19 @@ func TestProviderTypeAliases(t *testing.T) { } } +func TestCapabilityHasCapability(t *testing.T) { + both := CapabilityChat | CapabilityToolExec + if !both.HasCapability(CapabilityChat) { + t.Error("combined capability should include CapabilityChat") + } + if !both.HasCapability(CapabilityToolExec) { + t.Error("combined capability should include CapabilityToolExec") + } + if CapabilityChat.HasCapability(CapabilityToolExec) { + t.Error("CapabilityChat alone should not include CapabilityToolExec") + } +} + func TestMaxStderrBytes(t *testing.T) { // maxStderrBytes should be 1MB if maxStderrBytes != 1<<20 { @@ -58,8 +71,14 @@ func TestMixedModeConfigFields(t *testing.T) { func TestChatRequestZeroValue(t *testing.T) { // ChatRequest type alias should compile and instantiate var req ChatRequest - if req.Messages != nil { - t.Error("zero-value ChatRequest should have nil Messages") + if req.SessionID != "" { + t.Error("zero-value ChatRequest should have empty SessionID") + } + if req.Prompt != "" { + t.Error("zero-value ChatRequest should have empty Prompt") + } + if req.History != nil { + t.Error("zero-value ChatRequest should have nil History") } } @@ -69,4 +88,10 @@ func TestChatResponseZeroValue(t *testing.T) { if resp.Content != "" { t.Error("zero-value ChatResponse should have empty Content") } + if resp.Done { + t.Error("zero-value ChatResponse should have Done=false") + } + if resp.ExitCode != 0 { + t.Error("zero-value ChatResponse should have ExitCode=0") + } } From 8d7067456afb84726fbf14f52610b0c6322402f8 Mon Sep 17 00:00:00 2001 From: Andy Anderson Date: Mon, 29 Jun 2026 14:43:01 -0400 Subject: [PATCH 08/10] [quality] add build tag to procgroup_compat_test.go for Unix-only SysProcAttr check Signed-off-by: clubanderson Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/agent/procgroup_compat_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/agent/procgroup_compat_test.go b/pkg/agent/procgroup_compat_test.go index 3be2f45343..73dd4dfb92 100644 --- a/pkg/agent/procgroup_compat_test.go +++ b/pkg/agent/procgroup_compat_test.go @@ -1,3 +1,5 @@ +//go:build !windows + package agent import ( @@ -14,6 +16,9 @@ func TestConfigureProcessGroup(t *testing.T) { if cmd.SysProcAttr == nil { t.Error("configureProcessGroup did not set SysProcAttr") } + if !cmd.SysProcAttr.Setpgid { + t.Error("configureProcessGroup did not set Setpgid=true") + } } func TestConfigureProcessGroupNilFields(t *testing.T) { From 0497efcdd590bb04214d0f6db21106456820489d Mon Sep 17 00:00:00 2001 From: clubanderson Date: Mon, 29 Jun 2026 15:16:11 -0400 Subject: [PATCH 09/10] [scanner] fix: rename duplicate TestNewRestrictedAIProviderHTTPClient in providers_compat_test.go Signed-off-by: clubanderson --- pkg/agent/providers_compat_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/agent/providers_compat_test.go b/pkg/agent/providers_compat_test.go index f56e1a490a..5d72ad12fd 100644 --- a/pkg/agent/providers_compat_test.go +++ b/pkg/agent/providers_compat_test.go @@ -73,7 +73,7 @@ func TestTruncateString(t *testing.T) { } } -func TestNewRestrictedAIProviderHTTPClient(t *testing.T) { +func TestNewRestrictedAIProviderHTTPClient_Basic(t *testing.T) { client := newRestrictedAIProviderHTTPClient(30 * time.Second) if client == nil { t.Fatal("newRestrictedAIProviderHTTPClient returned nil") From 271fda83177c74d567797b42e06f36f9edeccd2e Mon Sep 17 00:00:00 2001 From: clubanderson Date: Mon, 29 Jun 2026 15:30:17 -0400 Subject: [PATCH 10/10] [quality] fix test bugs from Copilot review on providers_compat and config_compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix TruncateString expected values: implementation appends '...' on truncation - Fix provider key 'lmstudio' → 'lm-studio' to match actual GetBaseURLEnvKeyForProvider switch - Make TestGroqValidationURL hermetic by setting GROQ_BASE_URL via t.Setenv - Restore loopback flag in TestSetAllowLoopbackForTests via t.Cleanup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: clubanderson --- pkg/agent/config_compat_test.go | 2 +- pkg/agent/providers_compat_test.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/agent/config_compat_test.go b/pkg/agent/config_compat_test.go index d47afed069..e890075989 100644 --- a/pkg/agent/config_compat_test.go +++ b/pkg/agent/config_compat_test.go @@ -27,7 +27,7 @@ func TestGetBaseURLEnvKeyForProvider(t *testing.T) { {"llamacpp", true}, {"localai", true}, {"vllm", true}, - {"lmstudio", true}, + {"lm-studio", true}, {"nonexistent-provider", false}, } diff --git a/pkg/agent/providers_compat_test.go b/pkg/agent/providers_compat_test.go index 5d72ad12fd..8dbed5e733 100644 --- a/pkg/agent/providers_compat_test.go +++ b/pkg/agent/providers_compat_test.go @@ -40,6 +40,8 @@ func TestProviderVars(t *testing.T) { } func TestGroqValidationURL(t *testing.T) { + // Set GROQ_BASE_URL explicitly so the test is hermetic + t.Setenv("GROQ_BASE_URL", "https://api.groq.com/openai/v1") url := groqValidationURL() if url == "" { t.Error("groqValidationURL() returned empty string") @@ -59,8 +61,8 @@ func TestTruncateString(t *testing.T) { {"empty", "", 10, ""}, {"within limit", "hello", 10, "hello"}, {"at limit", "hello", 5, "hello"}, - {"over limit", "hello world", 5, "hello"}, - {"zero max", "hello", 0, ""}, + {"over limit", "hello world", 5, "hello..."}, + {"zero max", "hello", 0, "..."}, } for _, tt := range tests { @@ -99,6 +101,10 @@ func TestMaxLLMResponseBytes(t *testing.T) { } func TestSetAllowLoopbackForTests(t *testing.T) { + // Restore the package-wide default (loopback enabled) after the test + // so we don't break other tests that rely on httptest servers. + t.Cleanup(func() { SetAllowLoopbackForTests(true) }) + // Should not panic SetAllowLoopbackForTests(true) SetAllowLoopbackForTests(false)