|
1 | 1 | package websocket |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "fmt" |
5 | 6 | "net/http" |
6 | 7 | "net/http/httptest" |
7 | 8 | "testing" |
8 | 9 |
|
9 | 10 | "ambient-code-backend/handlers" |
| 11 | + "ambient-code-backend/tests/test_utils" |
| 12 | + "ambient-code-backend/types" |
10 | 13 |
|
11 | 14 | corev1 "k8s.io/api/core/v1" |
12 | 15 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 16 | + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" |
| 17 | + "k8s.io/apimachinery/pkg/runtime/schema" |
| 18 | + "k8s.io/client-go/dynamic" |
13 | 19 | k8sfake "k8s.io/client-go/kubernetes/fake" |
14 | 20 | ) |
15 | 21 |
|
@@ -204,3 +210,129 @@ func TestDefaultRunnerPort_Constant(t *testing.T) { |
204 | 210 | t.Errorf("Expected DefaultRunnerPort=8001, got %d", handlers.DefaultRunnerPort) |
205 | 211 | } |
206 | 212 | } |
| 213 | + |
| 214 | +// --- triggerDisplayNameGenerationIfNeeded tests (regression for #1561) --- |
| 215 | + |
| 216 | +func setupDisplayNameTest(t *testing.T, spec map[string]interface{}) (cleanup func()) { |
| 217 | + t.Helper() |
| 218 | + |
| 219 | + oldDynamic := handlers.DynamicClient |
| 220 | + oldK8sProjects := handlers.K8sClientProjects |
| 221 | + oldGVRFunc := handlers.GetAgenticSessionV1Alpha1Resource |
| 222 | + |
| 223 | + agenticSessionGVR := schema.GroupVersionResource{ |
| 224 | + Group: "vteam.ambient-code", |
| 225 | + Version: "v1alpha1", |
| 226 | + Resource: "agenticsessions", |
| 227 | + } |
| 228 | + handlers.GetAgenticSessionV1Alpha1Resource = func() schema.GroupVersionResource { |
| 229 | + return agenticSessionGVR |
| 230 | + } |
| 231 | + |
| 232 | + fakeClients := test_utils.NewFakeClientSet() |
| 233 | + handlers.DynamicClient = fakeClients.GetDynamicClient() |
| 234 | + handlers.K8sClientProjects = fakeClients.GetK8sClient() |
| 235 | + |
| 236 | + err := test_utils.CreateAgenticSessionInFakeClient( |
| 237 | + handlers.DynamicClient, "test-project", "test-session", spec, |
| 238 | + ) |
| 239 | + if err != nil { |
| 240 | + t.Fatalf("Failed to create test session: %v", err) |
| 241 | + } |
| 242 | + |
| 243 | + return func() { |
| 244 | + handlers.DynamicClient = oldDynamic |
| 245 | + handlers.K8sClientProjects = oldK8sProjects |
| 246 | + handlers.GetAgenticSessionV1Alpha1Resource = oldGVRFunc |
| 247 | + } |
| 248 | +} |
| 249 | + |
| 250 | +func getDisplayName(t *testing.T, dc dynamic.Interface) string { |
| 251 | + t.Helper() |
| 252 | + gvr := handlers.GetAgenticSessionV1Alpha1Resource() |
| 253 | + item, err := dc.Resource(gvr).Namespace("test-project").Get( |
| 254 | + context.Background(), "test-session", metav1.GetOptions{}, |
| 255 | + ) |
| 256 | + if err != nil { |
| 257 | + t.Fatalf("Failed to get session: %v", err) |
| 258 | + } |
| 259 | + dn, _, _ := unstructured.NestedString(item.Object, "spec", "displayName") |
| 260 | + return dn |
| 261 | +} |
| 262 | + |
| 263 | +func TestTriggerDisplayName_InitialPromptNotSkipped(t *testing.T) { |
| 264 | + cleanup := setupDisplayNameTest(t, map[string]interface{}{ |
| 265 | + "initialPrompt": "Help me debug auth", |
| 266 | + }) |
| 267 | + defer cleanup() |
| 268 | + |
| 269 | + called := false |
| 270 | + oldFn := handlers.GenerateDisplayNameAsync |
| 271 | + handlers.GenerateDisplayNameAsync = func(projectName, sessionName, userMessage string, sessionCtx handlers.SessionContext) { |
| 272 | + called = true |
| 273 | + } |
| 274 | + defer func() { handlers.GenerateDisplayNameAsync = oldFn }() |
| 275 | + |
| 276 | + msgs := []types.Message{ |
| 277 | + {ID: "msg-1", Role: "user", Content: "Help me debug auth"}, |
| 278 | + } |
| 279 | + |
| 280 | + triggerDisplayNameGenerationIfNeeded("test-project", "test-session", msgs) |
| 281 | + |
| 282 | + if !called { |
| 283 | + t.Error("Expected GenerateDisplayNameAsync to be called for initialPrompt message when displayName is empty") |
| 284 | + } |
| 285 | +} |
| 286 | + |
| 287 | +func TestTriggerDisplayName_SkipsWhenNameAlreadySet(t *testing.T) { |
| 288 | + cleanup := setupDisplayNameTest(t, map[string]interface{}{ |
| 289 | + "initialPrompt": "Help me debug auth", |
| 290 | + "displayName": "Debug Auth Middleware", |
| 291 | + }) |
| 292 | + defer cleanup() |
| 293 | + |
| 294 | + msgs := []types.Message{ |
| 295 | + {ID: "msg-1", Role: "user", Content: "Help me debug auth"}, |
| 296 | + } |
| 297 | + |
| 298 | + triggerDisplayNameGenerationIfNeeded("test-project", "test-session", msgs) |
| 299 | + |
| 300 | + // displayName should remain unchanged — ShouldGenerateDisplayName |
| 301 | + // returns false when displayName is already set. |
| 302 | + dn := getDisplayName(t, handlers.DynamicClient) |
| 303 | + if dn != "Debug Auth Middleware" { |
| 304 | + t.Errorf("Expected displayName to remain %q, got %q", "Debug Auth Middleware", dn) |
| 305 | + } |
| 306 | +} |
| 307 | + |
| 308 | +func TestTriggerDisplayName_SkipsWhenNoUserMessage(t *testing.T) { |
| 309 | + cleanup := setupDisplayNameTest(t, map[string]interface{}{ |
| 310 | + "initialPrompt": "Help me debug auth", |
| 311 | + }) |
| 312 | + defer cleanup() |
| 313 | + |
| 314 | + // Only assistant messages — no user content to generate from |
| 315 | + msgs := []types.Message{ |
| 316 | + {ID: "msg-1", Role: "assistant", Content: "I'll help you debug"}, |
| 317 | + } |
| 318 | + |
| 319 | + triggerDisplayNameGenerationIfNeeded("test-project", "test-session", msgs) |
| 320 | + |
| 321 | + dn := getDisplayName(t, handlers.DynamicClient) |
| 322 | + if dn != "" { |
| 323 | + t.Errorf("Expected empty displayName, got %q", dn) |
| 324 | + } |
| 325 | +} |
| 326 | + |
| 327 | +func TestTriggerDisplayName_SkipsWhenDynamicClientNil(t *testing.T) { |
| 328 | + oldDynamic := handlers.DynamicClient |
| 329 | + handlers.DynamicClient = nil |
| 330 | + defer func() { handlers.DynamicClient = oldDynamic }() |
| 331 | + |
| 332 | + msgs := []types.Message{ |
| 333 | + {ID: "msg-1", Role: "user", Content: "Help me debug auth"}, |
| 334 | + } |
| 335 | + |
| 336 | + // Should return early without panic when DynamicClient is nil |
| 337 | + triggerDisplayNameGenerationIfNeeded("test-project", "test-session", msgs) |
| 338 | +} |
0 commit comments