Skip to content

Commit 005cb97

Browse files
authored
fix(tests): close three integration-test races that flaked CI (#9964)
* fix(tests): wait for the job lane's first leg text to persist before killing its process The takeover test aborted the turn as soon as the fake worker had written the first leg, before the dying process had recorded that text in its stream buffer. The re-attach then carried receivedTextChars 0 and the occurrence's summary lost the first leg. Wait for the text event in the buffer first, as the unattended-turn suite already does. * fix(tests): handle the cancelled token-sealing run's rejection before polling for its backend The operator-cancel test started migrate() and only attached a handler after its pg_cancel_backend polling loop. When the cancellation reached the run's connection before the loop broke, Node saw an unhandled rejection and Vitest failed the whole db shard even though every test passed. Attach the rejection assertion when the run starts and await it after the loop. * fix(tests): handle the refused provider expansion before awaiting the concurrent grant The concurrent-grant test started ensureWorkspaceAccountsGroup and awaited the grant transaction before attaching a handler to the refusal. When the refusal resolved first, Node reported an unhandled rejection and Vitest failed the shard although the test passed. Attach the rejection assertion when the call starts and await it after the grant commits. * chore(ci): log lock waits and slow statements in the integration Postgres
1 parent 55bacfc commit 005cb97

4 files changed

Lines changed: 25 additions & 8 deletions

File tree

‎.github/workflows/checks.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ jobs:
149149
working-directory: packages/db
150150
run: |
151151
bun -e 'import postgres from "postgres"; const sql = postgres(process.env.DATABASE_URL); for (const extension of ["vector", "btree_gin", "pg_trgm"]) await sql`CREATE EXTENSION IF NOT EXISTS ${sql(extension)}`; await sql.end()'
152+
# A test that hangs on a lock leaves only its timeout behind; these name the waiter, the
153+
# lock, and the blocking statement in the Postgres log. Service containers take no -c flags,
154+
# and ALTER SYSTEM runs outside a transaction, so each setting is its own statement.
155+
bun -e 'import postgres from "postgres"; const sql = postgres(process.env.DATABASE_URL); for (const setting of ["log_lock_waits = on", "deadlock_timeout = 1000", "log_min_duration_statement = 20000"]) await sql.unsafe(`ALTER SYSTEM SET ${setting}`); await sql`SELECT pg_reload_conf()`; await sql.end()'
152156
bun run db:${{ matrix.provision }}
153157
154158
- name: Verify migration replay is a no-op

‎apps/sim/lib/knowledge/__integration__/search-source-setup.integration.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,14 +492,17 @@ describe('Search source identity and concurrent creation', () => {
492492
.where(eq(resourcePolicy.resourceId, searchGroupId))
493493
})
494494
await locked
495-
const append = ensureWorkspaceAccountsGroup(ids.workspaceId, ids.aliceId, {
496-
provider: 'jira',
497-
label: 'Jira',
498-
required: false,
499-
})
495+
/** Handled from the start: the refusal can land before the grant's commit resolves here. */
496+
const refused = expect(
497+
ensureWorkspaceAccountsGroup(ids.workspaceId, ids.aliceId, {
498+
provider: 'jira',
499+
label: 'Jira',
500+
required: false,
501+
})
502+
).rejects.toThrow('has workflow access')
500503
releaseGrant()
501504
await grant
502-
await expect(append).rejects.toThrow('has workflow access')
505+
await refused
503506
const existing = await ensureWorkspaceAccountsGroup(ids.workspaceId, ids.aliceId, {
504507
provider: 'google-drive',
505508
label: 'Google Drive',

‎apps/sim/lib/mothership/jobs/lane.integration.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ import { jobOccurrenceId, MIN_JOB_CADENCE_MS } from '@/lib/mothership/jobs/occur
165165
import { JOB_DISPATCH_GRACE_MS, reconcileJobRuns } from '@/lib/mothership/jobs/reconcile'
166166
import { takeOverAbandonedRuns } from '@/lib/mothership/request/application/abandoned-runs'
167167
import { startUnattendedTurn } from '@/lib/mothership/request/lifecycle/unattended'
168+
import { readEvents } from '@/lib/mothership/request/session/buffer'
168169
import {
169170
chatStreamLockKey,
170171
StreamControllerSupersededError,
@@ -506,6 +507,14 @@ describe.runIf(Boolean(redisUrl))('the scheduled job lane', () => {
506507
])
507508
await runJobLane(new Date())
508509
await waitFor(async () => worker.open.has(occurrenceId), 'the first leg')
510+
/** The worker has written the text, but the process must persist it before it dies. */
511+
await waitFor(
512+
async () =>
513+
(await readEvents(occurrenceId, '0')).some(
514+
(event) => event.type === 'text' && event.payload.text === 'Started triage. '
515+
),
516+
'the first leg text to persist before the process dies'
517+
)
509518

510519
controllers.get(occurrenceId)?.abort(new StreamControllerSupersededError())
511520
worker.open.get(occurrenceId)?.response.socket?.destroy()

‎packages/db/script-migrations/0037_seal_account_tokens.integration.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,8 @@ describe('sealing stored account tokens in PostgreSQL', () => {
358358
await insertAccount('cancelled-access', 'cancelled-refresh')
359359
await onAccountUpdate('PERFORM pg_sleep(20)')
360360

361-
const run = migrate()
361+
/** Handled from the start: the cancel can fail the run before the polling loop sees it. */
362+
const failed = expect(migrate()).rejects.toThrow('canceling statement due to user request')
362363
for (let attempt = 0; attempt < 100; attempt++) {
363364
const [cancelled] = await admin<{ cancelled: boolean }[]>`
364365
SELECT pg_cancel_backend(pid) AS cancelled FROM pg_stat_activity
@@ -368,7 +369,7 @@ describe('sealing stored account tokens in PostgreSQL', () => {
368369
await sleep(50)
369370
}
370371

371-
await expect(run).rejects.toThrow('canceling statement due to user request')
372+
await failed
372373
expect(await isRecorded()).toBe(false)
373374
expect((await storedRows())[0].access_token).toBe('cancelled-access')
374375
}, 30_000)

0 commit comments

Comments
 (0)