//go:build integration package inttest import ( "context" "errors" "testing" "github.com/google/uuid" "scrabble/backend/internal/account" ) // TestAccountProvisionByIdentity covers find-or-create semantics, distinct // accounts per identity, GetByID, and the identity confirmed flag per kind. func TestAccountProvisionByIdentity(t *testing.T) { ctx := context.Background() store := account.NewStore(testDB) tgExternal := "tg-" + uuid.NewString() first, err := store.ProvisionByIdentity(ctx, account.KindTelegram, tgExternal) if err != nil { t.Fatalf("provision telegram: %v", err) } if first.ID == uuid.Nil { t.Fatal("expected a non-nil account id") } if first.PreferredLanguage != "en" { t.Errorf("PreferredLanguage = %q, want default en", first.PreferredLanguage) } if first.TimeZone != "UTC" { t.Errorf("TimeZone = %q, want default UTC", first.TimeZone) } // Re-provisioning the same identity returns the same account. again, err := store.ProvisionByIdentity(ctx, account.KindTelegram, tgExternal) if err != nil { t.Fatalf("re-provision telegram: %v", err) } if again.ID != first.ID { t.Errorf("re-provision id = %s, want %s", again.ID, first.ID) } // A different identity yields a different account. other, err := store.ProvisionByIdentity(ctx, account.KindTelegram, "tg-"+uuid.NewString()) if err != nil { t.Fatalf("provision other telegram: %v", err) } if other.ID == first.ID { t.Error("distinct identity must map to a distinct account") } // GetByID round-trips, and a random id reports ErrNotFound. got, err := store.GetByID(ctx, first.ID) if err != nil { t.Fatalf("get by id: %v", err) } if got.ID != first.ID { t.Errorf("get id = %s, want %s", got.ID, first.ID) } if _, err := store.GetByID(ctx, uuid.New()); !errors.Is(err, account.ErrNotFound) { t.Errorf("get missing = %v, want ErrNotFound", err) } // A platform identity is confirmed; an email identity starts unconfirmed. if c := identityConfirmed(t, account.KindTelegram, tgExternal); !c { t.Error("telegram identity must be confirmed") } emailExternal := "e-" + uuid.NewString() + "@example.com" if _, err := store.ProvisionByIdentity(ctx, account.KindEmail, emailExternal); err != nil { t.Fatalf("provision email: %v", err) } if c := identityConfirmed(t, account.KindEmail, emailExternal); c { t.Error("email identity must start unconfirmed") } } // identityConfirmed reads the confirmed flag for one identity directly. func identityConfirmed(t *testing.T, kind, externalID string) bool { t.Helper() var confirmed bool err := testDB.QueryRowContext(context.Background(), "SELECT confirmed FROM identities WHERE kind = $1 AND external_id = $2", kind, externalID, ).Scan(&confirmed) if err != nil { t.Fatalf("read confirmed for (%s, %s): %v", kind, externalID, err) } return confirmed }