mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
fix tests
This commit is contained in:
parent
8cdd10785c
commit
871fe12f34
@ -11,6 +11,14 @@ import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env";
|
||||
import { captureError, StatusError } from "@stackframe/stack-shared/dist/utils/errors";
|
||||
import { wait } from "@stackframe/stack-shared/dist/utils/promises";
|
||||
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
function assertUuid(value: unknown, label: string): asserts value is string {
|
||||
if (typeof value !== "string" || value.trim().length === 0 || !UUID_REGEX.test(value)) {
|
||||
throw new StatusError(500, `${label} must be a valid UUID. Received: ${JSON.stringify(value)}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Assigns sequence IDs to rows that need them and queues sync requests for affected tenants.
|
||||
// Processes up to 1000 rows at a time from each table.
|
||||
async function backfillSequenceIds() {
|
||||
@ -37,6 +45,7 @@ async function backfillSequenceIds() {
|
||||
|
||||
// Enqueue sync for each affected tenant
|
||||
for (const { tenancyId } of projectUserTenants) {
|
||||
assertUuid(tenancyId, "projectUserTenants.tenancyId");
|
||||
await enqueueTenantSync(tenancyId);
|
||||
}
|
||||
|
||||
@ -63,6 +72,7 @@ async function backfillSequenceIds() {
|
||||
`;
|
||||
|
||||
for (const { tenancyId } of contactChannelTenants) {
|
||||
assertUuid(tenancyId, "contactChannelTenants.tenancyId");
|
||||
await enqueueTenantSync(tenancyId);
|
||||
}
|
||||
|
||||
@ -87,6 +97,7 @@ async function backfillSequenceIds() {
|
||||
`;
|
||||
|
||||
for (const { tenancyId } of deletedRowTenants) {
|
||||
assertUuid(tenancyId, "deletedRowTenants.tenancyId");
|
||||
await enqueueTenantSync(tenancyId);
|
||||
}
|
||||
}
|
||||
@ -94,6 +105,7 @@ async function backfillSequenceIds() {
|
||||
// Queues a sync request for a specific tenant if one isn't already pending.
|
||||
// Prevents duplicate sync requests by checking for unfulfilled requests.
|
||||
async function enqueueTenantSync(tenancyId: string) {
|
||||
assertUuid(tenancyId, "tenancyId");
|
||||
await globalPrismaClient.$executeRaw`
|
||||
INSERT INTO "OutgoingRequest" ("id", "createdAt", "qstashOptions", "startedFulfillingAt")
|
||||
SELECT
|
||||
@ -101,7 +113,7 @@ async function enqueueTenantSync(tenancyId: string) {
|
||||
NOW(),
|
||||
json_build_object(
|
||||
'url', '/api/latest/internal/external-db-sync/sync-engine',
|
||||
'body', json_build_object('tenancyId', ${tenancyId})
|
||||
'body', json_build_object('tenancyId', ${tenancyId}::uuid)
|
||||
),
|
||||
NULL
|
||||
WHERE NOT EXISTS (
|
||||
@ -173,4 +185,3 @@ export const GET = createSmartRouteHandler({
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -6,6 +6,62 @@ import { captureError, StackAssertionError, throwErr } from "@stackframe/stack-s
|
||||
import { omit } from "@stackframe/stack-shared/dist/utils/objects";
|
||||
import { Client } from 'pg';
|
||||
|
||||
const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
function assertNonEmptyString(value: unknown, label: string): asserts value is string {
|
||||
if (typeof value !== "string" || value.trim().length === 0) {
|
||||
throw new StackAssertionError(`${label} must be a non-empty string.`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertUuid(value: unknown, label: string): asserts value is string {
|
||||
assertNonEmptyString(value, label);
|
||||
if (!UUID_REGEX.test(value)) {
|
||||
throw new StackAssertionError(`${label} must be a valid UUID. Received: ${JSON.stringify(value)}`);
|
||||
}
|
||||
}
|
||||
|
||||
type PgErrorLike = {
|
||||
code?: string;
|
||||
constraint?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
function isDuplicateTypeError(error: unknown): error is PgErrorLike {
|
||||
if (!error || typeof error !== "object") return false;
|
||||
const pgError = error as PgErrorLike;
|
||||
return pgError.code === "23505" && pgError.constraint === "pg_type_typname_nsp_index";
|
||||
}
|
||||
|
||||
async function ensureExternalSchema(
|
||||
externalClient: Client,
|
||||
tableSchemaSql: string,
|
||||
tableName: string,
|
||||
) {
|
||||
try {
|
||||
await externalClient.query(tableSchemaSql);
|
||||
} catch (error) {
|
||||
if (!isDuplicateTypeError(error)) throw error;
|
||||
|
||||
// Concurrent CREATE TABLE can race and hit a duplicate type error.
|
||||
// If the table now exists, we can safely continue.
|
||||
const existsResult = await externalClient.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = $1
|
||||
);
|
||||
`, [tableName]);
|
||||
if (existsResult.rows[0]?.exists === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new StackAssertionError(
|
||||
`Duplicate type error while creating table ${JSON.stringify(tableName)}, but table does not exist.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function pushRowsToExternalDb(
|
||||
externalClient: Client,
|
||||
tableName: string,
|
||||
@ -14,6 +70,12 @@ async function pushRowsToExternalDb(
|
||||
expectedTenancyId: string,
|
||||
mappingId: string,
|
||||
) {
|
||||
assertNonEmptyString(tableName, "tableName");
|
||||
assertNonEmptyString(mappingId, "mappingId");
|
||||
assertUuid(expectedTenancyId, "expectedTenancyId");
|
||||
if (!Array.isArray(newRows)) {
|
||||
throw new StackAssertionError(`newRows must be an array for table ${JSON.stringify(tableName)}.`);
|
||||
}
|
||||
if (newRows.length === 0) return;
|
||||
// Just for our own sanity, make sure that we have the right number of positional parameters
|
||||
// The last parameter is mapping_name for metadata tracking
|
||||
@ -73,12 +135,22 @@ async function syncMapping(
|
||||
tenancyId: string,
|
||||
dbType: 'postgres',
|
||||
) {
|
||||
assertNonEmptyString(mappingId, "mappingId");
|
||||
assertNonEmptyString(mapping.targetTable, "mapping.targetTable");
|
||||
assertUuid(tenancyId, "tenancyId");
|
||||
const fetchQuery = mapping.internalDbFetchQuery;
|
||||
const updateQuery = mapping.externalDbUpdateQueries[dbType];
|
||||
const tableName = mapping.targetTable;
|
||||
assertNonEmptyString(fetchQuery, "internalDbFetchQuery");
|
||||
assertNonEmptyString(updateQuery, "externalDbUpdateQueries");
|
||||
if (!fetchQuery.includes("$1") || !fetchQuery.includes("$2")) {
|
||||
throw new StackAssertionError(
|
||||
`internalDbFetchQuery must reference $1 (tenancyId) and $2 (lastSequenceId). Mapping: ${mappingId}`
|
||||
);
|
||||
}
|
||||
|
||||
const tableSchema = mapping.targetTableSchemas[dbType];
|
||||
await externalClient.query(tableSchema);
|
||||
await ensureExternalSchema(externalClient, tableSchema, tableName);
|
||||
|
||||
let lastSequenceId = -1;
|
||||
const metadataResult = await externalClient.query(
|
||||
@ -88,10 +160,19 @@ async function syncMapping(
|
||||
if (metadataResult.rows.length > 0) {
|
||||
lastSequenceId = Number(metadataResult.rows[0].last_synced_sequence_id);
|
||||
}
|
||||
if (!Number.isFinite(lastSequenceId)) {
|
||||
throw new StackAssertionError(
|
||||
`Invalid last_synced_sequence_id for mapping ${mappingId}: ${JSON.stringify(metadataResult.rows[0]?.last_synced_sequence_id)}`
|
||||
);
|
||||
}
|
||||
|
||||
const BATCH_LIMIT = 1000;
|
||||
|
||||
while (true) {
|
||||
assertUuid(tenancyId, "tenancyId");
|
||||
if (!Number.isFinite(lastSequenceId)) {
|
||||
throw new StackAssertionError(`lastSequenceId must be a finite number for mapping ${mappingId}.`);
|
||||
}
|
||||
const rows = await internalPrisma.$queryRawUnsafe<any[]>(fetchQuery, tenancyId, lastSequenceId);
|
||||
|
||||
if (rows.length === 0) {
|
||||
@ -132,6 +213,8 @@ async function syncDatabase(
|
||||
internalPrisma: PrismaClientTransaction,
|
||||
tenancyId: string,
|
||||
) {
|
||||
assertNonEmptyString(dbId, "dbId");
|
||||
assertUuid(tenancyId, "tenancyId");
|
||||
if (dbConfig.type !== 'postgres') {
|
||||
throw new StackAssertionError(
|
||||
`Unsupported database type '${dbConfig.type}' for external DB ${dbId}. Only 'postgres' is currently supported.`
|
||||
@ -143,6 +226,7 @@ async function syncDatabase(
|
||||
`Invalid configuration for external DB ${dbId}: 'connectionString' is missing.`
|
||||
);
|
||||
}
|
||||
assertNonEmptyString(dbConfig.connectionString, `external DB ${dbId} connectionString`);
|
||||
|
||||
const externalClient = new Client({
|
||||
connectionString: dbConfig.connectionString,
|
||||
@ -176,6 +260,7 @@ async function syncDatabase(
|
||||
|
||||
|
||||
export async function syncExternalDatabases(tenancy: Tenancy) {
|
||||
assertUuid(tenancy?.id, "tenancy.id");
|
||||
const externalDatabases = tenancy.config.dbSync.externalDatabases;
|
||||
const internalPrisma = await getPrismaClientForTenancy(tenancy);
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const userA = await User.create({ emailAddress: 'user-a@example.com' });
|
||||
const userA = await User.create({ primary_email: 'user-a@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${userA.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -79,7 +79,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const userB = await User.create({ emailAddress: 'user-b@example.com' });
|
||||
const userB = await User.create({ primary_email: 'user-b@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${userB.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -178,9 +178,9 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user1 = await User.create({ emailAddress: 'seq1@example.com' });
|
||||
const user2 = await User.create({ emailAddress: 'seq2@example.com' });
|
||||
const user3 = await User.create({ emailAddress: 'seq3@example.com' });
|
||||
const user1 = await User.create({ primary_email: 'seq1@example.com' });
|
||||
const user2 = await User.create({ primary_email: 'seq2@example.com' });
|
||||
const user3 = await User.create({ primary_email: 'seq3@example.com' });
|
||||
|
||||
await niceBackendFetch(`/api/v1/users/${user1.userId}`, {
|
||||
accessType: 'admin',
|
||||
@ -219,7 +219,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
const seq1 = Number(metadata1.rows[0].last_synced_sequence_id);
|
||||
expect(seq1).toBeGreaterThan(0);
|
||||
|
||||
const user4 = await User.create({ emailAddress: 'seq4@example.com' });
|
||||
const user4 = await User.create({ primary_email: 'seq4@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user4.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -260,7 +260,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const user1 = await User.create({ emailAddress: 'user1@example.com' });
|
||||
const user1 = await User.create({ primary_email: 'user1@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user1.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -276,7 +276,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
expect(res.rows[0].display_name).toBe('User 1');
|
||||
const user1Id = res.rows[0].id;
|
||||
|
||||
const user2 = await User.create({ emailAddress: 'user2@example.com' });
|
||||
const user2 = await User.create({ primary_email: 'user2@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user2.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -316,7 +316,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
});
|
||||
|
||||
const specialName = "O'Connor 🚀 用户 \"Test\"";
|
||||
const user = await User.create({ emailAddress: 'special@example.com' });
|
||||
const user = await User.create({ primary_email: 'special@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -456,9 +456,9 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const user1 = await User.create({ emailAddress: 'seq1@example.com' });
|
||||
const user2 = await User.create({ emailAddress: 'seq2@example.com' });
|
||||
const user3 = await User.create({ emailAddress: 'seq3@example.com' });
|
||||
const user1 = await User.create({ primary_email: 'seq1@example.com' });
|
||||
const user2 = await User.create({ primary_email: 'seq2@example.com' });
|
||||
const user3 = await User.create({ primary_email: 'seq3@example.com' });
|
||||
|
||||
await niceBackendFetch(`/api/v1/users/${user1.userId}`, {
|
||||
accessType: 'admin',
|
||||
@ -505,7 +505,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
const user4 = await User.create({ emailAddress: 'seq4@example.com' });
|
||||
const user4 = await User.create({ primary_email: 'seq4@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user4.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -568,7 +568,7 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
|
||||
|
||||
const superClient = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'write-protect@example.com' });
|
||||
const user = await User.create({ primary_email: 'write-protect@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -645,7 +645,7 @@ $$;`);
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'multi-update@example.com' });
|
||||
const user = await User.create({ primary_email: 'multi-update@example.com' });
|
||||
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
@ -695,7 +695,7 @@ $$;`);
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'delete-before-sync@example.com' });
|
||||
const user = await User.create({ primary_email: 'delete-before-sync@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -748,7 +748,7 @@ $$;`);
|
||||
const client = dbManager.getClient(dbName);
|
||||
const email = 'recreate-after-delete@example.com';
|
||||
|
||||
const firstUser = await User.create({ emailAddress: email });
|
||||
const firstUser = await User.create({ primary_email: email });
|
||||
await niceBackendFetch(`/api/v1/users/${firstUser.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -772,7 +772,7 @@ $$;`);
|
||||
await waitForSyncedDeletion(client, email);
|
||||
await verifyNotInExternalDb(client, email);
|
||||
|
||||
const secondUser = await User.create({ emailAddress: email });
|
||||
const secondUser = await User.create({ primary_email: email });
|
||||
await niceBackendFetch(`/api/v1/users/${secondUser.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -825,7 +825,7 @@ $$;`);
|
||||
const client = dbManager.getClient(dbName);
|
||||
const email = 'lifecycle-test@example.com';
|
||||
|
||||
const user1 = await User.create({ emailAddress: email });
|
||||
const user1 = await User.create({ primary_email: email });
|
||||
await niceBackendFetch(`/api/v1/users/${user1.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -875,7 +875,7 @@ $$;`);
|
||||
res = await client.query(`SELECT * FROM "users" WHERE "primary_email" = $1`, [email]);
|
||||
expect(res.rows.length).toBe(0);
|
||||
|
||||
const user2 = await User.create({ emailAddress: email });
|
||||
const user2 = await User.create({ primary_email: email });
|
||||
await niceBackendFetch(`/api/v1/users/${user2.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
|
||||
@ -47,7 +47,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'insert-only@example.com' });
|
||||
const user = await User.create({ primary_email: 'insert-only@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -80,7 +80,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'update-only@example.com' });
|
||||
const user = await User.create({ primary_email: 'update-only@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -126,7 +126,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'delete-only@example.com' });
|
||||
const user = await User.create({ primary_email: 'delete-only@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -184,7 +184,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
description: 'Testing that data only appears after sync is triggered'
|
||||
});
|
||||
|
||||
const user = await User.create({ emailAddress: 'sync-verify@example.com' });
|
||||
const user = await User.create({ primary_email: 'sync-verify@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -225,7 +225,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'crud-test@example.com' });
|
||||
const user = await User.create({ primary_email: 'crud-test@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -274,7 +274,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const user = await User.create({ emailAddress: 'auto-create@example.com' });
|
||||
const user = await User.create({ primary_email: 'auto-create@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -320,7 +320,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
const user = await User.create({ emailAddress: 'resilience@example.com' });
|
||||
const user = await User.create({ primary_email: 'resilience@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -357,7 +357,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'primary@example.com' });
|
||||
const user = await User.create({ primary_email: 'primary@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
@ -410,7 +410,7 @@ describe.sequential('External DB Sync - Basic Tests', () => {
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
|
||||
const user = await User.create({ emailAddress: 'update-test@example.com' });
|
||||
const user = await User.create({ primary_email: 'update-test@example.com' });
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
method: 'PATCH',
|
||||
|
||||
@ -49,7 +49,7 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
|
||||
});
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
const user = await User.create({ emailAddress: 'parallel-sync@example.com' });
|
||||
const user = await User.create({ primary_email: 'parallel-sync@example.com' });
|
||||
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
@ -97,7 +97,7 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
|
||||
});
|
||||
|
||||
const client = dbManager.getClient(dbName);
|
||||
const user = await User.create({ emailAddress: 'update-delete@example.com' });
|
||||
const user = await User.create({ primary_email: 'update-delete@example.com' });
|
||||
|
||||
await niceBackendFetch(`/api/v1/users/${user.userId}`, {
|
||||
accessType: 'admin',
|
||||
@ -284,7 +284,7 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
|
||||
});
|
||||
|
||||
const externalClient = dbManager.getClient(dbName);
|
||||
const user = await User.create({ emailAddress: `${dbName}@example.com` });
|
||||
const user = await User.create({ primary_email: `${dbName}@example.com` });
|
||||
|
||||
// Make sure the users row exists
|
||||
await waitForTable(externalClient, 'users');
|
||||
@ -570,8 +570,8 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
|
||||
|
||||
const externalClient = dbManager.getClient(dbName);
|
||||
|
||||
const user1 = await User.create({ emailAddress: 'row1@example.com' });
|
||||
const user2 = await User.create({ emailAddress: 'row2@example.com' });
|
||||
const user1 = await User.create({ primary_email: 'row1@example.com' });
|
||||
const user2 = await User.create({ primary_email: 'row2@example.com' });
|
||||
|
||||
await waitForTable(externalClient, 'users');
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user