Skip to content

Commit 4c61ad3

Browse files
Add create tests
1 parent 2ad8fce commit 4c61ad3

File tree

2 files changed

+231
-5
lines changed

2 files changed

+231
-5
lines changed
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
22
import { AtlasLocalToolBase } from "../atlasLocalTool.js";
33
import type { OperationType, ToolArgs } from "../../tool.js";
4-
import type { Client } from "@mongodb-js-preview/atlas-local";
5-
import type { CreateDeploymentOptions, CreationSourceType } from "@mongodb-js-preview/atlas-local";
4+
import type { Client, CreateDeploymentOptions, CreationSourceType } from "@mongodb-js-preview/atlas-local";
65
import z from "zod";
76

87
export class CreateDeploymentTool extends AtlasLocalToolBase {
98
public name = "atlas-local-create-deployment";
109
protected description = "Create a MongoDB Atlas local deployment";
1110
public operationType: OperationType = "create";
1211
protected argsShape = {
13-
deploymentName: z.string().describe("Name of the deployment to create"),
12+
deploymentName: z.string().describe("Name of the deployment to create").optional(),
1413
};
1514

1615
protected async executeWithAtlasLocalClient(
@@ -19,13 +18,21 @@ export class CreateDeploymentTool extends AtlasLocalToolBase {
1918
): Promise<CallToolResult> {
2019
const deploymentOptions: CreateDeploymentOptions = {
2120
name: deploymentName,
22-
creationSource: "MCPServer",
21+
creationSource: {
22+
type: "MCPServer" as CreationSourceType,
23+
source: "MCPServer",
24+
},
2325
};
2426
// Create the deployment
2527
await client.createDeployment(deploymentOptions);
2628

29+
if (deploymentName) {
30+
return {
31+
content: [{ type: "text", text: `Deployment "${deploymentName}" created.` }],
32+
};
33+
}
2734
return {
28-
content: [{ type: "text", text: `Deployment ${deploymentName} created.` }],
35+
content: [{ type: "text", text: `Deployment created.` }],
2936
};
3037
}
3138
}
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import {
2+
defaultDriverOptions,
3+
defaultTestConfig,
4+
expectDefined,
5+
getResponseElements,
6+
setupIntegrationTest,
7+
waitUntilMcpClientIsSet,
8+
} from "../../helpers.js";
9+
import { afterEach, describe, expect, it } from "vitest";
10+
11+
const isMacOSInGitHubActions = process.platform === "darwin" && process.env.GITHUB_ACTIONS === "true";
12+
13+
// Docker is not available on macOS in GitHub Actions
14+
// That's why we skip the tests on macOS in GitHub Actions
15+
describe("atlas-local-create-deployment", () => {
16+
let deploymentNamesToCleanup: string[] = [];
17+
18+
afterEach(async () => {
19+
// Clean up any deployments created during the test
20+
for (const deploymentName of deploymentNamesToCleanup) {
21+
try {
22+
await integration.mcpClient().callTool({
23+
name: "atlas-local-delete-deployment",
24+
arguments: { deploymentName },
25+
});
26+
} catch (error) {
27+
console.warn(`Failed to delete deployment ${deploymentName}:`, error);
28+
}
29+
}
30+
deploymentNamesToCleanup = [];
31+
});
32+
const integration = setupIntegrationTest(
33+
() => defaultTestConfig,
34+
() => defaultDriverOptions
35+
);
36+
37+
it.skipIf(isMacOSInGitHubActions)("should have the atlas-local-create-deployment tool", async ({ signal }) => {
38+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
39+
40+
const { tools } = await integration.mcpClient().listTools();
41+
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
42+
expectDefined(createDeployment);
43+
});
44+
45+
it.skipIf(!isMacOSInGitHubActions)(
46+
"[MacOS in GitHub Actions] should not have the atlas-local-create-deployment tool",
47+
async ({ signal }) => {
48+
// This should throw an error because the client is not set within the timeout of 5 seconds (default)
49+
await expect(waitUntilMcpClientIsSet(integration.mcpServer(), signal)).rejects.toThrow();
50+
51+
const { tools } = await integration.mcpClient().listTools();
52+
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
53+
expect(createDeployment).toBeUndefined();
54+
}
55+
);
56+
57+
it.skipIf(isMacOSInGitHubActions)("should have correct metadata", async ({ signal }) => {
58+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
59+
const { tools } = await integration.mcpClient().listTools();
60+
const createDeployment = tools.find((tool) => tool.name === "atlas-local-create-deployment");
61+
expectDefined(createDeployment);
62+
expect(createDeployment.inputSchema.type).toBe("object");
63+
expectDefined(createDeployment.inputSchema.properties);
64+
expect(createDeployment.inputSchema.properties).toHaveProperty("deploymentName");
65+
});
66+
67+
it.skipIf(isMacOSInGitHubActions).sequential(
68+
"should create a deployment when calling the tool",
69+
async ({ signal }) => {
70+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
71+
72+
// Count the current number of deployments
73+
const beforeResponse = await integration.mcpClient().callTool({
74+
name: "atlas-local-list-deployments",
75+
arguments: {},
76+
});
77+
const beforeNumberOfDeployments = parseInt(
78+
getResponseElements(beforeResponse.content)[0]?.text.match(/\d+/)?.[0] || "0",
79+
10
80+
);
81+
82+
// Create a deployment
83+
const deploymentName = `test-deployment-${Date.now()}`;
84+
deploymentNamesToCleanup.push(deploymentName);
85+
await integration.mcpClient().callTool({
86+
name: "atlas-local-create-deployment",
87+
arguments: { deploymentName },
88+
});
89+
90+
// Count the number of deployments after creating the deployment
91+
const afterResponse = await integration.mcpClient().callTool({
92+
name: "atlas-local-list-deployments",
93+
arguments: {},
94+
});
95+
const afterNumberOfDeployments = parseInt(
96+
getResponseElements(afterResponse.content)[0]?.text.match(/\d+/)?.[0] || "0",
97+
10
98+
);
99+
// Check that the number of deployments has increased by 1
100+
expect(afterNumberOfDeployments).toBe(beforeNumberOfDeployments + 1);
101+
}
102+
);
103+
104+
it.skipIf(isMacOSInGitHubActions).sequential(
105+
"should return an error when creating a deployment that already exists",
106+
async ({ signal }) => {
107+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
108+
109+
// Create a deployment
110+
const deploymentName = `test-deployment-${Date.now()}`;
111+
deploymentNamesToCleanup.push(deploymentName);
112+
await integration.mcpClient().callTool({
113+
name: "atlas-local-create-deployment",
114+
arguments: { deploymentName },
115+
});
116+
117+
// Try to create the same deployment again
118+
const response = await integration.mcpClient().callTool({
119+
name: "atlas-local-create-deployment",
120+
arguments: { deploymentName },
121+
});
122+
const elements = getResponseElements(response.content);
123+
expect(elements.length).toBeGreaterThanOrEqual(1);
124+
expect(elements[0]?.text).toContain("Container already exists: " + deploymentName);
125+
}
126+
);
127+
128+
it.skipIf(isMacOSInGitHubActions).sequential(
129+
"should create a deployment with the correct name",
130+
async ({ signal }) => {
131+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
132+
133+
// Create a deployment
134+
const deploymentName = `test-deployment-${Date.now()}`;
135+
deploymentNamesToCleanup.push(deploymentName);
136+
await integration.mcpClient().callTool({
137+
name: "atlas-local-create-deployment",
138+
arguments: { deploymentName },
139+
});
140+
141+
// List the deployments
142+
const response = await integration.mcpClient().callTool({
143+
name: "atlas-local-list-deployments",
144+
arguments: {},
145+
});
146+
const elements = getResponseElements(response.content);
147+
expect(elements.length).toBeGreaterThanOrEqual(1);
148+
expect(elements[1]?.text).toContain(deploymentName);
149+
expect(elements[1]?.text).toContain("Running");
150+
}
151+
);
152+
153+
it.skipIf(isMacOSInGitHubActions).sequential(
154+
"should create a deployment when name is not provided",
155+
async ({ signal }) => {
156+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
157+
158+
// Create a deployment
159+
await integration.mcpClient().callTool({
160+
name: "atlas-local-create-deployment",
161+
arguments: {},
162+
});
163+
164+
// List the deployments
165+
const response = await integration.mcpClient().callTool({
166+
name: "atlas-local-list-deployments",
167+
arguments: {},
168+
});
169+
const elements = getResponseElements(response.content);
170+
expect(elements.length).toBeGreaterThanOrEqual(1);
171+
// Random name starts with local and a number
172+
const deploymentName = elements[1]?.text.match(/local\d+/)?.[0];
173+
expectDefined(deploymentName);
174+
deploymentNamesToCleanup.push(deploymentName);
175+
expect(elements[1]?.text).toContain("Running");
176+
}
177+
);
178+
179+
it.skipIf(isMacOSInGitHubActions).sequential(
180+
"should delete a deployment when calling the tool",
181+
async ({ signal }) => {
182+
await waitUntilMcpClientIsSet(integration.mcpServer(), signal);
183+
// Create a deployment
184+
const deploymentName = `test-deployment-${Date.now()}`;
185+
await integration.mcpClient().callTool({
186+
name: "atlas-local-create-deployment",
187+
arguments: { deploymentName },
188+
});
189+
190+
// Count the current number of deployments
191+
const beforeResponse = await integration.mcpClient().callTool({
192+
name: "atlas-local-list-deployments",
193+
arguments: {},
194+
});
195+
const beforeNumberOfDeployments = parseInt(
196+
getResponseElements(beforeResponse.content)[0]?.text.match(/\d+/)?.[0] || "0",
197+
10
198+
);
199+
200+
// Delete the deployment
201+
await integration.mcpClient().callTool({
202+
name: "atlas-local-delete-deployment",
203+
arguments: { deploymentName },
204+
});
205+
206+
// Count the number of deployments after deleting the deployment
207+
const afterResponse = await integration.mcpClient().callTool({
208+
name: "atlas-local-list-deployments",
209+
arguments: {},
210+
});
211+
const afterNumberOfDeployments = parseInt(
212+
getResponseElements(afterResponse.content)[0]?.text.match(/\d+/)?.[0] || "0",
213+
10
214+
);
215+
// Check that the number of deployments has decreased by 1
216+
expect(afterNumberOfDeployments).toBe(beforeNumberOfDeployments - 1);
217+
}
218+
);
219+
});

0 commit comments

Comments
 (0)