Files
cms-server/testutil/testutil.go
Asai Neko 0ab31652dd
All checks were successful
Server Check Build (NixCN CMS) TeamCity build finished
Rename attendance endpoint
Signed-off-by: Asai Neko <sugar@sne.moe>
2026-03-26 22:23:55 +08:00

173 lines
4.6 KiB
Go

package testutil
import (
"encoding/json"
"testing"
"time"
"nixcn-cms/data"
"nixcn-cms/internal/cryptography"
"github.com/alicebob/miniredis/v2"
"github.com/glebarez/sqlite"
"github.com/google/uuid"
"github.com/redis/go-redis/v9"
"github.com/spf13/viper"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// TestAESKey is a 32-byte AES key used for client_secret_key in tests.
const TestAESKey = "testkey1234567890123456789012345"
// TestKYCAESKey is a 16-byte AES key used for kyc_info_key in tests.
const TestKYCAESKey = "testkyckey123456"
// TestClientID is the OAuth client ID used across tests.
const TestClientID = "test-client"
// TestClientSecret is the plaintext client secret used in tests.
const TestClientSecret = "testsecret-32bytes-padded-here!!"
// SetupTestDB initialises an in-memory SQLite database and assigns it to
// data.Database. It auto-migrates all models including Agenda.
func SetupTestDB(t *testing.T) {
t.Helper()
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Fatalf("SetupTestDB: open sqlite: %v", err)
}
if err := db.AutoMigrate(
&data.User{},
&data.Event{},
&data.Attendance{},
&data.Client{},
&data.Kyc{},
&data.Agenda{},
); err != nil {
t.Fatalf("SetupTestDB: auto-migrate: %v", err)
}
data.Database = db
t.Cleanup(func() {
sqlDB, _ := db.DB()
_ = sqlDB.Close()
data.Database = nil
})
}
// SetupTestRedis starts an in-memory miniredis server and assigns it to
// data.Redis. It returns the miniredis instance for time manipulation.
func SetupTestRedis(t *testing.T) *miniredis.Miniredis {
t.Helper()
mr, err := miniredis.Run()
if err != nil {
t.Fatalf("SetupTestRedis: start miniredis: %v", err)
}
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
data.Redis = rdb
t.Cleanup(func() {
_ = rdb.Close()
mr.Close()
data.Redis = nil
})
return mr
}
// SetupViper configures the minimum viper keys needed by internal packages
// and services during tests.
func SetupViper(t *testing.T) {
t.Helper()
viper.Reset()
viper.Set("server.application", "test-app")
viper.Set("server.debug_mode", true)
viper.Set("server.external_url", "http://localhost:8080")
viper.Set("secrets.client_secret_key", TestAESKey)
viper.Set("secrets.kyc_info_key", TestKYCAESKey)
viper.Set("secrets.turnstile_secret", "test-turnstile-secret")
viper.Set("ttl.auth_code_ttl", 10*time.Minute)
viper.Set("ttl.access_ttl", 15*time.Minute)
viper.Set("ttl.refresh_ttl", 7*24*time.Hour)
viper.Set("ttl.checkin_code_ttl", 5*time.Minute)
viper.Set("kyc.ali_access_key_id", "test-key-id")
viper.Set("kyc.ali_access_key_secret", "test-key-secret")
viper.Set("kyc.passport_reader_public_key", "test-pub")
viper.Set("kyc.passport_reader_secret", "test-secret")
t.Cleanup(func() { viper.Reset() })
}
// Setup is a convenience that calls SetupViper, SetupTestDB, and
// SetupTestRedis, returning the miniredis instance.
func Setup(t *testing.T) *miniredis.Miniredis {
t.Helper()
SetupViper(t)
SetupTestDB(t)
return SetupTestRedis(t)
}
// SeedClient creates a test OAuth client in the database and returns it.
func SeedClient(t *testing.T) *data.Client {
t.Helper()
ctx := t.Context()
enc, err := cryptography.AESCBCEncrypt([]byte(TestClientSecret), []byte(TestAESKey))
if err != nil {
t.Fatalf("SeedClient: encrypt secret: %v", err)
}
redirectURIs := []string{"http://localhost/callback"}
urisJSON, _ := json.Marshal(redirectURIs)
client := &data.Client{
UUID: uuid.New(),
ClientId: TestClientID,
ClientSecret: enc,
ClientName: "Test Client",
RedirectUri: urisJSON,
}
if err := data.Database.WithContext(ctx).Create(client).Error; err != nil {
t.Fatalf("SeedClient: create: %v", err)
}
return client
}
// RandomEmail returns a unique email address for use in tests.
func RandomEmail() string {
return uuid.New().String() + "@test.com"
}
// SetupWithAuth is a convenience that calls Setup and SeedClient, then returns
// the miniredis instance and the seeded client.
func SetupWithAuth(t *testing.T) (*miniredis.Miniredis, *data.Client) {
t.Helper()
mr := Setup(t)
client := SeedClient(t)
return mr, client
}
// SeedUser creates a test user in the database and returns it.
func SeedUser(t *testing.T, email string, permLevel uint) *data.User {
t.Helper()
ctx := t.Context()
u := data.NewUser(
data.WithEmail(email),
data.WithUsername("user-"+uuid.New().String()[:8]),
data.WithPermissionLevel(permLevel),
data.WithNickname("Test User"),
)
if err := u.Create(ctx); err != nil {
t.Fatalf("SeedUser: create %q: %v", email, err)
}
return u
}