package sys import ( "context" "os" "regexp" "testing" "time" "hotgo/internal/library/imtenant" _ "github.com/gogf/gf/contrib/drivers/mysql/v2" "github.com/gogf/gf/v2/database/gdb" "golang.org/x/crypto/bcrypt" ) func TestRandomInviteCode(t *testing.T) { pattern := regexp.MustCompile(`^[A-Za-z]{5}$`) for i := 0; i < 100; i++ { code, err := randomInviteCode() if err != nil { t.Fatal(err) } if !pattern.MatchString(code) { t.Fatalf("invalid invite code %q", code) } } } func TestInviteDirectDatabase(t *testing.T) { link := os.Getenv("IM_MANAGER_INTEGRATION_DSN") if link == "" { t.Skip("IM_MANAGER_INTEGRATION_DSN is not set") } const group = "im_invite_integration" if err := gdb.SetConfigGroup(group, gdb.ConfigGroup{{Link: link}}); err != nil { t.Fatal(err) } db, err := gdb.Instance(group) if err != nil { t.Fatal(err) } ctx := context.Background() key := "integration-" + time.Now().UTC().Format("20060102150405.000000000") expiresAt := time.Now().UTC().Add(time.Hour).Round(time.Millisecond) batch, codes, err := createInviteBatch(ctx, db, 1, 1, 3, expiresAt, "integration", key) if err != nil { t.Fatal(err) } t.Cleanup(func() { _, _ = db.Exec(ctx, "DELETE FROM im_registration_invite_codes WHERE tenant_id=? AND batch_id=?", 1, batch.BatchID) _, _ = db.Exec(ctx, "DELETE FROM im_registration_invite_batches WHERE tenant_id=? AND id=?", 1, batch.BatchID) }) if batch.ActiveCount != 3 || len(codes) != 3 { t.Fatalf("unexpected batch result: %#v codes=%d", batch, len(codes)) } replayed, replayCodes, err := createInviteBatch(ctx, db, 1, 1, 3, expiresAt, "integration", key) if err != nil { t.Fatal(err) } if replayed.BatchID != batch.BatchID || len(replayCodes) != 0 { t.Fatalf("idempotent replay created a new batch: %#v", replayed) } items, total, err := queryInviteCodes(ctx, db, imInviteListRequest{TenantID: 1, BatchID: batch.BatchID}, 10, 0) if err != nil { t.Fatal(err) } if total != 3 || len(items) != 3 { t.Fatalf("unexpected query result total=%d items=%d", total, len(items)) } } func TestResetPasswordDirectDatabase(t *testing.T) { link := os.Getenv("IM_MANAGER_INTEGRATION_DSN") if link == "" { t.Skip("IM_MANAGER_INTEGRATION_DSN is not set") } const group = "im_password_reset_integration" if err := gdb.SetConfigGroup(group, gdb.ConfigGroup{{Link: link}}); err != nil { t.Fatal(err) } db, err := gdb.Instance(group) if err != nil { t.Fatal(err) } ctx := context.Background() userID, err := imtenant.NextSnowflakeID(ctx) if err != nil { t.Fatal(err) } now := time.Now().UTC().Round(time.Millisecond) username := "integration" + time.Now().UTC().Format("150405000000") if _, err = db.Exec(ctx, `INSERT INTO im_users(id,username,createdat,updatedat,state,useragent) VALUES(?,?,?,?,0,'integration-test')`, userID, username, now, now); err != nil { t.Fatal(err) } if _, err = db.Exec(ctx, "INSERT INTO im_auth(userid,authlvl,secret) VALUES(?,20,'old')", userID); err != nil { _, _ = db.Exec(ctx, "DELETE FROM im_users WHERE id=?", userID) t.Fatal(err) } t.Cleanup(func() { _, _ = db.Exec(ctx, "DELETE FROM im_business_events_outbox WHERE target=? AND event_type='security.password_reset'", userID) _, _ = db.Exec(ctx, "DELETE FROM im_user_security WHERE user_id=?", userID) _, _ = db.Exec(ctx, "DELETE FROM im_auth WHERE userid=?", userID) _, _ = db.Exec(ctx, "DELETE FROM im_users WHERE id=?", userID) }) scope := imAdminScope{TenantId: 1, OperatorId: 99, RequestId: "integration-password-reset"} if err = resetIMUserPassword(ctx, db, scope, userID, "new-password"); err != nil { t.Fatal(err) } secret, err := db.GetValue(ctx, "SELECT secret FROM im_auth WHERE userid=?", userID) if err != nil || bcrypt.CompareHashAndPassword(secret.Bytes(), []byte("new-password")) != nil { t.Fatalf("password hash was not updated: %v", err) } version, err := db.GetValue(ctx, "SELECT auth_version FROM im_user_security WHERE user_id=?", userID) if err != nil || version.Int() != 2 { t.Fatalf("unexpected auth version %d: %v", version.Int(), err) } events, err := db.GetValue(ctx, `SELECT COUNT(*) FROM im_business_events_outbox WHERE target=? AND event_type='security.password_reset' AND status='pending'`, userID) if err != nil || events.Int() != 1 { t.Fatalf("password reset event not written: count=%d err=%v", events.Int(), err) } }