package logic import ( "context" "errors" "testing" "spark-server/internal/infrastructure/id" smslogic "spark-server/internal/module/sms/logic" smsmodel "spark-server/internal/module/sms/model" friendlogic "spark-server/internal/module/friend/logic" friendmodel "spark-server/internal/module/friend/model" momentlogic "spark-server/internal/module/moment/logic" momentmodel "spark-server/internal/module/moment/model" "spark-server/internal/module/user/entity" "spark-server/internal/module/user/model" "spark-server/internal/pkg/errs" "spark-server/internal/pkg/reqctx" ) func TestDeleteAccountArchivesAndAllowsReregister(t *testing.T) { svc, repo, _ := testService(t) ctx := reqctx.With(t.Context(), &reqctx.RequestContext{RealIP: "203.0.113.10", Language: "zh-CN"}) device := &entity.LoginDevice{DeviceID: 7, DeviceType: entity.DeviceIOS} u, err := svc.AuthenticateEmail(ctx, "test01@spark.com", "1", device) if err != nil { t.Fatal(err) } if err := svc.DeleteAccount(ctx, u.ID, DeleteAccountInput{}); err != nil { t.Fatal(err) } if _, err := repo.GetByID(ctx, u.ID); !errors.Is(err, errs.ErrNotFound) { t.Fatalf("live user %v", err) } if _, err := repo.GetByEmail(ctx, "test01@spark.com"); !errors.Is(err, errs.ErrNotFound) { t.Fatalf("email still bound %v", err) } archived, err := repo.GetDeleted(ctx, u.ID) if err != nil || archived.Email != "test01@spark.com" || archived.SparkID != u.SparkID { t.Fatalf("archive %+v %v", archived, err) } again, err := svc.AuthenticateEmail(ctx, "test01@spark.com", "1", device) if err != nil { t.Fatal(err) } if again.ID == u.ID { t.Fatal("uid reused") } } func TestDeleteAccountPurgesFriendsAndMoments(t *testing.T) { ids, err := id.New(1) if err != nil { t.Fatal(err) } repo := model.NewMemoryRepo() store := smsmodel.NewMemoryStore() smsSvc := smslogic.NewService(store, nil, nil, nil) users := NewService(repo, smsSvc, ids, nil) friends := friendlogic.NewService(friendmodel.NewMemoryRepo(), users, ids, nil) moments := momentlogic.NewService(momentmodel.NewMemoryRepo(), friends, users, nil, ids) users.BindAccountCleanup(nil, nil, friends, moments) ctx := reqctx.With(t.Context(), &reqctx.RequestContext{RealIP: "10.0.0.1", Language: "zh-CN"}) a, err := users.AuthenticateEmail(ctx, "test01@spark.com", "1", &entity.LoginDevice{DeviceID: 1, DeviceType: entity.DeviceIOS}) if err != nil { t.Fatal(err) } b, err := users.AuthenticateEmail(ctx, "test02@spark.com", "1", &entity.LoginDevice{DeviceID: 2, DeviceType: entity.DeviceWeb}) if err != nil { t.Fatal(err) } applied, err := friends.Apply(ctx, a.ID, &friendlogic.ApplyInput{Email: "test02@spark.com"}) if err != nil { t.Fatal(err) } if _, err := friends.Accept(ctx, b.ID, friendlogic.AcceptInput{RequestID: applied.RequestID}); err != nil { t.Fatal(err) } ctxA := reqctx.With(ctx, &reqctx.RequestContext{UserID: a.ID, RealIP: "10.0.0.1", Language: "zh-CN"}) pub, err := moments.Publish(ctxA, a.ID, &momentlogic.PublishInput{Text: "bye"}) if err != nil || pub == nil { t.Fatalf("publish %+v %v", pub, err) } if err := users.DeleteAccount(ctx, a.ID, DeleteAccountInput{}); err != nil { t.Fatal(err) } ok, err := friends.AreFriends(ctx, a.ID, b.ID) if err != nil || ok { t.Fatalf("friends after cancel %v %v", ok, err) } if _, err := moments.Get(ctx, b.ID, pub.ID); !errors.Is(err, errs.ErrNotFound) { t.Fatalf("moment still visible %v", err) } } func (m *memObjects) Delete(_ context.Context, key string) error { delete(m.kv, key) return nil }