Skip to content

Commit b7f04da

Browse files
committed
test(gmail): narrow renewal rejection coverage
1 parent 0054629 commit b7f04da

4 files changed

Lines changed: 21 additions & 313 deletions

File tree

scripts/proof/gmail-watcher-renewal-catch.mts

Lines changed: 0 additions & 257 deletions
This file was deleted.

src/hooks/gmail-ops.test.ts

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// Foreground Gmail service tests cover `openclaw webhooks gmail run` behavior.
21
import { EventEmitter } from "node:events";
32
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
43

@@ -82,44 +81,38 @@ describe("runGmailService", () => {
8281
mocks.spawn.mockReset();
8382
});
8483

85-
afterEach(async () => {
84+
afterEach(() => {
8685
vi.useRealTimers();
87-
// Reset any leftover handlers from the previous run.
88-
vi.restoreAllMocks();
8986
});
9087

91-
it("catches renewal interval errors instead of letting them become unhandled rejections", async () => {
88+
it("logs rejected renewal commands", async () => {
9289
vi.useFakeTimers();
93-
const unhandled: unknown[] = [];
94-
const onUnhandled = (reason: unknown) => unhandled.push(reason);
95-
process.on("unhandledRejection", onUnhandled);
96-
97-
// Initial watch start succeeds; every renewal throws.
9890
mocks.runCommandWithTimeout
9991
.mockResolvedValueOnce({ code: 0, stdout: "", stderr: "" })
10092
.mockRejectedValue(new Error("renewal failed"));
10193

10294
const child = new EventEmitter();
103-
const kill = vi.fn((signal: string) => {
104-
queueMicrotask(() => child.emit("exit", null, signal));
95+
const kill = vi.fn(() => {
96+
child.emit("exit", null, "SIGTERM");
10597
return true;
10698
});
10799
mocks.spawn.mockReturnValue(Object.assign(child, { kill, killed: false }));
108100

109-
// Start the service without awaiting; it runs until we signal shutdown.
110-
const servicePromise = runGmailService({} as never);
111-
112-
// Advance one full renewal cycle to trigger the interval callback.
113-
await vi.advanceTimersByTimeAsync(720 * 60_000);
114-
115-
// Shut down so the test can finish.
116-
process.emit("SIGINT", "SIGINT");
117-
await servicePromise.catch(() => {
118-
// The service may reject on forced shutdown; we only care about unhandled rejections.
119-
});
120-
121-
process.off("unhandledRejection", onUnhandled);
122-
123-
expect(unhandled).toHaveLength(0);
101+
const existingSigintListeners = new Set(process.rawListeners("SIGINT"));
102+
let shutdown: (() => void) | undefined;
103+
try {
104+
await runGmailService({});
105+
shutdown = process
106+
.rawListeners("SIGINT")
107+
.find((listener) => !existingSigintListeners.has(listener)) as (() => void) | undefined;
108+
109+
await vi.advanceTimersByTimeAsync(720 * 60_000);
110+
111+
expect(mocks.defaultRuntime.error).toHaveBeenCalledWith(
112+
"gmail watch renew failed: Error: renewal failed",
113+
);
114+
} finally {
115+
shutdown?.();
116+
}
124117
});
125118
});

src/hooks/gmail-watcher.test.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -277,32 +277,6 @@ describe("startGmailWatcher", () => {
277277
}
278278
});
279279

280-
it("catches renewal interval errors instead of letting them become unhandled rejections", async () => {
281-
vi.useFakeTimers();
282-
const unhandled: unknown[] = [];
283-
const onUnhandled = (reason: unknown) => unhandled.push(reason);
284-
process.on("unhandledRejection", onUnhandled);
285-
try {
286-
let callCount = 0;
287-
mocks.runCommandWithTimeout.mockImplementation(async () => {
288-
callCount += 1;
289-
if (callCount === 1) {
290-
return { code: 0, stdout: "", stderr: "" };
291-
}
292-
throw new Error("renewal failed");
293-
});
294-
295-
await startGmailWatcher(createGmailConfig());
296-
// Advance one full renewal cycle to trigger the interval callback.
297-
await vi.advanceTimersByTimeAsync(720 * 60_000);
298-
299-
expect(unhandled).toHaveLength(0);
300-
} finally {
301-
process.off("unhandledRejection", onUnhandled);
302-
vi.useRealTimers();
303-
}
304-
});
305-
306280
it("escalates to SIGKILL and resolves on final timeout when process ignores signals", async () => {
307281
vi.useFakeTimers();
308282
try {

src/hooks/gmail-watcher.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,7 @@ export async function startGmailWatcher(
360360
if (shuttingDown) {
361361
return;
362362
}
363-
void startGmailWatch(runtimeConfig).catch((err: unknown) => {
364-
log.warn(`gmail watch renew failed: ${String(err)}`);
365-
});
363+
void startGmailWatch(runtimeConfig);
366364
}, renewMs);
367365

368366
log.info(

0 commit comments

Comments
 (0)