// UserRepo 仓储集成测试(t_user 主表查询 + 密码惰性升级写回)。 // // 依赖 test_helpers_test.go 的 setup/insertFixture;未设置 UNIFIED_TEST_DSN 时跳过。 package repository import ( "context" stderrors "errors" "testing" apperrors "yuansiwei/unified-backend/internal/infra/errors" "yuansiwei/unified-backend/internal/identity/id" identitymodel "yuansiwei/unified-backend/internal/identity/model" ) // TestUserRepo_GetByCanonicalUserID 命中 / 未命中。 func TestUserRepo_GetByCanonicalUserID(t *testing.T) { gdb := setup(t) ctx := context.Background() fx := insertFixture(t, gdb, ctx) repo := NewUserRepo(gdb) t.Run("命中", func(t *testing.T) { u, err := repo.GetByCanonicalUserID(ctx, fx.canonical) if err != nil { t.Fatalf("GetByCanonicalUserID 命中: %v", err) } if u.CanonicalUserID != fx.canonical { t.Errorf("返回 canonical_user_id = %q,期望 %q", u.CanonicalUserID, fx.canonical) } if u.Status != identitymodel.UserStatusActive { t.Errorf("status = %q,期望 %q", u.Status, identitymodel.UserStatusActive) } }) t.Run("未命中_返回ErrNotFound", func(t *testing.T) { _, err := repo.GetByCanonicalUserID(ctx, "00000000000000000000000000") if !stderrors.Is(err, apperrors.ErrNotFound) { t.Fatalf("期望 ErrNotFound,实际 %v", err) } }) } // TestUserRepo_UpdatePasswordLazyUpgrade 惰性升级写回(argon2 + salt NULL + hash_version)/ 未命中用户。 func TestUserRepo_UpdatePasswordLazyUpgrade(t *testing.T) { gdb := setup(t) ctx := context.Background() fx := insertFixture(t, gdb, ctx) repo := NewUserRepo(gdb) t.Run("命中_升级写回argon2_salt置NULL", func(t *testing.T) { // 升级前确认旧值 u, err := repo.GetByCanonicalUserID(ctx, fx.canonical) if err != nil { t.Fatalf("升级前取用户: %v", err) } if u.PasswordHash == nil || *u.PasswordHash != fx.hashOld { t.Fatalf("升级前 password_hash = %v,期望 %q", u.PasswordHash, fx.hashOld) } // 升级写回 if err := repo.UpdatePasswordLazyUpgrade(ctx, fx.canonical, fx.hashNew); err != nil { t.Fatalf("UpdatePasswordLazyUpgrade: %v", err) } // 断言升级后三列 u2, err := repo.GetByCanonicalUserID(ctx, fx.canonical) if err != nil { t.Fatalf("升级后取用户: %v", err) } if u2.PasswordHash == nil || *u2.PasswordHash != fx.hashNew { t.Errorf("升级后 password_hash = %v,期望 %q", u2.PasswordHash, fx.hashNew) } if u2.PasswordSalt != nil { t.Errorf("升级后 password_salt 应为 NULL,实际 %v", *u2.PasswordSalt) } if u2.HashVersion == nil || *u2.HashVersion != identitymodel.HashVersionArgon2 { t.Errorf("升级后 hash_version = %v,期望 argon2", u2.HashVersion) } }) t.Run("未命中用户_返回ErrNotFound", func(t *testing.T) { // 库里不存在该 ULID 的用户(RowsAffected=0 → ErrNotFound) ghost, err := id.NewCanonicalUserID() if err != nil { t.Fatalf("生成 ghost uid: %v", err) } if err := repo.UpdatePasswordLazyUpgrade(ctx, ghost, fx.hashNew); !stderrors.Is(err, apperrors.ErrNotFound) { t.Fatalf("期望 ErrNotFound,实际 %v", err) } }) }