From 28bbbe4f603c17ca770399f044bd8f25c2c8685f Mon Sep 17 00:00:00 2001 From: wangmiao0668000666 Date: Thu, 9 Jul 2026 13:12:24 +0800 Subject: [PATCH] fix(google-meet): bound Calendar event lookups (#102157) Co-authored-by: Peter Steinberger --- extensions/google-meet/src/calendar.test.ts | 51 +++++++++++++++++++++ extensions/google-meet/src/calendar.ts | 2 + 2 files changed, 53 insertions(+) create mode 100644 extensions/google-meet/src/calendar.test.ts diff --git a/extensions/google-meet/src/calendar.test.ts b/extensions/google-meet/src/calendar.test.ts new file mode 100644 index 000000000000..fceaa826072c --- /dev/null +++ b/extensions/google-meet/src/calendar.test.ts @@ -0,0 +1,51 @@ +// Google Meet tests cover Calendar API request behavior. +import { afterEach, describe, expect, it, vi } from "vitest"; +import { listGoogleMeetCalendarEvents } from "./calendar.js"; + +afterEach(() => { + vi.useRealTimers(); + vi.unstubAllGlobals(); +}); + +describe("Google Calendar requests", () => { + it("aborts a stalled events.list request after 30 seconds", async () => { + vi.useFakeTimers(); + const fetchMock = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => { + return new Promise((_resolve, reject) => { + const signal = init?.signal; + if (!signal) { + reject(new Error("expected Calendar request abort signal")); + return; + } + const rejectAbort = () => + reject( + signal.reason instanceof Error + ? signal.reason + : new Error("Calendar request was aborted"), + ); + if (signal.aborted) { + rejectAbort(); + return; + } + signal.addEventListener("abort", rejectAbort, { once: true }); + }); + }); + vi.stubGlobal("fetch", fetchMock); + + const request = listGoogleMeetCalendarEvents({ accessToken: "test-token" }); + const rejection = expect(request).rejects.toMatchObject({ + name: "TimeoutError", + message: "request timed out", + }); + await vi.advanceTimersByTimeAsync(0); + const signal = fetchMock.mock.calls[0]?.[1]?.signal; + expect(signal?.aborted).toBe(false); + + await vi.advanceTimersByTimeAsync(29_999); + expect(signal?.aborted).toBe(false); + + await vi.advanceTimersByTimeAsync(1); + expect(signal?.aborted).toBe(true); + await rejection; + }); +}); diff --git a/extensions/google-meet/src/calendar.ts b/extensions/google-meet/src/calendar.ts index 6a1592ab7f0e..71711494fbac 100644 --- a/extensions/google-meet/src/calendar.ts +++ b/extensions/google-meet/src/calendar.ts @@ -7,6 +7,7 @@ const GOOGLE_CALENDAR_API_BASE_URL = "https://www.googleapis.com/calendar/v3"; const GOOGLE_CALENDAR_API_HOST = "www.googleapis.com"; const GOOGLE_MEET_URL_HOST = "meet.google.com"; const GOOGLE_CALENDAR_EVENTS_SCOPE = "https://www.googleapis.com/auth/calendar.events.readonly"; +const GOOGLE_CALENDAR_REQUEST_TIMEOUT_MS = 30_000; type GoogleCalendarEventDate = { date?: string; @@ -189,6 +190,7 @@ async function fetchGoogleCalendarEvents(params: { }, policy: { allowedHostnames: [GOOGLE_CALENDAR_API_HOST] }, auditContext: "google-meet.calendar.events.list", + timeoutMs: GOOGLE_CALENDAR_REQUEST_TIMEOUT_MS, }); try { if (!response.ok) {