The integration suite claimed exclusive ownership of a shared project. Its
globalSetup and globalTeardown each ran a project-wide wipe:
deleteAll({userId: '*', agentId: '*', appId: '*', runId: '*'})
deleteUsers()
CI runs this suite concurrently across PRs against one MEM0_API_KEY, so each
job's wipe deleted the memories its neighbours had just seeded. maxWorkers: 1
and max-parallel: 1 only serialize within a run, not across them.
Evidence from three jobs that overlapped on 2026-08-12:
6903 crud seeded 13:53:24-13:54:15, hit by 6928's wipe (13:53:20-30) FAIL
6928 crud seeded 13:53:30-13:54:19, hit by 6902's wipe (13:53:31-43) FAIL
6902 crud seeded 13:53:43-13:54:21, no overlapping wipe PASS
6902 batch ran 13:55:31-13:56:20, hit by 6928's teardown (13:55:59) FAIL
Every failure surfaced as waitForMemories timing out with zero memories, which
reads as pipeline latency but was deletion: probing the live API shows a seeded
user settling in 17s, well inside the 45s budget.
- drop globalSetup/globalTeardown; every suite already cleans up its own
UUID-scoped user in afterAll
- remove the fullProjectCleanup helper so the wipe cannot come back
- give updateWebhook a per-run URL; the project enforces uniqueness on
(project, url), so concurrent runs collided on the hardcoded constant
Verified: two suites run concurrently against the same key go from 3 failures
to 1. The remainder is updateProject() mutating project-level
custom_instructions, a singleton two runs cannot both own.
8 lines
249 B
JavaScript
8 lines
249 B
JavaScript
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
|
module.exports = {
|
|
...require("./jest.config"),
|
|
testMatch: ["**/integration/**/*.test.ts"],
|
|
// Run integration tests serially to avoid rate limiting and race conditions
|
|
maxWorkers: 1,
|
|
};
|