package core import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" ) func TestHandleSend_AllowsAttachmentOnly(t *testing.T) { engine := NewEngine("test", &stubAgent{}, []Platform{&stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}}, "", LangEnglish) engine.interactiveStates["session-1"] = &interactiveState{ platform: &stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}, replyCtx: "reply-ctx", } api := &APIServer{engines: map[string]*Engine{"test": engine}} reqBody := SendRequest{ Project: "test", SessionKey: "session-1", Images: []ImageAttachment{{ MimeType: "image/png", Data: []byte("img"), FileName: "chart.png", }}, } body, err := json.Marshal(reqBody) if err != nil { t.Fatalf("marshal request: %v", err) } req := httptest.NewRequest(http.MethodPost, "/send", bytes.NewReader(body)) rec := httptest.NewRecorder() api.handleSend(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, body=%s", rec.Code, rec.Body.String()) } } // TestHandleSend_UnknownProjectReturns404 ensures the API does NOT silently // fall back to the only registered engine when the caller named a different // project. Previously a typo'd project name routed messages to whatever // single engine happened to be loaded. func TestHandleSend_UnknownProjectReturns404(t *testing.T) { engine := NewEngine("projectA", &stubAgent{}, []Platform{&stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}}, "", LangEnglish) engine.interactiveStates["session-1"] = &interactiveState{ platform: &stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}, replyCtx: "reply-ctx", } api := &APIServer{engines: map[string]*Engine{"projectA": engine}} body, err := json.Marshal(SendRequest{ Project: "projectB", // typo; does NOT match the loaded engine SessionKey: "session-1", Message: "hi", }) if err != nil { t.Fatalf("marshal: %v", err) } req := httptest.NewRequest(http.MethodPost, "/send", bytes.NewReader(body)) rec := httptest.NewRecorder() api.handleSend(rec, req) if rec.Code != http.StatusNotFound { t.Fatalf("status = %d, want 404; body=%s", rec.Code, rec.Body.String()) } if !strings.Contains(rec.Body.String(), `"projectB"`) { t.Errorf("body should mention the unknown project name, got: %s", rec.Body.String()) } } // TestHandleSend_EmptyProjectFallsBackToSingleEngine documents the intended // convenience behavior: when the caller omits project entirely AND only one // engine is loaded, the API picks it automatically. func TestHandleSend_EmptyProjectFallsBackToSingleEngine(t *testing.T) { engine := NewEngine("solo", &stubAgent{}, []Platform{&stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}}, "", LangEnglish) engine.interactiveStates["session-1"] = &interactiveState{ platform: &stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}, replyCtx: "reply-ctx", } api := &APIServer{engines: map[string]*Engine{"solo": engine}} body, err := json.Marshal(SendRequest{ // Project deliberately omitted. SessionKey: "session-1", Message: "hi", }) if err != nil { t.Fatalf("marshal: %v", err) } req := httptest.NewRequest(http.MethodPost, "/send", bytes.NewReader(body)) rec := httptest.NewRecorder() api.handleSend(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want 200; body=%s", rec.Code, rec.Body.String()) } } // TestHandleSend_EmptyProjectMultipleEnginesRequiresName ensures the API // refuses to guess when more than one engine is loaded and the caller did // not specify which one to send to. func TestHandleSend_EmptyProjectMultipleEnginesRequiresName(t *testing.T) { engineA := NewEngine("a", &stubAgent{}, []Platform{&stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}}, "", LangEnglish) engineB := NewEngine("b", &stubAgent{}, []Platform{&stubMediaPlatform{stubPlatformEngine: stubPlatformEngine{n: "test"}}}, "", LangEnglish) api := &APIServer{engines: map[string]*Engine{"a": engineA, "b": engineB}} body, err := json.Marshal(SendRequest{ SessionKey: "session-1", Message: "hi", }) if err != nil { t.Fatalf("marshal: %v", err) } req := httptest.NewRequest(http.MethodPost, "/send", bytes.NewReader(body)) rec := httptest.NewRecorder() api.handleSend(rec, req) if rec.Code != http.StatusBadRequest { t.Fatalf("status = %d, want 400; body=%s", rec.Code, rec.Body.String()) } }