2026-04-29 12:43:05 +08:00

138 lines
5.3 KiB
Go

// Package mysqltest provides real MySQL repositories for user-service tests.
package mysqltest
import (
"context"
"strings"
"testing"
"time"
userdomain "hyapp/services/user-service/internal/domain/user"
mysqlstorage "hyapp/services/user-service/internal/storage/mysql"
"hyapp/services/user-service/internal/testutil/mysqlschema"
)
// Repository wraps the production MySQL repository and adds test-only seed helpers.
type Repository struct {
*mysqlstorage.Repository
t testing.TB
schema *mysqlschema.Schema
}
// NewRepository creates an isolated MySQL schema and initializes the user-service tables.
func NewRepository(t testing.TB) *Repository {
t.Helper()
schema := mysqlschema.New(t)
repository, err := mysqlstorage.Open(context.Background(), schema.DSN)
if err != nil {
t.Fatalf("open storage repository failed: %v", err)
}
wrapped := &Repository{
Repository: repository,
t: t,
schema: schema,
}
t.Cleanup(wrapped.Close)
return wrapped
}
// Close shuts down the storage repository; mysqlschema owns schema cleanup.
func (r *Repository) Close() {
r.t.Helper()
if r.Repository != nil {
_ = r.Repository.Close()
}
}
// PutUser seeds or overwrites a user row plus its active default display_user_id.
func (r *Repository) PutUser(user userdomain.User) {
r.t.Helper()
user = user.NormalizeDisplayUserIDState()
if user.Status == "" {
user.Status = userdomain.StatusActive
}
nowMs := user.UpdatedAtMs
if nowMs == 0 {
nowMs = time.Now().UnixMilli()
}
if user.CreatedAtMs == 0 {
user.CreatedAtMs = nowMs
}
user.UpdatedAtMs = nowMs
_, err := r.schema.DB.ExecContext(context.Background(), `
INSERT INTO users (
user_id, default_display_user_id, current_display_user_id, current_display_user_id_kind,
current_display_user_id_expires_at_ms, username, gender, country, region_id, invite_code,
register_ip, register_user_agent, country_by_ip, register_device_id, register_device,
os_version, avatar, birth_date, app_version, build_number, source, install_channel,
campaign, platform, language, timezone, status, created_at_ms, updated_at_ms
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
default_display_user_id = VALUES(default_display_user_id),
current_display_user_id = VALUES(current_display_user_id),
current_display_user_id_kind = VALUES(current_display_user_id_kind),
current_display_user_id_expires_at_ms = VALUES(current_display_user_id_expires_at_ms),
username = VALUES(username),
gender = VALUES(gender),
country = VALUES(country),
region_id = VALUES(region_id),
invite_code = VALUES(invite_code),
register_ip = VALUES(register_ip),
register_user_agent = VALUES(register_user_agent),
country_by_ip = VALUES(country_by_ip),
register_device_id = VALUES(register_device_id),
register_device = VALUES(register_device),
os_version = VALUES(os_version),
avatar = VALUES(avatar),
birth_date = VALUES(birth_date),
app_version = VALUES(app_version),
build_number = VALUES(build_number),
source = VALUES(source),
install_channel = VALUES(install_channel),
campaign = VALUES(campaign),
platform = VALUES(platform),
language = VALUES(language),
timezone = VALUES(timezone),
status = VALUES(status),
updated_at_ms = VALUES(updated_at_ms)
`, user.UserID, user.DefaultDisplayUserID, user.CurrentDisplayUserID, string(user.CurrentDisplayUserIDKind), nullableInt64(user.CurrentDisplayUserIDExpiresAtMs), nullableString(user.Username), nullableString(user.Gender), nullableString(user.Country), nullableInt64(user.RegionID), nullableString(user.InviteCode), nullableString(user.RegisterIP), nullableString(user.RegisterUserAgent), nullableString(user.CountryByIP), nullableString(user.RegisterDeviceID), nullableString(user.RegisterDevice), nullableString(user.RegisterOSVersion), nullableString(user.Avatar), nullableString(user.BirthDate), nullableString(user.RegisterAppVersion), nullableString(user.RegisterBuildNumber), nullableString(user.RegisterSource), nullableString(user.RegisterInstallChannel), nullableString(user.RegisterCampaign), nullableString(user.RegisterPlatform), nullableString(user.Language), nullableString(user.Timezone), string(user.Status), user.CreatedAtMs, user.UpdatedAtMs)
if err != nil {
r.t.Fatalf("seed user %d failed: %v", user.UserID, err)
}
_, err = r.schema.DB.ExecContext(context.Background(), `
INSERT INTO user_display_user_ids (display_user_id, user_id, display_user_id_kind, status, assigned_at_ms, activated_at_ms, created_at_ms, updated_at_ms)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
user_id = VALUES(user_id),
display_user_id_kind = VALUES(display_user_id_kind),
status = VALUES(status),
activated_at_ms = VALUES(activated_at_ms),
updated_at_ms = VALUES(updated_at_ms)
`, user.DefaultDisplayUserID, user.UserID, string(userdomain.DisplayUserIDKindDefault), string(userdomain.DisplayUserIDStatusActive), user.CreatedAtMs, user.CreatedAtMs, user.CreatedAtMs, user.UpdatedAtMs)
if err != nil {
r.t.Fatalf("seed display_user_id %s failed: %v", user.DefaultDisplayUserID, err)
}
}
func nullableString(value string) any {
if strings.TrimSpace(value) == "" {
return nil
}
return value
}
func nullableInt64(value int64) any {
if value <= 0 {
return nil
}
return value
}