fix(ts-tests): stop integration runs from deleting each other's data

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.
This commit is contained in:
kartik-mem0
2026-08-12 19:47:08 +05:30
parent d64d7b525b
commit 227c02da9f
3 changed files with 2 additions and 32 deletions
-2
View File
@@ -2,8 +2,6 @@
module.exports = {
...require("./jest.config"),
testMatch: ["**/integration/**/*.test.ts"],
globalSetup: "<rootDir>/src/client/tests/integration/global-setup.ts",
globalTeardown: "<rootDir>/src/client/tests/integration/global-teardown.ts",
// Run integration tests serially to avoid rate limiting and race conditions
maxWorkers: 1,
};
@@ -220,32 +220,3 @@ export async function cleanupTestUser(
// ignore
}
}
/**
* Full project wipe — deletes all memories and all entities.
* Equivalent to Python SDK's:
* client.delete_all(user_id="*", agent_id="*", app_id="*", run_id="*")
*
* Used as cleanup before and after integration test runs so tests
* start from a clean slate and don't leave data behind.
*/
export async function fullProjectCleanup(client: MemoryClient): Promise<void> {
// Delete all memories — all four filters set explicitly
try {
await client.deleteAll({
userId: "*",
agentId: "*",
appId: "*",
runId: "*",
});
} catch {
// ignore — may 404 if no data exists
}
// Delete all entities (users, agents, apps, runs)
try {
await client.deleteUsers();
} catch {
// ignore — may throw "No entities to delete"
}
}
@@ -100,6 +100,7 @@ describeIntegration("MemoryClient Integration — Users & Project", () => {
const hookName = `test-hook-${randomUUID().slice(0, 8)}`;
const hookUrl = `https://example.com/webhook/${randomUUID().slice(0, 8)}`;
const updatedName = `updated-hook-${randomUUID().slice(0, 8)}`;
const updatedUrl = `https://example.com/updated/${randomUUID().slice(0, 8)}`;
afterAll(async () => {
if (createdWebhookId) {
@@ -168,7 +169,7 @@ describeIntegration("MemoryClient Integration — Users & Project", () => {
client.updateWebhook({
webhookId: createdWebhookId,
name: updatedName,
url: "https://example.com/updated",
url: updatedUrl,
eventTypes: [WebhookEvent.MEMORY_DELETED],
}),
);