Skip to content

Commit 248a229

Browse files
committed
chore: make tests less flaky
1 parent 0fd263a commit 248a229

File tree

2 files changed

+43
-26
lines changed

2 files changed

+43
-26
lines changed

tests/integration/tools/mongodb/mongodbHelpers.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { EJSON } from "bson";
1919
import { GenericContainer } from "testcontainers";
2020
import type { StartedTestContainer } from "testcontainers";
2121
import { ShellWaitStrategy } from "testcontainers/build/wait-strategies/shell-wait-strategy.js";
22+
import { execSync } from "node:child_process";
2223

2324
const __dirname = path.dirname(fileURLToPath(import.meta.url));
2425

@@ -71,7 +72,8 @@ export function describeWithMongoDB(
7172
downloadOptions: MongoClusterOptions["downloadOptions"] | MongoSearchConfiguration = { enterprise: false },
7273
serverArgs: string[] = []
7374
): void {
74-
describe(name, () => {
75+
describe(name, ({ skipIf }) => {
76+
skipIf(!isMongoDBEnvSupported(downloadOptions));
7577
const mdbIntegration = setupMongoDBIntegrationTest(downloadOptions, serverArgs);
7678
const integration = setupIntegrationTest(
7779
() => ({
@@ -110,6 +112,19 @@ function isTestContainersCluster(
110112
return !!(cluster as StartedTestContainer)?.stop;
111113
}
112114

115+
function isMongoDBEnvSupported(downloadOptions: MongoClusterOptions["downloadOptions"] | MongoSearchConfiguration) {
116+
if (isSearchOptions(downloadOptions)) {
117+
try {
118+
execSync("docker --version");
119+
return true;
120+
} catch {
121+
return false;
122+
}
123+
}
124+
125+
return true;
126+
}
127+
113128
export function setupMongoDBIntegrationTest(
114129
downloadOptions: MongoClusterOptions["downloadOptions"] | MongoSearchConfiguration,
115130
serverArgs: string[]

tests/integration/tools/mongodb/search/listSearchIndexes.test.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describeWithMongoDB, getSingleDocFromUntrustedContent } from "../mongodbHelpers.js";
2-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
2+
import { describe, it, expect, beforeEach, beforeAll, afterAll } from "vitest";
33
import {
44
getResponseContent,
55
databaseCollectionParameters,
@@ -11,6 +11,9 @@ import {
1111
import type { NodeDriverServiceProvider } from "@mongosh/service-provider-node-driver";
1212
import type { SearchIndexStatus } from "../../../../../src/tools/mongodb/search/listSearchIndexes.js";
1313

14+
const SEARCH_RETRIES = 10_000;
15+
const SEARCH_TIMEOUT = 20_000;
16+
1417
describeWithMongoDB("list search indexes tool in local MongoDB", (integration) => {
1518
validateToolMetadata(
1619
integration,
@@ -62,11 +65,7 @@ describeWithMongoDB(
6265
await provider.createSearchIndexes("any", "foo", [{ definition: { mappings: { dynamic: true } } }]);
6366
});
6467

65-
afterEach(async () => {
66-
await provider.dropCollection("any", "foo");
67-
});
68-
69-
it("returns the list of existing indexes", async () => {
68+
it("returns the list of existing indexes", { timeout: SEARCH_TIMEOUT }, async () => {
7069
const response = await integration.mcpClient().callTool({
7170
name: "list-search-indexes",
7271
arguments: { database: "any", collection: "foo" },
@@ -79,31 +78,34 @@ describeWithMongoDB(
7978
expect(indexDefinition?.latestDefinition).toEqual({ mappings: { dynamic: true, fields: {} } });
8079
});
8180

82-
it("returns the list of existing indexes and detects if they are queryable", async ({ signal }) => {
83-
await waitUntilIndexIsQueryable(provider, "any", "foo", "default", signal);
84-
85-
const response = await integration.mcpClient().callTool({
86-
name: "list-search-indexes",
87-
arguments: { database: "any", collection: "foo" },
88-
});
89-
90-
const content = getResponseContent(response.content);
91-
const indexDefinition = getSingleDocFromUntrustedContent<SearchIndexStatus>(content);
92-
93-
expect(indexDefinition?.name).toEqual("default");
94-
expect(indexDefinition?.type).toEqual("search");
95-
expect(indexDefinition?.latestDefinition).toEqual({ mappings: { dynamic: true, fields: {} } });
96-
expect(indexDefinition?.queryable).toEqual(true);
97-
expect(indexDefinition?.status).toEqual("READY");
98-
});
81+
it(
82+
"returns the list of existing indexes and detects if they are queryable",
83+
{ timeout: SEARCH_TIMEOUT },
84+
async ({ signal }) => {
85+
await waitUntilIndexIsQueryable(provider, "any", "foo", "default", signal);
86+
87+
const response = await integration.mcpClient().callTool({
88+
name: "list-search-indexes",
89+
arguments: { database: "any", collection: "foo" },
90+
});
91+
92+
const content = getResponseContent(response.content);
93+
const indexDefinition = getSingleDocFromUntrustedContent<SearchIndexStatus>(content);
94+
95+
expect(indexDefinition?.name).toEqual("default");
96+
expect(indexDefinition?.type).toEqual("search");
97+
expect(indexDefinition?.latestDefinition).toEqual({ mappings: { dynamic: true, fields: {} } });
98+
expect(indexDefinition?.queryable).toEqual(true);
99+
expect(indexDefinition?.status).toEqual("READY");
100+
}
101+
);
99102
});
100103
},
101104
undefined, // default user config
102105
undefined, // default driver config
103106
{ search: true } // use a search cluster
104107
);
105108

106-
const SEARCH_RETRIES = 10_000;
107109
async function waitUntilSearchIsReady(provider: NodeDriverServiceProvider, abortSignal: AbortSignal): Promise<void> {
108110
let success = true;
109111
let lastError: unknown = false;
@@ -153,7 +155,7 @@ async function waitUntilIndexIsQueryable(
153155

154156
if (!success) {
155157
throw new Error(
156-
`Index ${indexName} in ${database}.${collection} is not ready: \nlastIndexStatus: ${lastIndexStatus}\nlastError: ${lastError}`
158+
`Index ${indexName} in ${database}.${collection} is not ready: \nlastIndexStatus: ${JSON.stringify(lastIndexStatus)}\nlastError: ${lastError}`
157159
);
158160
}
159161
}

0 commit comments

Comments
 (0)