Skip to content

Commit 816aefe

Browse files
committed
chore: some suggestions on the PR
1 parent e015ccf commit 816aefe

File tree

3 files changed

+55
-43
lines changed

3 files changed

+55
-43
lines changed

src/common/connectionManager.ts

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@ export class ConnectionManager extends EventEmitter<ConnectionManagerEvents> {
140140
try {
141141
const connectionType = ConnectionManager.inferConnectionTypeFromSettings(this.userConfig, connectionInfo);
142142
if (connectionType.startsWith("oidc")) {
143-
// The error here is irrelevant, we only use this ping to force the connection
144-
// Errors will be handled by the auth flow.
145-
void serviceProvider?.runCommand?.("admin", { hello: 1 }).catch(() => {});
143+
void this.pingAndForget(serviceProvider);
146144

147145
return this.changeState("connection-requested", {
148146
tag: "connecting",
@@ -207,9 +205,7 @@ export class ConnectionManager extends EventEmitter<ConnectionManagerEvents> {
207205

208206
private onOidcAuthFailed(error: unknown): void {
209207
if (this.state.tag === "connecting" && this.state.connectionStringAuthType?.startsWith("oidc")) {
210-
void this.disconnect().then(() => {
211-
this.changeState("connection-errored", { tag: "errored", errorReason: String(error) });
212-
});
208+
void this.disconnectOnOidcError(error);
213209
}
214210
}
215211

@@ -279,31 +275,23 @@ export class ConnectionManager extends EventEmitter<ConnectionManagerEvents> {
279275
}
280276
}
281277

282-
static async waitUntil<T extends ConnectionState>(
283-
tag: T["tag"],
284-
cm: ConnectionManager,
285-
signal: AbortSignal,
286-
additionalCondition?: (state: T) => boolean
287-
): Promise<T> {
288-
let ts: NodeJS.Timeout | undefined;
289-
290-
return new Promise<T>((resolve, reject) => {
291-
ts = setInterval(() => {
292-
if (signal.aborted) {
293-
return reject(new Error(`Aborted: ${signal.reason}`));
294-
}
278+
private async pingAndForget(serviceProvider: NodeDriverServiceProvider): Promise<void> {
279+
try {
280+
await serviceProvider?.runCommand?.("admin", { hello: 1 }).catch(() => {});
281+
} catch (error: unknown) {
282+
// we really don't care about this error
283+
void error;
284+
}
285+
}
295286

296-
const status = cm.currentConnectionState;
297-
if (status.tag === tag) {
298-
if (!additionalCondition || (additionalCondition && additionalCondition(status as T))) {
299-
return resolve(status as T);
300-
}
301-
}
302-
}, 100);
303-
}).finally(() => {
304-
if (ts !== undefined) {
305-
clearInterval(ts);
306-
}
307-
});
287+
private async disconnectOnOidcError(error: unknown): Promise<void> {
288+
try {
289+
await this.disconnect();
290+
} catch (error: unknown) {
291+
// we really don't care about this error
292+
void error;
293+
} finally {
294+
this.changeState("connection-errored", { tag: "errored", errorReason: String(error) });
295+
}
308296
}
309297
}

tests/integration/common/connectionManager.oidc.test.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ import {
77
getServerVersion,
88
MongoDBIntegrationTestCase,
99
} from "../tools/mongodb/mongodbHelpers.js";
10-
import { defaultTestConfig, responseAsText, timeout } from "../helpers.js";
11-
import {
12-
ConnectionManager,
13-
ConnectionStateConnected,
14-
ConnectionStateConnecting,
15-
} from "../../../src/common/connectionManager.js";
10+
import { defaultTestConfig, responseAsText, timeout, waitUntil } from "../helpers.js";
11+
import { ConnectionStateConnected, ConnectionStateConnecting } from "../../../src/common/connectionManager.js";
1612
import { setupDriverConfig, UserConfig } from "../../../src/common/config.js";
1713
import path from "path";
1814
import type { OIDCMockProviderConfig } from "@mongodb-js/oidc-mock-provider";
@@ -161,7 +157,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as
161157
for (const { version, nonce } of baseTestMatrix) {
162158
describeOidcTest(version, `auth-flow;nonce=${nonce}`, { additionalConfig: { oidcNoNonce: !nonce } }, (it) => {
163159
it("can connect with the expected user", async ({ signal }, integration) => {
164-
const state = await ConnectionManager.waitUntil<ConnectionStateConnected>(
160+
const state = await waitUntil<ConnectionStateConnected>(
165161
"connected",
166162
integration.mcpServer().session.connectionManager,
167163
signal
@@ -186,7 +182,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as
186182
});
187183

188184
it("can list existing databases", async ({ signal }, integration) => {
189-
const state = await ConnectionManager.waitUntil<ConnectionStateConnected>(
185+
const state = await waitUntil<ConnectionStateConnected>(
190186
"connected",
191187
integration.mcpServer().session.connectionManager,
192188
signal
@@ -198,7 +194,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as
198194
});
199195

200196
it("can refresh a token once expired", async ({ signal }, integration) => {
201-
const state = await ConnectionManager.waitUntil<ConnectionStateConnected>(
197+
const state = await waitUntil<ConnectionStateConnected>(
202198
"connected",
203199
integration.mcpServer().session.connectionManager,
204200
signal
@@ -221,7 +217,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as
221217
{ additionalConfig: { oidcFlows: "device-auth", browser: false } },
222218
(it) => {
223219
it("gets requested by the agent to connect", async ({ signal }, integration) => {
224-
const state = await ConnectionManager.waitUntil<ConnectionStateConnecting>(
220+
const state = await waitUntil<ConnectionStateConnecting>(
225221
"connecting",
226222
integration.mcpServer().session.connectionManager,
227223
signal,
@@ -236,7 +232,7 @@ describe.skipIf(process.platform !== "linux")("ConnectionManager OIDC Tests", as
236232
expect(response).toContain(state.oidcLoginUrl);
237233
expect(response).toContain(state.oidcUserCode);
238234

239-
await ConnectionManager.waitUntil<ConnectionStateConnected>(
235+
await waitUntil<ConnectionStateConnected>(
240236
"connected",
241237
integration.mcpServer().session.connectionManager,
242238
signal

tests/integration/helpers.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Session } from "../../src/common/session.js";
88
import { Telemetry } from "../../src/telemetry/telemetry.js";
99
import { config, driverOptions } from "../../src/common/config.js";
1010
import { afterAll, afterEach, beforeAll, describe, expect, it, vi } from "vitest";
11-
import { ConnectionManager } from "../../src/common/connectionManager.js";
11+
import { ConnectionManager, ConnectionState } from "../../src/common/connectionManager.js";
1212
import { CompositeLogger } from "../../src/common/logger.js";
1313
import { ExportsManager } from "../../src/common/exportsManager.js";
1414

@@ -304,3 +304,31 @@ export function resourceChangedNotification(client: Client, uri: string): Promis
304304
export function responseAsText(response: Awaited<ReturnType<Client["callTool"]>>): string {
305305
return JSON.stringify(response.content, undefined, 2);
306306
}
307+
308+
export function waitUntil<T extends ConnectionState>(
309+
tag: T["tag"],
310+
cm: ConnectionManager,
311+
signal: AbortSignal,
312+
additionalCondition?: (state: T) => boolean
313+
): Promise<T> {
314+
let ts: NodeJS.Timeout | undefined;
315+
316+
return new Promise<T>((resolve, reject) => {
317+
ts = setInterval(() => {
318+
if (signal.aborted) {
319+
return reject(new Error(`Aborted: ${signal.reason}`));
320+
}
321+
322+
const status = cm.currentConnectionState;
323+
if (status.tag === tag) {
324+
if (!additionalCondition || (additionalCondition && additionalCondition(status as T))) {
325+
return resolve(status as T);
326+
}
327+
}
328+
}, 100);
329+
}).finally(() => {
330+
if (ts !== undefined) {
331+
clearInterval(ts);
332+
}
333+
});
334+
}

0 commit comments

Comments
 (0)