Skip to content

Commit 2393508

Browse files
committed
chore: add telemetry unit tests
1 parent 064ca88 commit 2393508

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { jest } from "@jest/globals";
2+
import { ApiClient } from "../../../../src/common/atlas/apiClient.js";
3+
import { BaseEvent } from "../../../../src/telemetry/types.js";
4+
5+
/**
6+
* Mock implementation of the ApiClient for unit testing
7+
*/
8+
export const mockApiClient = {
9+
sendEvents: jest.fn<(events: BaseEvent[]) => Promise<void>>(),
10+
hasCredentials: jest.fn<() => boolean>(),
11+
};
12+
13+
/**
14+
* Creates a mocked ApiClient instance for testing
15+
*/
16+
export function createMockApiClient(): jest.Mocked<Partial<ApiClient>> {
17+
return mockApiClient as jest.Mocked<Partial<ApiClient>>;
18+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { jest } from "@jest/globals";
2+
import { EventCache } from "../../../../src/telemetry/eventCache.js";
3+
import { BaseEvent } from "../../../../src/telemetry/types.js";
4+
5+
/**
6+
* Creates a mocked EventCache instance for testing
7+
*/
8+
export function createMockEventCache(initialEvents: BaseEvent[] = []): jest.Mocked<Partial<EventCache>> {
9+
let events = [...initialEvents];
10+
11+
return {
12+
getEvents: jest.fn().mockImplementation(() => [...events]),
13+
appendEvents: jest.fn().mockImplementation((newEvents: BaseEvent[]) => {
14+
events.push(...newEvents);
15+
}),
16+
clearEvents: jest.fn().mockImplementation(() => {
17+
events = [];
18+
}),
19+
} as jest.Mocked<Partial<EventCache>>;
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { jest } from "@jest/globals";
2+
import { Session } from "../../../../src/session.js";
3+
import { createMockApiClient } from "./apiClient.mock.js";
4+
5+
/**
6+
* Creates a mocked Session instance for testing
7+
*/
8+
export function createMockSession(): jest.Mocked<Partial<Session>> {
9+
return {
10+
apiClient: createMockApiClient(),
11+
sessionId: "test-session-id",
12+
agentRunner: {
13+
name: "test-agent",
14+
version: "1.0.0",
15+
},
16+
close: jest.fn().mockResolvedValue(undefined),
17+
} as jest.Mocked<Partial<Session>>;
18+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { jest } from "@jest/globals";
2+
import { Telemetry } from "../../../src/telemetry/telemetry.js";
3+
import { BaseEvent } from "../../../src/telemetry/types.js";
4+
import { mockApiClient, createMockApiClient } from "./mocks/apiClient.mock.js";
5+
import { createMockEventCache } from "./mocks/eventCache.mock.js";
6+
import { createMockSession } from "./mocks/session.mock.js";
7+
8+
// Mock the config module
9+
jest.mock("../../../src/config.js", () => ({
10+
config: {
11+
telemetry: "enabled",
12+
},
13+
}));
14+
15+
// Mock the constants module
16+
jest.mock("../../../src/telemetry/constants.js", () => ({
17+
MACHINE_METADATA: {
18+
device_id: "mock-device-id",
19+
mcp_server_version: "1.0.0",
20+
mcp_server_name: "atlas-mcp-server",
21+
platform: "test-platform",
22+
arch: "test-arch",
23+
os_type: "test-os",
24+
os_version: "test-version",
25+
},
26+
}));
27+
28+
// Helper function to create a test event
29+
const createTestEvent = (overrides: Partial<BaseEvent> = {}): BaseEvent => ({
30+
timestamp: new Date().toISOString(),
31+
source: "mdbmcp",
32+
properties: {
33+
device_id: "mock-device-id",
34+
mcp_server_version: "1.0.0",
35+
mcp_server_name: "atlas-mcp-server",
36+
platform: "test-platform",
37+
arch: "test-arch",
38+
os_type: "test-os",
39+
component: "test",
40+
duration_ms: 100,
41+
result: "success",
42+
category: "test",
43+
...overrides.properties,
44+
},
45+
...overrides,
46+
});
47+
48+
describe("Telemetry", () => {
49+
// Save and restore environment variables between tests
50+
const originalEnv = process.env;
51+
52+
beforeEach(() => {
53+
process.env = { ...originalEnv };
54+
jest.clearAllMocks();
55+
56+
// Reset mocked API client
57+
mockApiClient.sendEvents.mockReset();
58+
mockApiClient.hasCredentials.mockReset();
59+
mockApiClient.sendEvents.mockResolvedValue(undefined);
60+
mockApiClient.hasCredentials.mockReturnValue(true);
61+
});
62+
63+
afterAll(() => {
64+
process.env = originalEnv;
65+
});
66+
67+
describe("emitEvents", () => {
68+
it("should send events successfully and clear cache", async () => {
69+
// Arrange
70+
mockApiClient.sendEvents.mockResolvedValue(undefined);
71+
const mockSession = createMockSession();
72+
const cachedEvents = [createTestEvent({ properties: { command: "list-clusters" } })];
73+
const mockEventCache = createMockEventCache(cachedEvents);
74+
const telemetry = new Telemetry(mockSession as any, mockEventCache as any);
75+
const newEvents = [createTestEvent({ properties: { command: "new" } })];
76+
77+
// Act
78+
await telemetry.emitEvents(newEvents);
79+
80+
// Assert
81+
expect(mockApiClient.sendEvents).toHaveBeenCalledWith([...cachedEvents, ...newEvents]);
82+
expect(mockEventCache.clearEvents).toHaveBeenCalled();
83+
expect(mockEventCache.appendEvents).not.toHaveBeenCalled();
84+
});
85+
});
86+
});

0 commit comments

Comments
 (0)