125 lines
4.3 KiB
Go
125 lines
4.3 KiB
Go
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)
|
|
}
|
|
}
|