Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions packages/mcp-core/src/api-client/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { beforeEach, afterEach, describe, expect, it, vi } from "vitest";
import { http, HttpResponse } from "msw";
import { mswServer } from "@sentry/mcp-server-mocks";
import { SentryApiService } from "./client";
import { ConfigurationError } from "../errors";

Expand Down Expand Up @@ -327,6 +329,126 @@ describe("getEventsExplorerUrl", () => {
});
});

describe("monitor time parameters", () => {
it("defaults blank monitor statsPeriod values to a 24h window", async () => {
const requestUrls: URL[] = [];
mswServer.use(
http.get(
"https://sentry.io/api/0/organizations/my-org/monitors/nightly-import/checkins/",
({ request }) => {
requestUrls.push(new URL(request.url));
return HttpResponse.json([]);
},
),
http.get(
"https://sentry.io/api/0/organizations/my-org/monitors/nightly-import/stats/",
({ request }) => {
requestUrls.push(new URL(request.url));
return HttpResponse.json([]);
},
),
);

const apiService = new SentryApiService({
host: "sentry.io",
accessToken: "test-token",
});

await apiService.listMonitorCheckIns({
organizationSlug: "my-org",
monitorSlug: "nightly-import",
statsPeriod: " ",
limit: 10,
});
await apiService.getMonitorStats({
organizationSlug: "my-org",
monitorSlug: "nightly-import",
statsPeriod: " ",
});

expect(requestUrls).toHaveLength(2);
const [checkInsUrl, statsUrl] = requestUrls as [URL, URL];
expect(checkInsUrl.pathname).toBe(
"/api/0/organizations/my-org/monitors/nightly-import/checkins/",
);
expect(checkInsUrl.searchParams.get("statsPeriod")).toBe("24h");
expect(statsUrl.pathname).toBe(
"/api/0/organizations/my-org/monitors/nightly-import/stats/",
);
expect(statsUrl.searchParams.get("statsPeriod")).toBeNull();
expect(statsUrl.searchParams.get("since")).not.toBeNull();
expect(statsUrl.searchParams.get("until")).not.toBeNull();
});

it("rejects invalid monitor check-in statsPeriod values before sending a request", async () => {
let requestReceived = false;
mswServer.use(
http.get(
"https://sentry.io/api/0/organizations/my-org/monitors/nightly-import/checkins/",
() => {
requestReceived = true;
return HttpResponse.json([]);
},
),
);

const apiService = new SentryApiService({
host: "sentry.io",
accessToken: "test-token",
});

await expect(
apiService.listMonitorCheckIns({
organizationSlug: "my-org",
monitorSlug: "nightly-import",
statsPeriod: "bogus",
limit: 10,
}),
).rejects.toThrow("statsPeriod must use a supported relative time format");
expect(requestReceived).toBe(false);
});

it("rejects conflicting monitor statsPeriod and absolute time ranges before sending requests", async () => {
let requestReceived = false;
mswServer.use(
http.get(
"https://sentry.io/api/0/organizations/my-org/monitors/nightly-import/checkins/",
() => {
requestReceived = true;
return HttpResponse.json([]);
},
),
http.get(
"https://sentry.io/api/0/organizations/my-org/monitors/nightly-import/stats/",
() => {
requestReceived = true;
return HttpResponse.json([]);
},
),
);

const apiService = new SentryApiService({
host: "sentry.io",
accessToken: "test-token",
});
const params = {
organizationSlug: "my-org",
monitorSlug: "nightly-import",
statsPeriod: "24h",
start: "2024-01-01T00:00:00Z",
end: "2024-01-02T00:00:00Z",
};

await expect(apiService.listMonitorCheckIns(params)).rejects.toThrow(
"Cannot use both statsPeriod and start/end parameters",
);
await expect(apiService.getMonitorStats(params)).rejects.toThrow(
"Cannot use both statsPeriod and start/end parameters",
);
expect(requestReceived).toBe(false);
});
});

describe("network error handling", () => {
let originalFetch: typeof globalThis.fetch;

Expand Down
Loading
Loading