Files
cms-server/data/attendance_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

482 lines
12 KiB
Go

package data_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"nixcn-cms/data"
"nixcn-cms/testutil"
)
func seedEventAndUser(t *testing.T, ctx context.Context) (eventId, userId uuid.UUID) {
t.Helper()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
return ev.EventId, u.UserId
}
func seedAttendance(t *testing.T, ctx context.Context, eventId, userId uuid.UUID) *data.Attendance {
t.Helper()
a := data.NewAttendance(
data.WithEventId(eventId),
data.WithUserId(userId),
data.WithKycId(uuid.Nil),
data.WithRole("attendee"),
data.WithState("success"),
)
_, err := a.Create(ctx)
require.NoError(t, err)
return a
}
func TestAttendanceCreate(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
a := seedAttendance(t, ctx, eventId, userId)
assert.NotEqual(t, uuid.Nil, a.AttendanceId)
}
func TestAttendanceGetAttendance(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
seedAttendance(t, ctx, eventId, userId)
got, err := new(data.Attendance).GetAttendance(ctx, userId, eventId)
require.NoError(t, err)
require.NotNil(t, got)
assert.Equal(t, eventId, got.EventId)
assert.Equal(t, userId, got.UserId)
}
func TestAttendanceGetAttendanceNotFound(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
got, err := new(data.Attendance).GetAttendance(ctx, uuid.New(), uuid.New())
require.NoError(t, err)
assert.Nil(t, got)
}
func TestAttendancePatch(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
a := seedAttendance(t, ctx, eventId, userId)
now := time.Now().Truncate(time.Second)
updated, err := new(data.Attendance).PatchByAttendanceId(ctx, a.AttendanceId,
data.WithState("suspended"),
data.WithCheckinAt(now),
)
require.NoError(t, err)
assert.Equal(t, "suspended", updated.State)
}
func TestAttendanceCountByEventID(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 3; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
seedAttendance(t, ctx, ev.EventId, u.UserId)
}
count, err := new(data.Attendance).CountUsersByEventID(ctx, ev.EventId)
require.NoError(t, err)
assert.Equal(t, int64(3), count)
}
func TestAttendanceGetJoinedEventIDs(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev1 := makeEvent(owner)
require.NoError(t, ev1.Create(ctx))
ev2 := makeEvent(owner)
require.NoError(t, ev2.Create(ctx))
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
seedAttendance(t, ctx, ev1.EventId, u.UserId)
joined, err := new(data.Attendance).GetJoinedEventIDs(ctx, u.UserId, []uuid.UUID{ev1.EventId, ev2.EventId})
require.NoError(t, err)
assert.True(t, joined[ev1.EventId])
assert.False(t, joined[ev2.EventId])
}
func TestAttendanceGenAndVerifyCheckinCode(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
a := seedAttendance(t, ctx, eventId, userId)
code, err := a.GenCheckinCode(ctx, a.EventId)
require.NoError(t, err)
require.NotNil(t, code)
assert.Len(t, *code, 6)
require.NoError(t, new(data.Attendance).VerifyCheckinCode(ctx, *code))
got, err := new(data.Attendance).GetAttendance(ctx, userId, eventId)
require.NoError(t, err)
assert.False(t, got.CheckinAt.IsZero())
}
func TestAttendanceVerifyCheckinCodeInvalid(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
err := new(data.Attendance).VerifyCheckinCode(ctx, "000000")
require.Error(t, err)
}
func TestAttendanceGetByAttendanceId(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
a := seedAttendance(t, ctx, eventId, userId)
got, err := new(data.Attendance).GetAttendanceByAttendanceId(ctx, a.AttendanceId)
require.NoError(t, err)
require.NotNil(t, got)
assert.Equal(t, a.AttendanceId, got.AttendanceId)
assert.Equal(t, eventId, got.EventId)
assert.Equal(t, userId, got.UserId)
}
func TestAttendanceGetByAttendanceIdNotFound(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
got, err := new(data.Attendance).GetAttendanceByAttendanceId(ctx, uuid.New())
require.NoError(t, err)
assert.Nil(t, got)
}
func TestAttendanceGetUsersByEventID(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 3; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
seedAttendance(t, ctx, ev.EventId, u.UserId)
}
users, err := new(data.Attendance).GetUsersByEventID(ctx, ev.EventId)
require.NoError(t, err)
require.NotNil(t, users)
assert.Len(t, *users, 3)
}
func TestAttendanceGetEventsByUserID(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev1 := makeEvent(owner)
require.NoError(t, ev1.Create(ctx))
ev2 := makeEvent(owner)
require.NoError(t, ev2.Create(ctx))
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
seedAttendance(t, ctx, ev1.EventId, u.UserId)
seedAttendance(t, ctx, ev2.EventId, u.UserId)
events, err := new(data.Attendance).GetEventsByUserID(ctx, u.UserId)
require.NoError(t, err)
require.NotNil(t, events)
assert.Len(t, *events, 2)
}
func TestAttendanceGetAttendanceListByEventId(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 4; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
seedAttendance(t, ctx, ev.EventId, u.UserId)
}
list, err := new(data.Attendance).GetAttendanceListByEventId(ctx, ev.EventId)
require.NoError(t, err)
require.NotNil(t, list)
assert.Len(t, *list, 4)
}
func TestAttendanceGetCheckedInEventIDs(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev1 := makeEvent(owner)
require.NoError(t, ev1.Create(ctx))
ev2 := makeEvent(owner)
require.NoError(t, ev2.Create(ctx))
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
a1 := seedAttendance(t, ctx, ev1.EventId, u.UserId)
_, err := new(data.Attendance).PatchByAttendanceId(ctx, a1.AttendanceId, data.WithCheckinAt(time.Now()))
require.NoError(t, err)
seedAttendance(t, ctx, ev2.EventId, u.UserId)
checkedIn, err := new(data.Attendance).GetCheckedInEventIDs(ctx, u.UserId, []uuid.UUID{ev1.EventId, ev2.EventId})
require.NoError(t, err)
assert.True(t, checkedIn[ev1.EventId])
assert.False(t, checkedIn[ev2.EventId])
}
func TestAttendanceCountCheckedInUsersByEventID(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 3; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
a := seedAttendance(t, ctx, ev.EventId, u.UserId)
if i < 2 {
_, err := new(data.Attendance).PatchByAttendanceId(ctx, a.AttendanceId, data.WithCheckinAt(time.Now()))
require.NoError(t, err)
}
}
count, err := new(data.Attendance).CountCheckedInUsersByEventID(ctx, ev.EventId)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
}
func TestAttendanceCountWithKycByEventID(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 3; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
kycId := uuid.Nil
if i < 2 {
kycId = uuid.New()
}
a := data.NewAttendance(
data.WithEventId(ev.EventId),
data.WithUserId(u.UserId),
data.WithKycId(kycId),
data.WithRole("attendee"),
data.WithState("success"),
)
_, err := a.Create(ctx)
require.NoError(t, err)
}
count, err := new(data.Attendance).CountWithKycByEventID(ctx, ev.EventId)
require.NoError(t, err)
assert.Equal(t, int64(2), count)
}
func TestAttendanceGetAttendanceListFiltered(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
owner := uuid.New()
ev := makeEvent(owner)
require.NoError(t, ev.Create(ctx))
for i := 0; i < 5; i++ {
u := data.NewUser(
data.WithEmail(uuid.New().String()+"@test.com"),
data.WithUsername(uuid.New().String()),
data.WithNickname(fmt.Sprintf("FilterUser%d", i)),
data.WithPermissionLevel(10),
)
require.NoError(t, u.Create(ctx))
kycId := uuid.Nil
if i < 3 {
kycId = uuid.New()
}
a := data.NewAttendance(
data.WithEventId(ev.EventId),
data.WithUserId(u.UserId),
data.WithKycId(kycId),
data.WithRole("attendee"),
data.WithState("success"),
)
_, err := a.Create(ctx)
require.NoError(t, err)
}
t.Run("no_filters_returns_all", func(t *testing.T) {
list, total, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
Limit: 20,
})
require.NoError(t, err)
assert.Equal(t, int64(5), total)
assert.Len(t, *list, 5)
})
t.Run("with_kyc_filter", func(t *testing.T) {
list, total, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
KycStatus: "with_kyc",
Limit: 20,
})
require.NoError(t, err)
assert.Equal(t, int64(3), total)
assert.Len(t, *list, 3)
})
t.Run("without_kyc_filter", func(t *testing.T) {
list, total, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
KycStatus: "without_kyc",
Limit: 20,
})
require.NoError(t, err)
assert.Equal(t, int64(2), total)
assert.Len(t, *list, 2)
})
t.Run("name_filter", func(t *testing.T) {
list, total, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
Name: "FilterUser1",
Limit: 20,
})
require.NoError(t, err)
assert.Equal(t, int64(1), total)
assert.Len(t, *list, 1)
})
t.Run("pagination", func(t *testing.T) {
list, total, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
Limit: 2,
Offset: 0,
})
require.NoError(t, err)
assert.Equal(t, int64(5), total)
assert.Len(t, *list, 2)
})
t.Run("sort_by_id_asc", func(t *testing.T) {
list, _, err := new(data.Attendance).GetAttendanceListFiltered(ctx, data.AttendanceListFilter{
EventId: ev.EventId,
SortBy: "id",
SortOrder: "asc",
Limit: 20,
})
require.NoError(t, err)
require.NotNil(t, list)
items := *list
for i := 1; i < len(items); i++ {
assert.GreaterOrEqual(t, items[i].Id, items[i-1].Id)
}
})
}
func TestAttendanceCheckinCodeExpiry(t *testing.T) {
mr := testutil.Setup(t)
ctx := context.Background()
eventId, userId := seedEventAndUser(t, ctx)
a := seedAttendance(t, ctx, eventId, userId)
code, err := a.GenCheckinCode(ctx, a.EventId)
require.NoError(t, err)
require.NotNil(t, code)
mr.FastForward(10 * time.Minute)
err = new(data.Attendance).VerifyCheckinCode(ctx, *code)
require.Error(t, err, "expired code should not be valid")
}
func TestAttendanceGetCheckedInEventIDsEmpty(t *testing.T) {
testutil.Setup(t)
ctx := context.Background()
result, err := new(data.Attendance).GetCheckedInEventIDs(ctx, uuid.New(), []uuid.UUID{})
require.NoError(t, err)
assert.Empty(t, result)
}