mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 21:39:54 +02:00
- Migration 046 adds UNIQUE(workspace_id, name) with dedup (keep most recently updated) - CreateAgent handler returns 409 Conflict scoped to constraint name agent_workspace_name_unique - Dedup verified as (0 rows) against worktree DB; rerun against staging/production before applying - Down migration drops the constraint only; deleted rows and cascaded data are not restored Co-authored-by: Anup Joy <joyanup@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
56 lines
1.6 KiB
Go
56 lines
1.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestCreateAgent_RejectsDuplicateName(t *testing.T) {
|
|
if testHandler == nil {
|
|
t.Skip("database not available")
|
|
}
|
|
|
|
// Clean up any agents created by this test.
|
|
t.Cleanup(func() {
|
|
testPool.Exec(context.Background(),
|
|
`DELETE FROM agent WHERE workspace_id = $1 AND name = $2`,
|
|
testWorkspaceID, "duplicate-name-test-agent",
|
|
)
|
|
})
|
|
|
|
body := map[string]any{
|
|
"name": "duplicate-name-test-agent",
|
|
"description": "first description",
|
|
"runtime_id": testRuntimeID,
|
|
"visibility": "private",
|
|
"max_concurrent_tasks": 1,
|
|
}
|
|
|
|
// First call — creates the agent.
|
|
w1 := httptest.NewRecorder()
|
|
testHandler.CreateAgent(w1, newRequest(http.MethodPost, "/api/agents", body))
|
|
if w1.Code != http.StatusCreated {
|
|
t.Fatalf("first CreateAgent: expected 201, got %d: %s", w1.Code, w1.Body.String())
|
|
}
|
|
var resp1 map[string]any
|
|
if err := json.NewDecoder(w1.Body).Decode(&resp1); err != nil {
|
|
t.Fatalf("decode first response: %v", err)
|
|
}
|
|
agentID1, _ := resp1["id"].(string)
|
|
if agentID1 == "" {
|
|
t.Fatalf("first CreateAgent: no id in response: %v", resp1)
|
|
}
|
|
|
|
// Second call — same name must be rejected with 409 Conflict.
|
|
// The unique constraint prevents silent duplicates; the UI shows a clear error.
|
|
body["description"] = "updated description"
|
|
w2 := httptest.NewRecorder()
|
|
testHandler.CreateAgent(w2, newRequest(http.MethodPost, "/api/agents", body))
|
|
if w2.Code != http.StatusConflict {
|
|
t.Fatalf("second CreateAgent with duplicate name: expected 409, got %d: %s", w2.Code, w2.Body.String())
|
|
}
|
|
}
|