Files
ttstd-infinite-canvas/backend/internal/repository/email_identity_test.go

138 lines
4.2 KiB
Go

package repository
import (
"path/filepath"
"sync"
"testing"
"time"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"yingce/backend/internal/model"
)
func TestGmailMailboxRegistrationConcurrent(t *testing.T) {
dsn := filepath.Join(t.TempDir(), "users.db") + "?_busy_timeout=5000&_journal_mode=WAL"
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.User{}, &model.EmailVerificationCode{}); err != nil {
t.Fatal(err)
}
now := time.Now()
for _, id := range []string{"one", "two"} {
if err := db.Create(&model.EmailVerificationCode{ID: id, Email: id + "@gmail.com", ExpiresAt: now.Add(time.Hour)}).Error; err != nil {
t.Fatal(err)
}
}
var wg sync.WaitGroup
errs := make(chan error, 2)
start := make(chan struct{})
for i, email := range []string{"a.b+first@gmail.com", "ab+second@googlemail.com"} {
id := []string{"one", "two"}[i]
peer, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
sqlDB, _ := peer.DB()
t.Cleanup(func() { _ = sqlDB.Close() })
wg.Add(1)
go func() {
defer wg.Done()
<-start
errs <- New(peer).CreateUserWithEmailVerification(&model.User{ID: id, Username: id, Email: email}, id, now)
}()
}
close(start)
wg.Wait()
close(errs)
success := 0
for err := range errs {
if err == nil {
success++
} else if err.Error() != "邮箱已被注册" {
t.Fatalf("unexpected error: %v", err)
}
}
if success != 1 {
t.Fatalf("successful registrations=%d want 1", success)
}
var consumed int64
if err := db.Model(&model.EmailVerificationCode{}).Where("used_at IS NOT NULL").Count(&consumed).Error; err != nil || consumed != 1 {
t.Fatalf("consumed=%d err=%v", consumed, err)
}
}
func TestGmailMailboxLegacyLookupsRemainExact(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.User{}); err != nil {
t.Fatal(err)
}
r := New(db)
for _, user := range []model.User{{ID: "one", Username: "one", Email: "a.b+old@gmail.com"}, {ID: "two", Username: "two", Email: "ab@gmail.com"}} {
if err := db.Create(&user).Error; err != nil {
t.Fatal(err)
}
got, err := r.UserByEmail(user.Email)
if err != nil || got.ID != user.ID {
t.Fatalf("lookup %q=%v err=%v", user.Email, got, err)
}
}
if err := r.CheckEmailAvailable("ab+new@googlemail.com", ""); err == nil {
t.Fatal("legacy alias collision not detected")
}
if err := r.CheckEmailAvailable("a.b+new@example.com", ""); err != nil {
t.Fatal(err)
}
}
func TestGmailMailboxVerificationEntryPoints(t *testing.T) {
for _, mode := range []string{"ticket", "oauth", "bind", "first-user"} {
t.Run(mode, func(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
sqlDB, _ := db.DB()
t.Cleanup(func() { _ = sqlDB.Close() })
if err := db.AutoMigrate(&model.User{}, &model.AuthVerification{}, &model.UserIdentity{}, &model.CreditAccount{}); err != nil {
t.Fatal(err)
}
r := New(db)
if err := db.Create(&model.User{ID: "owner", Username: "owner", Email: "a.b@gmail.com"}).Error; err != nil {
t.Fatal(err)
}
user := model.User{ID: "new", Username: "new", Email: "ab+tag@googlemail.com", Status: model.UserStatusActive}
v := model.AuthVerification{ID: "ticket", UserID: "new", Email: user.Email, Ready: true, ExpiresAt: time.Now().Add(time.Hour)}
if err := db.Create(&v).Error; err != nil {
t.Fatal(err)
}
switch mode {
case "ticket":
err = r.CreateUserWithVerification(&user, v.ID)
case "oauth":
err = r.CreateOAuthUser(&user, &model.UserIdentity{ID: "identity", UserID: user.ID, Provider: "linuxdo", Subject: "subject"})
case "first-user":
err = r.CreateRegisteredUser(&user)
case "bind":
user.Email = ""
if err := db.Create(&user).Error; err != nil {
t.Fatal(err)
}
_, err = r.CompleteAuthVerification(&v, true)
}
if err == nil || err.Error() != "邮箱已被注册" {
t.Fatalf("alias accepted or unexpected error: %v", err)
}
stored, err := r.AuthVerification(v.ID)
if err != nil || stored.UsedAt != nil {
t.Fatalf("rejected collision consumed ticket: %v err=%v", stored, err)
}
})
}
}