Skip to content

Commit c612c92

Browse files
committed
test: add telemetry module and settings resolution unit tests
- src/tests/telemetry.test.ts: 6 tests covering enabled flag, missing machineId, correct fetch params, error swallowing, custom timeout - src/tests/settings-and-notify.test.ts: 3 new tests + extended precedence test verifying telemetryEnabled resolution chain
1 parent b906283 commit c612c92

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

src/tests/settings-and-notify.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ test("resolveSettings reads THINKING_ENABLED, REASONING_EFFORT, and DEBUG_LOG_EN
8383
assert.equal(resolved.baseURL, "https://default.example.com");
8484
});
8585

86+
test("resolveSettings defaults telemetryEnabled to true", () => {
87+
const resolved = resolveSettings(
88+
{},
89+
{ model: "default-model", baseURL: "https://default.example.com" },
90+
TEST_PROCESS_ENV
91+
);
92+
assert.equal(resolved.telemetryEnabled, true);
93+
});
94+
95+
test("resolveSettings reads TELEMETRY_ENABLED from env", () => {
96+
const resolved = resolveSettings(
97+
{ env: { TELEMETRY_ENABLED: "0" } },
98+
{ model: "default-model", baseURL: "https://default.example.com" },
99+
TEST_PROCESS_ENV
100+
);
101+
assert.equal(resolved.telemetryEnabled, false);
102+
});
103+
104+
test("resolveSettings gives top-level telemetryEnabled priority over env TELEMETRY_ENABLED", () => {
105+
const resolved = resolveSettings(
106+
{
107+
telemetryEnabled: false,
108+
env: { TELEMETRY_ENABLED: "true" },
109+
},
110+
{ model: "default-model", baseURL: "https://default.example.com" },
111+
TEST_PROCESS_ENV
112+
);
113+
assert.equal(resolved.telemetryEnabled, false);
114+
});
115+
86116
test("resolveSettings ignores removed legacy env.THINKING", () => {
87117
const resolved = resolveSettings(
88118
{
@@ -115,6 +145,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
115145
thinkingEnabled: true,
116146
reasoningEffort: "max",
117147
debugLogEnabled: true,
148+
telemetryEnabled: false,
118149
},
119150
{
120151
env: {
@@ -125,6 +156,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
125156
},
126157
model: "project-top-model",
127158
thinkingEnabled: true,
159+
telemetryEnabled: true,
128160
},
129161
{
130162
model: "default-model",
@@ -135,6 +167,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
135167
DEEPCODE_THINKING_ENABLED: "false",
136168
DEEPCODE_REASONING_EFFORT: "high",
137169
DEEPCODE_DEBUG_LOG_ENABLED: "true",
170+
DEEPCODE_TELEMETRY_ENABLED: "false",
138171
DEEPCODE_WEBHOOK: "system-webhook",
139172
}
140173
);
@@ -144,6 +177,7 @@ test("resolveSettingsSources applies user, project, and DEEPCODE environment pre
144177
assert.equal(resolved.thinkingEnabled, false);
145178
assert.equal(resolved.reasoningEffort, "high");
146179
assert.equal(resolved.debugLogEnabled, true);
180+
assert.equal(resolved.telemetryEnabled, false);
147181
assert.equal(resolved.env.WEBHOOK, "system-webhook");
148182
});
149183

src/tests/telemetry.test.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { test } from "node:test";
2+
import assert from "node:assert/strict";
3+
import { reportNewPrompt } from "../common/telemetry";
4+
5+
test("reportNewPrompt does not call fetch when enabled is false", () => {
6+
let called = false;
7+
const originalFetch = globalThis.fetch;
8+
globalThis.fetch = ((..._args: unknown[]) => {
9+
called = true;
10+
return Promise.resolve(new Response());
11+
}) as typeof globalThis.fetch;
12+
13+
try {
14+
reportNewPrompt({ enabled: false, machineId: "test-machine" });
15+
assert.equal(called, false);
16+
} finally {
17+
globalThis.fetch = originalFetch;
18+
}
19+
});
20+
21+
test("reportNewPrompt does not call fetch when machineId is undefined", () => {
22+
let called = false;
23+
const originalFetch = globalThis.fetch;
24+
globalThis.fetch = ((..._args: unknown[]) => {
25+
called = true;
26+
return Promise.resolve(new Response());
27+
}) as typeof globalThis.fetch;
28+
29+
try {
30+
reportNewPrompt({ enabled: true });
31+
assert.equal(called, false);
32+
} finally {
33+
globalThis.fetch = originalFetch;
34+
}
35+
});
36+
37+
test("reportNewPrompt does not call fetch when machineId is empty string", () => {
38+
let called = false;
39+
const originalFetch = globalThis.fetch;
40+
globalThis.fetch = ((..._args: unknown[]) => {
41+
called = true;
42+
return Promise.resolve(new Response());
43+
}) as typeof globalThis.fetch;
44+
45+
try {
46+
reportNewPrompt({ enabled: true, machineId: "" });
47+
assert.equal(called, false);
48+
} finally {
49+
globalThis.fetch = originalFetch;
50+
}
51+
});
52+
53+
test("reportNewPrompt calls fetch with correct URL, method, headers, and body", async () => {
54+
const calls: Array<{ url: string; init: RequestInit }> = [];
55+
const originalFetch = globalThis.fetch;
56+
globalThis.fetch = ((url: string | URL | Request, init?: RequestInit) => {
57+
calls.push({ url: String(url), init: init ?? {} });
58+
return Promise.resolve(new Response());
59+
}) as typeof globalThis.fetch;
60+
61+
try {
62+
reportNewPrompt({ enabled: true, machineId: "test-machine" });
63+
64+
// Wait for the fire-and-forget fetch to settle.
65+
await new Promise((resolve) => setTimeout(resolve, 50));
66+
67+
assert.equal(calls.length, 1);
68+
assert.equal(calls[0].url, "https://deepcode.vegamo.cn/api/plugin/new");
69+
assert.equal(calls[0].init.method, "POST");
70+
assert.equal((calls[0].init.headers as Record<string, string>)["Content-Type"], "application/json");
71+
assert.equal((calls[0].init.headers as Record<string, string>)["Token"], "test-machine");
72+
assert.equal(calls[0].init.body, JSON.stringify({}));
73+
} finally {
74+
globalThis.fetch = originalFetch;
75+
}
76+
});
77+
78+
test("reportNewPrompt swallows fetch errors without throwing", async () => {
79+
const originalFetch = globalThis.fetch;
80+
globalThis.fetch = (() => {
81+
return Promise.reject(new Error("Network error"));
82+
}) as typeof globalThis.fetch;
83+
84+
try {
85+
// Should not throw.
86+
reportNewPrompt({ enabled: true, machineId: "test-machine" });
87+
await new Promise((resolve) => setTimeout(resolve, 50));
88+
} finally {
89+
globalThis.fetch = originalFetch;
90+
}
91+
});
92+
93+
test("reportNewPrompt respects custom timeoutMs", async () => {
94+
const calls: Array<{ signal: AbortSignal }> = [];
95+
const originalFetch = globalThis.fetch;
96+
globalThis.fetch = ((_url: string | URL | Request, init?: RequestInit) => {
97+
calls.push({ signal: init?.signal as AbortSignal });
98+
return Promise.resolve(new Response());
99+
}) as typeof globalThis.fetch;
100+
101+
try {
102+
reportNewPrompt({ enabled: true, machineId: "test-machine", timeoutMs: 100 });
103+
await new Promise((resolve) => setTimeout(resolve, 50));
104+
assert.equal(calls.length, 1);
105+
assert.equal(calls[0].signal.aborted, false);
106+
} finally {
107+
globalThis.fetch = originalFetch;
108+
}
109+
});

0 commit comments

Comments
 (0)