Files
cms-server/api/agenda/agenda_handler_test.go
Asai Neko 82c412d839
All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Add more tests for modules co worked by claude
Signed-off-by: Asai Neko <sugar@sne.moe>
2026-03-26 23:36:40 +08:00

444 lines
14 KiB
Go

package agenda
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/spf13/viper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"nixcn-cms/data"
"nixcn-cms/internal/authtoken"
"nixcn-cms/service/service_agenda"
"nixcn-cms/service/service_event"
"nixcn-cms/testutil"
)
func init() { gin.SetMode(gin.TestMode) }
func issueToken(t *testing.T, userId uuid.UUID) string {
t.Helper()
tok := &authtoken.Token{Application: viper.GetString("server.application")}
access, _, err := tok.IssueTokens(context.Background(), testutil.TestClientID, userId)
require.NoError(t, err)
return access
}
func newAgendaRouter(t *testing.T) *gin.Engine {
t.Helper()
r := gin.New()
ApiHandler(r.Group("/agenda"))
return r
}
func postWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder {
t.Helper()
b, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPost, path, bytes.NewBuffer(b))
req.Header.Set("Content-Type", "application/json")
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func patchWithBearer(t *testing.T, r *gin.Engine, path, token string, body any) *httptest.ResponseRecorder {
t.Helper()
b, _ := json.Marshal(body)
req := httptest.NewRequest(http.MethodPatch, path, bytes.NewBuffer(b))
req.Header.Set("Content-Type", "application/json")
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
func getWithBearer(t *testing.T, r *gin.Engine, path, token string) *httptest.ResponseRecorder {
t.Helper()
req := httptest.NewRequest(http.MethodGet, path, nil)
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
return w
}
// seedEventWithAttendee creates an event owned by owner and joins it with attendee.
func seedEventWithAttendee(t *testing.T, owner, attendee *data.User) *data.Event {
t.Helper()
ctx := t.Context()
eventSvc := service_event.NewEventService()
cr := eventSvc.Create(&service_event.EventCreatePayload{
Context: ctx,
Data: &service_event.EventCreateData{
UserId: owner.UserId.String(),
PermissionLevel: owner.PermissionLevel,
Type: "party",
Name: "Agenda Test Event",
Subtitle: "sub",
StartTime: time.Now().Add(24 * time.Hour),
EndTime: time.Now().Add(48 * time.Hour),
Quota: 100,
Limit: 100,
},
})
require.Equal(t, 200, cr.Common.HttpCode)
eventId, err := uuid.Parse(cr.Data.EventId)
require.NoError(t, err)
// Join as attendee
agendaSvc := service_agenda.NewAgendaService()
jr := agendaSvc.Submit(&service_agenda.SubmitPayload{
Context: ctx,
UserId: attendee.UserId,
Data: &service_agenda.SubmitData{EventId: eventId, Name: "dummy"},
})
// It's OK if this fails due to not being joined; we just need the event.
_ = jr
// Actually join via event service
joinResult := eventSvc.Join(&service_event.EventJoinPayload{
Context: ctx,
Data: &service_event.EventJoinData{
EventId: cr.Data.EventId,
UserId: attendee.UserId.String(),
},
})
require.Equal(t, 200, joinResult.Common.HttpCode)
var event data.Event
require.NoError(t, data.Database.Where("event_id = ?", eventId).First(&event).Error)
return &event
}
// ---- Submit ----
func TestAgendaSubmitHandlerNoAuth(t *testing.T) {
testutil.Setup(t)
r := newAgendaRouter(t)
w := postWithBearer(t, r, "/agenda/submit", "", map[string]any{
"event_id": uuid.New().String(),
"name": "Test Talk",
})
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestAgendaSubmitHandlerMissingFields(t *testing.T) {
testutil.SetupWithAuth(t)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
token := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
// Missing name and description → handler returns 400
w := postWithBearer(t, r, "/agenda/submit", token, map[string]any{
"event_id": uuid.New().String(),
})
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaSubmitHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
token := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
w := postWithBearer(t, r, "/agenda/submit", token, service_agenda.SubmitData{
EventId: event.EventId,
Name: "My Talk",
Description: "About Go testing",
})
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- ScheduleGet ----
func TestAgendaScheduleGetHandlerInvalidEventId(t *testing.T) {
testutil.SetupWithAuth(t)
user := testutil.SeedUser(t, testutil.RandomEmail(), 10)
token := issueToken(t, user.UserId)
r := newAgendaRouter(t)
w := getWithBearer(t, r, "/agenda/schedule?event_id=not-a-uuid", token)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaScheduleGetHandlerNotPublished(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
token := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
w := getWithBearer(t, r, "/agenda/schedule?event_id="+event.EventId.String(), token)
assert.Equal(t, http.StatusForbidden, w.Code)
}
// ---- MyList ----
func TestAgendaMyListHandlerInvalidEventId(t *testing.T) {
testutil.SetupWithAuth(t)
user := testutil.SeedUser(t, testutil.RandomEmail(), 10)
token := issueToken(t, user.UserId)
r := newAgendaRouter(t)
w := getWithBearer(t, r, "/agenda/my-list?event_id=bad-uuid", token)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaMyListHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
token := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
w := getWithBearer(t, r, "/agenda/my-list?event_id="+event.EventId.String(), token)
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- List (manager) ----
func TestAgendaListHandlerInvalidEventId(t *testing.T) {
testutil.SetupWithAuth(t)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
token := issueToken(t, manager.UserId)
r := newAgendaRouter(t)
w := getWithBearer(t, r, "/agenda/list?event_id=bad-uuid", token)
assert.Equal(t, http.StatusBadRequest, w.Code)
}
// ---- Review (manager) ----
func TestAgendaReviewHandlerMissingFields(t *testing.T) {
testutil.SetupWithAuth(t)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
token := issueToken(t, manager.UserId)
r := newAgendaRouter(t)
w := patchWithBearer(t, r, "/agenda/review", token, map[string]any{
"status": "approved",
// missing agenda_id and event_id → 400
})
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaReviewHandlerInvalidStatus(t *testing.T) {
testutil.SetupWithAuth(t)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
token := issueToken(t, manager.UserId)
r := newAgendaRouter(t)
w := patchWithBearer(t, r, "/agenda/review", token, service_agenda.AgendaReviewData{
EventId: uuid.New(),
AgendaId: uuid.New(),
Status: "maybe",
})
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaReviewHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
managerToken := issueToken(t, manager.UserId)
attendeeToken := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{
EventId: event.EventId,
Name: "Talk to Review",
Description: "desc",
})
require.Equal(t, http.StatusOK, submitW.Code)
var submitResp map[string]any
require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp))
agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string)
w := patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{
EventId: event.EventId,
AgendaId: uuid.MustParse(agendaId),
Status: "approved",
})
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- List (success) ----
func TestAgendaListHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
managerToken := issueToken(t, manager.UserId)
attendeeToken := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{
EventId: event.EventId,
Name: "Talk 1",
})
w := getWithBearer(t, r, "/agenda/list?event_id="+event.EventId.String(), managerToken)
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- Update ----
func TestAgendaUpdateHandlerMissingAgendaId(t *testing.T) {
testutil.SetupWithAuth(t)
user := testutil.SeedUser(t, testutil.RandomEmail(), 10)
token := issueToken(t, user.UserId)
r := newAgendaRouter(t)
w := patchWithBearer(t, r, "/agenda/update", token, map[string]any{
"name": "New Name",
})
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaUpdateHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
attendeeToken := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{
EventId: event.EventId,
Name: "Original Talk",
Description: "desc",
})
require.Equal(t, http.StatusOK, submitW.Code)
var submitResp map[string]any
require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp))
agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string)
newName := "Updated Talk"
w := patchWithBearer(t, r, "/agenda/update", attendeeToken, service_agenda.AgendaUpdateData{
AgendaId: uuid.MustParse(agendaId),
Name: &newName,
})
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- Schedule PATCH ----
func TestAgendaScheduleHandlerMissingAgendaId(t *testing.T) {
testutil.SetupWithAuth(t)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
token := issueToken(t, manager.UserId)
r := newAgendaRouter(t)
w := patchWithBearer(t, r, "/agenda/schedule", token, map[string]any{
"start_time": time.Now().Add(time.Hour),
"end_time": time.Now().Add(2 * time.Hour),
})
assert.Equal(t, http.StatusBadRequest, w.Code)
}
func TestAgendaScheduleHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
managerToken := issueToken(t, manager.UserId)
attendeeToken := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{
EventId: event.EventId,
Name: "Schedule Me",
Description: "base64desc",
})
require.Equal(t, http.StatusOK, submitW.Code)
var submitResp map[string]any
require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp))
agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string)
reviewW := patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{
EventId: event.EventId,
AgendaId: uuid.MustParse(agendaId),
Status: "approved",
})
require.Equal(t, http.StatusOK, reviewW.Code)
now := time.Now()
w := patchWithBearer(t, r, "/agenda/schedule", managerToken, service_agenda.AgendaScheduleData{
AgendaId: uuid.MustParse(agendaId),
StartTime: now.Add(time.Hour),
EndTime: now.Add(2 * time.Hour),
})
assert.Equal(t, http.StatusOK, w.Code)
}
// ---- ScheduleGet (success) ----
func TestAgendaScheduleGetHandlerSuccess(t *testing.T) {
testutil.SetupWithAuth(t)
owner := testutil.SeedUser(t, testutil.RandomEmail(), 40)
attendee := testutil.SeedUser(t, testutil.RandomEmail(), 10)
event := seedEventWithAttendee(t, owner, attendee)
manager := testutil.SeedUser(t, testutil.RandomEmail(), 30)
managerToken := issueToken(t, manager.UserId)
attendeeToken := issueToken(t, attendee.UserId)
r := newAgendaRouter(t)
submitW := postWithBearer(t, r, "/agenda/submit", attendeeToken, service_agenda.SubmitData{
EventId: event.EventId,
Name: "Published Talk",
Description: "base64desc",
})
require.Equal(t, http.StatusOK, submitW.Code)
var submitResp map[string]any
require.NoError(t, json.Unmarshal(submitW.Body.Bytes(), &submitResp))
agendaId := submitResp["data"].(map[string]any)["agenda_id"].(string)
patchWithBearer(t, r, "/agenda/review", managerToken, service_agenda.AgendaReviewData{
EventId: event.EventId,
AgendaId: uuid.MustParse(agendaId),
Status: "approved",
})
now := time.Now()
patchWithBearer(t, r, "/agenda/schedule", managerToken, service_agenda.AgendaScheduleData{
AgendaId: uuid.MustParse(agendaId),
StartTime: now.Add(time.Hour),
EndTime: now.Add(2 * time.Hour),
})
require.NoError(t, new(data.Event).PatchByEventId(t.Context(), event.EventId, data.WithIsAgendaPublished(true)))
w := getWithBearer(t, r, "/agenda/schedule?event_id="+event.EventId.String(), attendeeToken)
assert.Equal(t, http.StatusOK, w.Code)
var resp map[string]any
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
items, ok := resp["data"].([]any)
require.True(t, ok)
assert.Len(t, items, 1)
}