chore: fixing the ci integration test and token management for integration

This commit is contained in:
kartik-mem0
2026-03-19 11:00:22 +05:30
parent 2131da5101
commit a14bc1ff24
2 changed files with 70 additions and 20 deletions
+56 -12
View File
@@ -3,9 +3,13 @@
*
* Provides environment gating, client factory, polling helpers,
* and console suppression for telemetry noise.
*
* API credit budget: these helpers are designed to minimize API calls.
* Each CI run should use ~40 calls total across all test files.
*/
import { MemoryClient } from "../../mem0";
import type { Memory } from "../../mem0.types";
import { NetworkError, RateLimitError } from "../../../common/exceptions";
// ─── Environment gate ────────────────────────────────────
export const API_KEY = process.env.MEM0_API_KEY;
@@ -15,9 +19,35 @@ export const describeIntegration = API_KEY ? describe : describe.skip;
* Create a MemoryClient with the real API key.
* Call this inside beforeAll — not at module scope — so it only
* runs when the suite is not skipped.
*
* The returned client retries transient errors (502, 503, 504, 429)
* with backoff so CI runs are not flaky.
*/
export function createTestClient(): MemoryClient {
return new MemoryClient({ apiKey: API_KEY! });
const client = new MemoryClient({ apiKey: API_KEY! });
const originalFetch = (client as any)._fetchWithErrorHandling.bind(client);
(client as any)._fetchWithErrorHandling = async (
url: string,
options: any,
) => {
const MAX_RETRIES = 2;
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
try {
return await originalFetch(url, options);
} catch (error: any) {
const isTransient =
error instanceof NetworkError || error instanceof RateLimitError;
if (isTransient && attempt < MAX_RETRIES) {
await new Promise((r) => setTimeout(r, 3_000 * attempt));
continue;
}
throw error;
}
}
};
return client;
}
/**
@@ -42,6 +72,27 @@ export async function waitForMemories(
return await client.getAll({ user_id: userId });
}
/**
* Poll search until results appear. Only used by search tests —
* other test files should NOT call this to avoid wasting API credits.
*/
export async function waitForSearchResults(
client: MemoryClient,
query: string,
options: Record<string, any>,
maxWaitMs = 30_000,
): Promise<Memory[]> {
const start = Date.now();
while (Date.now() - start < maxWaitMs) {
const results = await client.search(query, options);
if (Array.isArray(results) && results.length > 0) {
return results;
}
await new Promise((r) => setTimeout(r, 3_000));
}
return await client.search(query, options);
}
/**
* Suppress telemetry console noise during tests.
* Returns a cleanup function to call in afterAll.
@@ -69,7 +120,10 @@ export function suppressTelemetryNoise(): () => void {
/**
* Add test memories and wait for them to be processed.
* Returns the memory IDs once available.
* Returns the memory IDs once available via getAll.
*
* NOTE: This only waits for the listing index. If your test needs
* search results, call waitForSearchResults() separately.
*/
export async function seedTestMemories(
client: MemoryClient,
@@ -104,17 +158,7 @@ export async function seedTestMemories(
{ user_id: userId },
);
// Wait for async processing (listing index)
const memories = await waitForMemories(client, userId, 1);
// Also wait for search index — it can lag behind getAll under load (e.g. CI)
const start = Date.now();
while (Date.now() - start < 60_000) {
const results = await client.search("favorite color", { user_id: userId });
if (Array.isArray(results) && results.length > 0) break;
await new Promise((r) => setTimeout(r, 3_000));
}
return memories.map((m) => m.id);
}
@@ -13,6 +13,7 @@ import {
suppressTelemetryNoise,
seedTestMemories,
cleanupTestUser,
waitForSearchResults,
} from "./helpers";
jest.setTimeout(120_000);
@@ -38,9 +39,12 @@ describeIntegration("MemoryClient Integration — Search & History", () => {
// ─── Search v1 ────────────────────────────────────────────
describe("search v1", () => {
test("searches memories by user_id and returns results with scores", async () => {
const results = await client.search("What is my favorite color?", {
user_id: TEST_USER_ID,
});
// Search index may lag behind listing index — poll until ready
const results = await waitForSearchResults(
client,
"What is my favorite color?",
{ user_id: TEST_USER_ID },
);
expect(Array.isArray(results)).toBe(true);
expect(results.length).toBeGreaterThan(0);
@@ -56,12 +60,14 @@ describeIntegration("MemoryClient Integration — Search & History", () => {
// ─── Search v2 ────────────────────────────────────────────
describe("search v2", () => {
test("searches with OR filters and returns results", async () => {
const results = await client.search("What do you know about me?", {
filters: {
OR: [{ user_id: TEST_USER_ID }],
const results = await waitForSearchResults(
client,
"What do you know about me?",
{
filters: { OR: [{ user_id: TEST_USER_ID }] },
api_version: "v2",
},
api_version: "v2",
});
);
expect(Array.isArray(results)).toBe(true);
expect(results.length).toBeGreaterThan(0);