205 lines
5.8 KiB
Go
205 lines
5.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
usermodel "wx_service/internal/model"
|
|
quitmodel "wx_service/internal/quitcheckin/model"
|
|
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/logger"
|
|
)
|
|
|
|
func setupSupervisorTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
|
|
Logger: logger.Default.LogMode(logger.Silent),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
|
|
if err := db.AutoMigrate(
|
|
&usermodel.User{},
|
|
&quitmodel.Profile{},
|
|
&quitmodel.DailyStatus{},
|
|
&quitmodel.RelapseEvent{},
|
|
&quitmodel.HPChangeLog{},
|
|
&quitmodel.SupervisorInvite{},
|
|
&quitmodel.SupervisorBinding{},
|
|
&quitmodel.RewardGoal{},
|
|
&quitmodel.DreamPreset{},
|
|
); err != nil {
|
|
t.Fatalf("auto migrate: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestSupervisorInviteBindAndOverview(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := setupSupervisorTestDB(t)
|
|
svc := NewService(db)
|
|
ctx := context.Background()
|
|
|
|
ownerUID := 3001
|
|
supervisorUID := 3002
|
|
now := time.Date(2026, 4, 16, 10, 0, 0, 0, time.Local)
|
|
|
|
if err := db.Create(&usermodel.User{ID: uint(ownerUID), NickName: "owner"}).Error; err != nil {
|
|
t.Fatalf("seed owner user: %v", err)
|
|
}
|
|
if err := db.Create(&usermodel.User{ID: uint(supervisorUID), NickName: "supervisor"}).Error; err != nil {
|
|
t.Fatalf("seed supervisor user: %v", err)
|
|
}
|
|
|
|
startDate := time.Date(2026, 4, 10, 0, 0, 0, 0, time.Local)
|
|
if _, err := svc.UpsertProfile(ctx, ownerUID, UpsertProfileRequest{
|
|
QuitStartDate: &startDate,
|
|
PackPriceCent: intPtr(2500),
|
|
BaselineCigsPerDay: intPtr(10),
|
|
}, "owner", "", now); err != nil {
|
|
t.Fatalf("upsert profile: %v", err)
|
|
}
|
|
|
|
invite, err := svc.CreateSupervisorInvite(ctx, ownerUID, now, 7)
|
|
if err != nil {
|
|
t.Fatalf("create invite: %v", err)
|
|
}
|
|
if invite.Token == "" {
|
|
t.Fatalf("invite token empty")
|
|
}
|
|
|
|
if err := svc.BindSupervisorInvite(ctx, supervisorUID, invite.Token, now); err != nil {
|
|
t.Fatalf("bind: %v", err)
|
|
}
|
|
|
|
overview, err := svc.GetSupervisorOverview(ctx, supervisorUID, now)
|
|
if err != nil {
|
|
t.Fatalf("overview: %v", err)
|
|
}
|
|
if len(overview.Items) != 1 {
|
|
t.Fatalf("overview items=%d, want=1", len(overview.Items))
|
|
}
|
|
if overview.Items[0].Owner.UserID != ownerUID {
|
|
t.Fatalf("owner uid=%d, want=%d", overview.Items[0].Owner.UserID, ownerUID)
|
|
}
|
|
if overview.Items[0].Home.Summary.HPCurrent <= 0 {
|
|
t.Fatalf("hp_current=%d, want > 0", overview.Items[0].Home.Summary.HPCurrent)
|
|
}
|
|
|
|
status, err := svc.GetSupervisorStatus(ctx, ownerUID)
|
|
if err != nil {
|
|
t.Fatalf("status: %v", err)
|
|
}
|
|
if len(status.Items) != 1 || status.Items[0].UserID != supervisorUID {
|
|
t.Fatalf("status=%v, want one supervisor uid=%d", status.Items, supervisorUID)
|
|
}
|
|
}
|
|
|
|
func TestSupervisorRevokeBindingBySupervisor(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := setupSupervisorTestDB(t)
|
|
svc := NewService(db)
|
|
ctx := context.Background()
|
|
|
|
ownerUID := 3101
|
|
supervisorUID := 3102
|
|
now := time.Date(2026, 4, 16, 10, 0, 0, 0, time.Local)
|
|
|
|
if err := db.Create(&usermodel.User{ID: uint(ownerUID), NickName: "owner"}).Error; err != nil {
|
|
t.Fatalf("seed owner user: %v", err)
|
|
}
|
|
if err := db.Create(&usermodel.User{ID: uint(supervisorUID), NickName: "supervisor"}).Error; err != nil {
|
|
t.Fatalf("seed supervisor user: %v", err)
|
|
}
|
|
|
|
startDate := time.Date(2026, 4, 10, 0, 0, 0, 0, time.Local)
|
|
if _, err := svc.UpsertProfile(ctx, ownerUID, UpsertProfileRequest{
|
|
QuitStartDate: &startDate,
|
|
PackPriceCent: intPtr(2500),
|
|
BaselineCigsPerDay: intPtr(10),
|
|
}, "owner", "", now); err != nil {
|
|
t.Fatalf("upsert profile: %v", err)
|
|
}
|
|
|
|
invite, err := svc.CreateSupervisorInvite(ctx, ownerUID, now, 7)
|
|
if err != nil {
|
|
t.Fatalf("create invite: %v", err)
|
|
}
|
|
if err := svc.BindSupervisorInvite(ctx, supervisorUID, invite.Token, now); err != nil {
|
|
t.Fatalf("bind: %v", err)
|
|
}
|
|
|
|
if err := svc.RevokeSupervisorBinding(ctx, supervisorUID, ownerUID, supervisorUID, now); err != nil {
|
|
t.Fatalf("revoke by supervisor: %v", err)
|
|
}
|
|
|
|
overview, err := svc.GetSupervisorOverview(ctx, supervisorUID, now)
|
|
if err != nil {
|
|
t.Fatalf("overview: %v", err)
|
|
}
|
|
if len(overview.Items) != 0 {
|
|
t.Fatalf("overview items=%d, want=0 after revoke", len(overview.Items))
|
|
}
|
|
}
|
|
|
|
func TestSupervisorBindRespectsMaxSupervisors(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := setupSupervisorTestDB(t)
|
|
svc := NewService(db)
|
|
ctx := context.Background()
|
|
|
|
ownerUID := 3201
|
|
now := time.Date(2026, 4, 16, 10, 0, 0, 0, time.Local)
|
|
|
|
if err := db.Create(&usermodel.User{ID: uint(ownerUID), NickName: "owner"}).Error; err != nil {
|
|
t.Fatalf("seed owner user: %v", err)
|
|
}
|
|
|
|
startDate := time.Date(2026, 4, 10, 0, 0, 0, 0, time.Local)
|
|
if _, err := svc.UpsertProfile(ctx, ownerUID, UpsertProfileRequest{
|
|
QuitStartDate: &startDate,
|
|
PackPriceCent: intPtr(2500),
|
|
BaselineCigsPerDay: intPtr(10),
|
|
}, "owner", "", now); err != nil {
|
|
t.Fatalf("upsert profile: %v", err)
|
|
}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
supervisorUID := 3300 + i
|
|
if err := db.Create(&usermodel.User{ID: uint(supervisorUID), NickName: "s"}).Error; err != nil {
|
|
t.Fatalf("seed supervisor user: %v", err)
|
|
}
|
|
invite, err := svc.CreateSupervisorInvite(ctx, ownerUID, now, 7)
|
|
if err != nil {
|
|
t.Fatalf("create invite: %v", err)
|
|
}
|
|
if err := svc.BindSupervisorInvite(ctx, supervisorUID, invite.Token, now); err != nil {
|
|
t.Fatalf("bind #%d: %v", i+1, err)
|
|
}
|
|
}
|
|
|
|
supervisorUID := 3399
|
|
if err := db.Create(&usermodel.User{ID: uint(supervisorUID), NickName: "s4"}).Error; err != nil {
|
|
t.Fatalf("seed supervisor user: %v", err)
|
|
}
|
|
invite, err := svc.CreateSupervisorInvite(ctx, ownerUID, now, 7)
|
|
if err != nil {
|
|
t.Fatalf("create invite: %v", err)
|
|
}
|
|
if err := svc.BindSupervisorInvite(ctx, supervisorUID, invite.Token, now); err == nil {
|
|
t.Fatalf("bind #4 should fail")
|
|
} else if !errors.Is(err, ErrSupervisorLimitReached) {
|
|
t.Fatalf("bind #4 err=%v, want ErrSupervisorLimitReached", err)
|
|
}
|
|
}
|