Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1) with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo. Brand: Starfire → Molecule AI. Slug: starfire / agent-molecule → molecule. Env vars: STARFIRE_* → MOLECULE_*. Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform. Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent. DB: agentmolecule → molecule. History truncated; see public repo for prior commits and contributor attribution. Verified green: go test -race ./... (platform), pytest (workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
159 lines
4.2 KiB
Go
159 lines
4.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/DATA-DOG/go-sqlmock"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// ==================== GET /events (List) ====================
|
|
|
|
func TestEventsList_Success(t *testing.T) {
|
|
mock := setupTestDB(t)
|
|
setupTestRedis(t)
|
|
handler := NewEventsHandler()
|
|
|
|
now := time.Now()
|
|
wsID := "ws-evt-1"
|
|
rows := sqlmock.NewRows([]string{"id", "event_type", "workspace_id", "payload", "created_at"}).
|
|
AddRow("evt-1", "WORKSPACE_ONLINE", &wsID, []byte(`{"name":"Agent A"}`), now).
|
|
AddRow("evt-2", "WORKSPACE_OFFLINE", &wsID, []byte(`{"name":"Agent A"}`), now)
|
|
|
|
mock.ExpectQuery("SELECT id, event_type, workspace_id, payload, created_at").
|
|
WillReturnRows(rows)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/events", nil)
|
|
|
|
handler.List(c)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var resp []map[string]interface{}
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to parse response: %v", err)
|
|
}
|
|
if len(resp) != 2 {
|
|
t.Errorf("expected 2 events, got %d", len(resp))
|
|
}
|
|
if resp[0]["event_type"] != "WORKSPACE_ONLINE" {
|
|
t.Errorf("expected event_type 'WORKSPACE_ONLINE', got %v", resp[0]["event_type"])
|
|
}
|
|
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Errorf("unmet sqlmock expectations: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEventsList_Empty(t *testing.T) {
|
|
mock := setupTestDB(t)
|
|
setupTestRedis(t)
|
|
handler := NewEventsHandler()
|
|
|
|
mock.ExpectQuery("SELECT id, event_type, workspace_id, payload, created_at").
|
|
WillReturnRows(sqlmock.NewRows([]string{"id", "event_type", "workspace_id", "payload", "created_at"}))
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/events", nil)
|
|
|
|
handler.List(c)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", w.Code)
|
|
}
|
|
|
|
var resp []map[string]interface{}
|
|
json.Unmarshal(w.Body.Bytes(), &resp)
|
|
if len(resp) != 0 {
|
|
t.Errorf("expected empty list, got %d events", len(resp))
|
|
}
|
|
}
|
|
|
|
func TestEventsList_DBError(t *testing.T) {
|
|
mock := setupTestDB(t)
|
|
setupTestRedis(t)
|
|
handler := NewEventsHandler()
|
|
|
|
mock.ExpectQuery("SELECT id, event_type, workspace_id, payload, created_at").
|
|
WillReturnError(sql.ErrConnDone)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest("GET", "/events", nil)
|
|
|
|
handler.List(c)
|
|
|
|
if w.Code != http.StatusInternalServerError {
|
|
t.Errorf("expected 500, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
// ==================== GET /events/:workspaceId (ListByWorkspace) ====================
|
|
|
|
func TestEventsListByWorkspace_Success(t *testing.T) {
|
|
mock := setupTestDB(t)
|
|
setupTestRedis(t)
|
|
handler := NewEventsHandler()
|
|
|
|
now := time.Now()
|
|
wsID := "ws-by-ws"
|
|
rows := sqlmock.NewRows([]string{"id", "event_type", "workspace_id", "payload", "created_at"}).
|
|
AddRow("evt-3", "WORKSPACE_PROVISIONING", &wsID, []byte(`{"name":"Agent B"}`), now)
|
|
|
|
mock.ExpectQuery("SELECT id, event_type, workspace_id, payload, created_at").
|
|
WithArgs("ws-by-ws").
|
|
WillReturnRows(rows)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{{Key: "workspaceId", Value: "ws-by-ws"}}
|
|
c.Request = httptest.NewRequest("GET", "/events/ws-by-ws", nil)
|
|
|
|
handler.ListByWorkspace(c)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var resp []map[string]interface{}
|
|
json.Unmarshal(w.Body.Bytes(), &resp)
|
|
if len(resp) != 1 {
|
|
t.Errorf("expected 1 event, got %d", len(resp))
|
|
}
|
|
|
|
if err := mock.ExpectationsWereMet(); err != nil {
|
|
t.Errorf("unmet sqlmock expectations: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestEventsListByWorkspace_DBError(t *testing.T) {
|
|
mock := setupTestDB(t)
|
|
setupTestRedis(t)
|
|
handler := NewEventsHandler()
|
|
|
|
mock.ExpectQuery("SELECT id, event_type, workspace_id, payload, created_at").
|
|
WithArgs("ws-err").
|
|
WillReturnError(sql.ErrConnDone)
|
|
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Params = gin.Params{{Key: "workspaceId", Value: "ws-err"}}
|
|
c.Request = httptest.NewRequest("GET", "/events/ws-err", nil)
|
|
|
|
handler.ListByWorkspace(c)
|
|
|
|
if w.Code != http.StatusInternalServerError {
|
|
t.Errorf("expected 500, got %d", w.Code)
|
|
}
|
|
}
|