| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- //go:build integration
- package repository
- import (
- "context"
- "testing"
- "github.com/Wei-Shaw/sub2api/internal/service"
- dbmigrations "github.com/Wei-Shaw/sub2api/migrations"
- "github.com/google/uuid"
- "github.com/lib/pq"
- "github.com/stretchr/testify/require"
- )
- func requireCanonicalUUIDString(t *testing.T, value string) {
- t.Helper()
- parsed, err := uuid.Parse(value)
- require.NoError(t, err)
- require.NotEqual(t, uuid.Nil, parsed)
- require.Equal(t, parsed.String(), value)
- }
- func TestMigration225BackfillsOnlyEnabledOpenAIOAuthMissingOrMalformedSeeds(t *testing.T) {
- tx := testTx(t)
- ctx := context.Background()
- migrationSQL, err := dbmigrations.FS.ReadFile("225_backfill_codex_fingerprint_seed.sql")
- require.NoError(t, err)
- var missingID, blankID, malformedID, validID, offID, apiKeyID int64
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-missing', 'openai', 'oauth', '{"codex_fingerprint_mode":"session"}'::jsonb)
- RETURNING id
- `).Scan(&missingID))
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-blank', 'openai', 'oauth', '{"codex_fingerprint_mode":"device","codex_fingerprint_seed":""}'::jsonb)
- RETURNING id
- `).Scan(&blankID))
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-malformed', 'openai', 'oauth', '{"codex_fingerprint_mode":"full","codex_fingerprint_seed":"BAD"}'::jsonb)
- RETURNING id
- `).Scan(&malformedID))
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-valid', 'openai', 'oauth', '{"codex_fingerprint_mode":"session","codex_fingerprint_seed":"11111111-1111-4111-8111-111111111111"}'::jsonb)
- RETURNING id
- `).Scan(&validID))
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-off', 'openai', 'oauth', '{"codex_fingerprint_mode":"off"}'::jsonb)
- RETURNING id
- `).Scan(&offID))
- require.NoError(t, tx.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ('migration-225-apikey', 'openai', 'apikey', '{"codex_fingerprint_mode":"session"}'::jsonb)
- RETURNING id
- `).Scan(&apiKeyID))
- _, err = tx.ExecContext(ctx, string(migrationSQL))
- require.NoError(t, err)
- seedsAfterFirst := map[int64]string{}
- for _, id := range []int64{missingID, blankID, malformedID, validID} {
- var seed string
- require.NoError(t, tx.QueryRowContext(ctx, `SELECT extra->>'codex_fingerprint_seed' FROM accounts WHERE id = $1`, id).Scan(&seed))
- requireCanonicalUUIDString(t, seed)
- seedsAfterFirst[id] = seed
- }
- require.Equal(t, "11111111-1111-4111-8111-111111111111", seedsAfterFirst[validID])
- for _, id := range []int64{offID, apiKeyID} {
- var hasSeed bool
- require.NoError(t, tx.QueryRowContext(ctx, `SELECT extra ? 'codex_fingerprint_seed' FROM accounts WHERE id = $1`, id).Scan(&hasSeed))
- require.False(t, hasSeed)
- }
- _, err = tx.ExecContext(ctx, string(migrationSQL))
- require.NoError(t, err)
- for id, want := range seedsAfterFirst {
- var got string
- require.NoError(t, tx.QueryRowContext(ctx, `SELECT extra->>'codex_fingerprint_seed' FROM accounts WHERE id = $1`, id).Scan(&got))
- require.Equal(t, want, got)
- }
- }
- func TestBulkUpdateGeneratesDistinctStableCodexFingerprintSeedsPerEligibleRow(t *testing.T) {
- ctx := context.Background()
- testName := "bulk-codex-seed-" + uuid.NewString()
- type fixture struct {
- name string
- accountType string
- extra string
- }
- fixtures := []fixture{
- {name: testName + "-missing-a", accountType: service.AccountTypeOAuth, extra: `{}`},
- {name: testName + "-missing-b", accountType: service.AccountTypeOAuth, extra: `{"codex_fingerprint_seed":"BAD"}`},
- {name: testName + "-valid", accountType: service.AccountTypeOAuth, extra: `{"codex_fingerprint_seed":"11111111-1111-4111-8111-111111111111"}`},
- {name: testName + "-apikey", accountType: service.AccountTypeAPIKey, extra: `{}`},
- }
- ids := make([]int64, 0, len(fixtures))
- for _, f := range fixtures {
- var id int64
- require.NoError(t, integrationDB.QueryRowContext(ctx, `
- INSERT INTO accounts (name, platform, type, extra)
- VALUES ($1, 'openai', $2, $3::jsonb)
- RETURNING id
- `, f.name, f.accountType, f.extra).Scan(&id))
- ids = append(ids, id)
- }
- t.Cleanup(func() {
- _, _ = integrationDB.ExecContext(context.Background(), `DELETE FROM scheduler_outbox WHERE account_id = ANY($1)`, pq.Array(ids))
- _, _ = integrationDB.ExecContext(context.Background(), `DELETE FROM accounts WHERE id = ANY($1)`, pq.Array(ids))
- })
- repo := newAccountRepositoryWithSQL(testEntClient(t), integrationDB, nil)
- updates := service.AccountBulkUpdate{
- Extra: map[string]any{
- "codex_fingerprint_mode": "session",
- },
- EnsureCodexFingerprintSeed: true,
- }
- rows, err := repo.BulkUpdate(ctx, ids, updates)
- require.NoError(t, err)
- require.Equal(t, int64(len(ids)), rows)
- readSeed := func(id int64) string {
- t.Helper()
- var seed string
- require.NoError(t, integrationDB.QueryRowContext(ctx, `SELECT COALESCE(extra->>'codex_fingerprint_seed', '') FROM accounts WHERE id = $1`, id).Scan(&seed))
- return seed
- }
- firstSeeds := []string{readSeed(ids[0]), readSeed(ids[1]), readSeed(ids[2]), readSeed(ids[3])}
- requireCanonicalUUIDString(t, firstSeeds[0])
- requireCanonicalUUIDString(t, firstSeeds[1])
- require.NotEqual(t, firstSeeds[0], firstSeeds[1], "gen_random_uuid must be evaluated per eligible row")
- require.Equal(t, "11111111-1111-4111-8111-111111111111", firstSeeds[2])
- require.Empty(t, firstSeeds[3], "API-key accounts must not receive a Codex fingerprint seed")
- rows, err = repo.BulkUpdate(ctx, ids, updates)
- require.NoError(t, err)
- require.Equal(t, int64(len(ids)), rows)
- for i, want := range firstSeeds {
- require.Equal(t, want, readSeed(ids[i]), "retry must not rotate an existing valid seed")
- }
- }
|