Skip to content

Commit 5da6e8d

Browse files
committed
Add tests
1 parent 9dbdca1 commit 5da6e8d

File tree

2 files changed

+224
-12
lines changed

2 files changed

+224
-12
lines changed

src/tools/atlas/read/getPerformanceAdvisor.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,22 @@ export class GetPerformanceAdvisorTool extends AtlasToolBase {
6464
: Promise.resolve(undefined),
6565
]);
6666

67+
const hasSuggestedIndexes = suggestedIndexesResult && suggestedIndexesResult?.suggestedIndexes?.length > 0;
68+
const hasDropIndexSuggestions =
69+
dropIndexSuggestionsResult &&
70+
dropIndexSuggestionsResult?.hiddenIndexes?.length > 0 &&
71+
dropIndexSuggestionsResult?.redundantIndexes?.length > 0 &&
72+
dropIndexSuggestionsResult?.unusedIndexes?.length > 0;
73+
const hasSlowQueryLogs = slowQueryLogsResult && slowQueryLogsResult?.slowQueryLogs?.length > 0;
74+
const hasSchemaSuggestions =
75+
schemaSuggestionsResult && schemaSuggestionsResult?.recommendations?.length > 0;
76+
77+
// Inserts the performance advisor data with the relevant section header if it exists
6778
const performanceAdvisorData = [
68-
suggestedIndexesResult && suggestedIndexesResult?.suggestedIndexes?.length > 0
69-
? `## Suggested Indexes\n${JSON.stringify(suggestedIndexesResult.suggestedIndexes)}`
70-
: "No suggested indexes found.",
71-
dropIndexSuggestionsResult
72-
? `## Drop Index Suggestions\n${JSON.stringify(dropIndexSuggestionsResult)}`
73-
: "No drop index suggestions found.",
74-
slowQueryLogsResult && slowQueryLogsResult?.slowQueryLogs?.length > 0
75-
? `## Slow Query Logs\n${JSON.stringify(slowQueryLogsResult.slowQueryLogs)}`
76-
: "No slow query logs found.",
77-
schemaSuggestionsResult && schemaSuggestionsResult?.recommendations?.length > 0
78-
? `## Schema Suggestions\n${JSON.stringify(schemaSuggestionsResult.recommendations)}`
79-
: "No schema suggestions found.",
79+
`## Suggested Indexes\n${hasSuggestedIndexes ? JSON.stringify(suggestedIndexesResult.suggestedIndexes) : "No suggested indexes found."}`,
80+
`## Drop Index Suggestions\n${hasDropIndexSuggestions ? JSON.stringify(dropIndexSuggestionsResult) : "No drop index suggestions found."}`,
81+
`## Slow Query Logs\n${hasSlowQueryLogs ? JSON.stringify(slowQueryLogsResult.slowQueryLogs) : "No slow query logs found."}`,
82+
`## Schema Suggestions\n${hasSchemaSuggestions ? JSON.stringify(schemaSuggestionsResult.recommendations) : "No schema suggestions found."}`,
8083
];
8184

8285
if (performanceAdvisorData.length === 0) {
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import { expectDefined, getResponseElements } from "../../helpers.js";
2+
import { describeWithAtlas, withProject } from "./atlasHelpers.js";
3+
import { describe, expect, it, vi } from "vitest";
4+
5+
describeWithAtlas("performanceAdvisor", (integration) => {
6+
withProject(integration, ({ getProjectId }) => {
7+
describe("atlas-get-performance-advisor", () => {
8+
it("should have correct metadata", async () => {
9+
const { tools } = await integration.mcpClient().listTools();
10+
const getPerformanceAdvisor = tools.find((tool) => tool.name === "atlas-get-performance-advisor");
11+
expectDefined(getPerformanceAdvisor);
12+
expect(getPerformanceAdvisor.inputSchema.type).toBe("object");
13+
expectDefined(getPerformanceAdvisor.inputSchema.properties);
14+
expect(getPerformanceAdvisor.inputSchema.properties).toHaveProperty("projectId");
15+
expect(getPerformanceAdvisor.inputSchema.properties).toHaveProperty("clusterName");
16+
expect(getPerformanceAdvisor.inputSchema.properties).toHaveProperty("operations");
17+
expect(getPerformanceAdvisor.inputSchema.properties).toHaveProperty("since");
18+
expect(getPerformanceAdvisor.inputSchema.properties).toHaveProperty("namespaces");
19+
});
20+
21+
it("returns mocked performance advisor data", async () => {
22+
const projectId = getProjectId();
23+
const session = integration.mcpServer().session;
24+
25+
// Mock the API client methods since we can't guarantee performance advisor data
26+
const mockSuggestedIndexes = vi.fn().mockResolvedValue({
27+
content: {
28+
suggestedIndexes: [
29+
{
30+
namespace: "testdb.testcollection",
31+
index: { field: 1 },
32+
impact: ["queryShapeString"],
33+
},
34+
],
35+
},
36+
});
37+
38+
const mockDropIndexSuggestions = vi.fn().mockResolvedValue({
39+
content: {
40+
hiddenIndexes: [],
41+
redundantIndexes: [
42+
{
43+
accessCount: 100,
44+
namespace: "testdb.testcollection",
45+
index: { field: 1 },
46+
reason: "Redundant with compound index",
47+
},
48+
],
49+
unusedIndexes: [],
50+
},
51+
});
52+
53+
const mockSchemaAdvice = vi.fn().mockResolvedValue({
54+
content: {
55+
recommendations: [
56+
{
57+
description: "Consider adding an index on 'status' field",
58+
recommendation: "REDUCE_LOOKUP_OPS",
59+
affectedNamespaces: [
60+
{
61+
namespace: "testdb.testcollection",
62+
triggers: [
63+
{
64+
triggerType: "PERCENT_QUERIES_USE_LOOKUP",
65+
details:
66+
"Queries filtering by status field are causing collection scans",
67+
},
68+
],
69+
},
70+
],
71+
},
72+
],
73+
},
74+
});
75+
76+
const mockSlowQueries = vi.fn().mockResolvedValue({
77+
slowQueries: [
78+
{
79+
namespace: "testdb.testcollection",
80+
query: { find: "testcollection", filter: { status: "active" } },
81+
duration: 1500,
82+
timestamp: "2024-01-15T10:30:00Z",
83+
},
84+
],
85+
});
86+
87+
const mockGetCluster = vi.fn().mockResolvedValue({
88+
connectionStrings: {
89+
standard: "mongodb://test-cluster.mongodb.net:27017",
90+
},
91+
});
92+
93+
session.apiClient.listClusterSuggestedIndexes = mockSuggestedIndexes;
94+
session.apiClient.listDropIndexes = mockDropIndexSuggestions;
95+
session.apiClient.listSchemaAdvice = mockSchemaAdvice;
96+
session.apiClient.listSlowQueries = mockSlowQueries;
97+
session.apiClient.getCluster = mockGetCluster;
98+
99+
const response = await integration.mcpClient().callTool({
100+
name: "atlas-get-performance-advisor",
101+
arguments: {
102+
projectId,
103+
clusterName: "mockClusterName",
104+
operations: ["suggestedIndexes", "dropIndexSuggestions", "slowQueryLogs", "schemaSuggestions"],
105+
},
106+
});
107+
108+
if (response.isError) {
109+
console.error("Performance advisor call failed:", response.content);
110+
throw new Error("Performance advisor call failed - see console for details");
111+
}
112+
113+
const elements = getResponseElements(response.content);
114+
expect(elements).toHaveLength(2);
115+
116+
expect(elements[0]?.text).toContain("Performance advisor data");
117+
expect(elements[1]?.text).toContain("<untrusted-user-data-");
118+
119+
expect(elements[1]?.text).toContain("## Suggested Indexes");
120+
expect(elements[1]?.text).toContain("## Drop Index Suggestions");
121+
expect(elements[1]?.text).toContain("## Slow Query Logs");
122+
expect(elements[1]?.text).toContain("## Schema Suggestions");
123+
124+
expect(mockSuggestedIndexes).toHaveBeenCalled();
125+
expect(mockDropIndexSuggestions).toHaveBeenCalled();
126+
expect(mockSchemaAdvice).toHaveBeenCalled();
127+
expect(mockSlowQueries).toHaveBeenCalled();
128+
expect(mockGetCluster).toHaveBeenCalled();
129+
});
130+
131+
it("returns performance advisor data with no recommendations", async () => {
132+
const projectId = getProjectId();
133+
const session = integration.mcpServer().session;
134+
135+
const mockSuggestedIndexes = vi.fn().mockResolvedValue({
136+
content: {
137+
suggestedIndexes: [],
138+
},
139+
});
140+
141+
const mockDropIndexSuggestions = vi.fn().mockResolvedValue({
142+
content: {
143+
hiddenIndexes: [],
144+
redundantIndexes: [],
145+
unusedIndexes: [],
146+
},
147+
});
148+
149+
const mockSchemaAdvice = vi.fn().mockResolvedValue({
150+
content: {
151+
recommendations: [],
152+
},
153+
});
154+
155+
const mockSlowQueries = vi.fn().mockResolvedValue({
156+
slowQueries: [],
157+
});
158+
159+
// Mock the cluster inspection for getProcessIdFromCluster
160+
const mockGetCluster = vi.fn().mockResolvedValue({
161+
connectionStrings: {
162+
standard: "mongodb://test-cluster.mongodb.net:27017",
163+
},
164+
});
165+
166+
session.apiClient.listClusterSuggestedIndexes = mockSuggestedIndexes;
167+
session.apiClient.listDropIndexes = mockDropIndexSuggestions;
168+
session.apiClient.listSchemaAdvice = mockSchemaAdvice;
169+
session.apiClient.listSlowQueries = mockSlowQueries;
170+
session.apiClient.getCluster = mockGetCluster;
171+
172+
const response = await integration.mcpClient().callTool({
173+
name: "atlas-get-performance-advisor",
174+
arguments: {
175+
projectId,
176+
clusterName: "mockClusterName",
177+
operations: ["suggestedIndexes", "dropIndexSuggestions", "slowQueryLogs", "schemaSuggestions"],
178+
},
179+
});
180+
181+
if (response.isError) {
182+
console.error("Performance advisor call failed:", response.content);
183+
throw new Error("Performance advisor call failed - see console for details");
184+
}
185+
186+
const elements = getResponseElements(response.content);
187+
expect(elements).toHaveLength(2);
188+
189+
expect(elements[0]?.text).toContain("Performance advisor data");
190+
expect(elements[1]?.text).toContain("<untrusted-user-data-");
191+
192+
expect(elements[1]?.text).toContain("## Suggested Indexes");
193+
expect(elements[1]?.text).toContain("No suggested indexes found.");
194+
expect(elements[1]?.text).toContain("## Drop Index Suggestions");
195+
expect(elements[1]?.text).toContain("No drop index suggestions found.");
196+
expect(elements[1]?.text).toContain("## Slow Query Logs");
197+
expect(elements[1]?.text).toContain("No slow query logs found.");
198+
expect(elements[1]?.text).toContain("## Schema Suggestions");
199+
expect(elements[1]?.text).toContain("No schema suggestions found.");
200+
201+
expect(mockSuggestedIndexes).toHaveBeenCalled();
202+
expect(mockDropIndexSuggestions).toHaveBeenCalled();
203+
expect(mockSchemaAdvice).toHaveBeenCalled();
204+
expect(mockSlowQueries).toHaveBeenCalled();
205+
expect(mockGetCluster).toHaveBeenCalled();
206+
});
207+
});
208+
});
209+
});

0 commit comments

Comments
 (0)