-
Notifications
You must be signed in to change notification settings - Fork 41
chore: add integration tests for insert-many #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,141 @@ | ||||||||||||||||||||||||||||||||
import { | ||||||||||||||||||||||||||||||||
getResponseContent, | ||||||||||||||||||||||||||||||||
validateParameters, | ||||||||||||||||||||||||||||||||
dbOperationParameters, | ||||||||||||||||||||||||||||||||
setupIntegrationTest, | ||||||||||||||||||||||||||||||||
} from "../../../helpers.js"; | ||||||||||||||||||||||||||||||||
import { McpError } from "@modelcontextprotocol/sdk/types.js"; | ||||||||||||||||||||||||||||||||
import config from "../../../../../src/config.js"; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
describe("insertMany tool", () => { | ||||||||||||||||||||||||||||||||
const integration = setupIntegrationTest(); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
it("should have correct metadata", async () => { | ||||||||||||||||||||||||||||||||
const { tools } = await integration.mcpClient().listTools(); | ||||||||||||||||||||||||||||||||
const insertMany = tools.find((tool) => tool.name === "insert-many")!; | ||||||||||||||||||||||||||||||||
expect(insertMany).toBeDefined(); | ||||||||||||||||||||||||||||||||
expect(insertMany.description).toBe("Insert an array of documents into a MongoDB collection"); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
validateParameters(insertMany, [ | ||||||||||||||||||||||||||||||||
...dbOperationParameters, | ||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||
name: "documents", | ||||||||||||||||||||||||||||||||
type: "array", | ||||||||||||||||||||||||||||||||
description: | ||||||||||||||||||||||||||||||||
"The array of documents to insert, matching the syntax of the document argument of db.collection.insertMany()", | ||||||||||||||||||||||||||||||||
required: true, | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
]); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
describe("with invalid arguments", () => { | ||||||||||||||||||||||||||||||||
const args = [ | ||||||||||||||||||||||||||||||||
{}, | ||||||||||||||||||||||||||||||||
{ collection: "bar", database: 123, documents: [] }, | ||||||||||||||||||||||||||||||||
{ collection: [], database: "test", documents: [] }, | ||||||||||||||||||||||||||||||||
{ collection: "bar", database: "test", documents: "my-document" }, | ||||||||||||||||||||||||||||||||
{ collection: "bar", database: "test", documents: { name: "Peter" } }, | ||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||
for (const arg of args) { | ||||||||||||||||||||||||||||||||
Comment on lines
+32
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
it(`throws a schema error for: ${JSON.stringify(arg)}`, async () => { | ||||||||||||||||||||||||||||||||
await integration.connectMcpClient(); | ||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||
await integration.mcpClient().callTool({ name: "insert-many", arguments: arg }); | ||||||||||||||||||||||||||||||||
expect.fail("Expected an error to be thrown"); | ||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||
expect(error).toBeInstanceOf(McpError); | ||||||||||||||||||||||||||||||||
const mcpError = error as McpError; | ||||||||||||||||||||||||||||||||
expect(mcpError.code).toEqual(-32602); | ||||||||||||||||||||||||||||||||
expect(mcpError.message).toContain("Invalid arguments for tool insert-many"); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
const validateDocuments = async (collection: string, expectedDocuments: object[]) => { | ||||||||||||||||||||||||||||||||
const collections = await integration.mongoClient().db(integration.randomDbName()).listCollections().toArray(); | ||||||||||||||||||||||||||||||||
expect(collections.find((c) => c.name === collection)).toBeDefined(); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
const docs = await integration | ||||||||||||||||||||||||||||||||
.mongoClient() | ||||||||||||||||||||||||||||||||
.db(integration.randomDbName()) | ||||||||||||||||||||||||||||||||
.collection(collection) | ||||||||||||||||||||||||||||||||
.find() | ||||||||||||||||||||||||||||||||
.toArray(); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
expect(docs).toHaveLength(expectedDocuments.length); | ||||||||||||||||||||||||||||||||
for (const expectedDocument of expectedDocuments) { | ||||||||||||||||||||||||||||||||
expect(docs).toContainEqual(expect.objectContaining(expectedDocument)); | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
it("creates the namespace if necessary", async () => { | ||||||||||||||||||||||||||||||||
await integration.connectMcpClient(); | ||||||||||||||||||||||||||||||||
const response = await integration.mcpClient().callTool({ | ||||||||||||||||||||||||||||||||
name: "insert-many", | ||||||||||||||||||||||||||||||||
arguments: { | ||||||||||||||||||||||||||||||||
database: integration.randomDbName(), | ||||||||||||||||||||||||||||||||
Comment on lines
+73
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Store the random database name in a variable and reuse it for both the tool call and the subsequent validation to ensure consistency between the created and verified namespaces.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||
collection: "coll1", | ||||||||||||||||||||||||||||||||
documents: [{ prop1: "value1" }], | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
const content = getResponseContent(response.content); | ||||||||||||||||||||||||||||||||
expect(content).toContain('Inserted `1` document(s) into collection "coll1"'); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
await validateDocuments("coll1", [{ prop1: "value1" }]); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
it("returns an error when inserting duplicates", async () => { | ||||||||||||||||||||||||||||||||
const { insertedIds } = await integration | ||||||||||||||||||||||||||||||||
.mongoClient() | ||||||||||||||||||||||||||||||||
.db(integration.randomDbName()) | ||||||||||||||||||||||||||||||||
.collection("coll1") | ||||||||||||||||||||||||||||||||
.insertMany([{ prop1: "value1" }]); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
await integration.connectMcpClient(); | ||||||||||||||||||||||||||||||||
const response = await integration.mcpClient().callTool({ | ||||||||||||||||||||||||||||||||
name: "insert-many", | ||||||||||||||||||||||||||||||||
arguments: { | ||||||||||||||||||||||||||||||||
database: integration.randomDbName(), | ||||||||||||||||||||||||||||||||
collection: "coll1", | ||||||||||||||||||||||||||||||||
documents: [{ prop1: "value1", _id: insertedIds[0] }], | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
const content = getResponseContent(response.content); | ||||||||||||||||||||||||||||||||
expect(content).toContain("Error running insert-many"); | ||||||||||||||||||||||||||||||||
expect(content).toContain("duplicate key error"); | ||||||||||||||||||||||||||||||||
expect(content).toContain(insertedIds[0].toString()); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
describe("when not connected", () => { | ||||||||||||||||||||||||||||||||
it("connects automatically if connection string is configured", async () => { | ||||||||||||||||||||||||||||||||
config.connectionString = integration.connectionString(); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
const response = await integration.mcpClient().callTool({ | ||||||||||||||||||||||||||||||||
name: "insert-many", | ||||||||||||||||||||||||||||||||
arguments: { | ||||||||||||||||||||||||||||||||
database: integration.randomDbName(), | ||||||||||||||||||||||||||||||||
collection: "coll1", | ||||||||||||||||||||||||||||||||
documents: [{ prop1: "value1" }], | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
const content = getResponseContent(response.content); | ||||||||||||||||||||||||||||||||
expect(content).toContain('Inserted `1` document(s) into collection "coll1"'); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
it("throw an error if connection string is not configured", async () => { | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] Consider updating the test description to 'throws an error if connection string is not configured' to maintain grammatical consistency.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||
const response = await integration.mcpClient().callTool({ | ||||||||||||||||||||||||||||||||
name: "insert-many", | ||||||||||||||||||||||||||||||||
arguments: { | ||||||||||||||||||||||||||||||||
database: integration.randomDbName(), | ||||||||||||||||||||||||||||||||
collection: "coll1", | ||||||||||||||||||||||||||||||||
documents: [{ prop1: "value1" }], | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
const content = getResponseContent(response.content); | ||||||||||||||||||||||||||||||||
expect(content).toContain("You need to connect to a MongoDB instance before you can access its data."); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||
}); |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason for the change of the `?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly consistency - it doesn't really matter as in my experience, the model will not return the result as-is, but rather reformat it. But we've been using quotes in other places, so figured I should standardize around it.