-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cloudflare): instrument scheduled handler
- Loading branch information
1 parent
e3af1ce
commit 1482a37
Showing
5 changed files
with
193 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,7 @@ const MOCK_ENV = { | |
SENTRY_DSN: 'https://[email protected]/1337', | ||
}; | ||
|
||
describe('withSentry', () => { | ||
describe('withSentry fetch handler', () => { | ||
beforeEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
@@ -76,9 +76,8 @@ describe('withSentry', () => { | |
}, | ||
} satisfies ExportedHandler; | ||
|
||
const context = createMockExecutionContext(); | ||
const wrappedHandler = withSentry(() => ({}), handler); | ||
await wrappedHandler.fetch(new Request('https://example.com'), MOCK_ENV, context); | ||
await wrappedHandler.fetch(new Request('https://example.com'), MOCK_ENV, createMockExecutionContext()); | ||
|
||
expect(initAndBindSpy).toHaveBeenCalledTimes(1); | ||
expect(initAndBindSpy).toHaveBeenLastCalledWith(CloudflareClient, expect.any(Object)); | ||
|
@@ -295,6 +294,87 @@ describe('withSentry', () => { | |
}); | ||
}); | ||
|
||
describe('withSentry scheduled handler', () => { | ||
const MOCK_SCHEDULED_CONTROLLER: ScheduledController = { | ||
scheduledTime: 123, | ||
cron: '0 0 * * *', | ||
noRetry: vi.fn(), | ||
}; | ||
|
||
test('gets env from handler', async () => { | ||
const handler = { | ||
scheduled(_controller, _env, context) { | ||
context.waitUntil(Promise.resolve()); | ||
}, | ||
} satisfies ExportedHandler; | ||
|
||
const optionsCallback = vi.fn().mockReturnValue({}); | ||
|
||
const wrappedHandler = withSentry(optionsCallback, handler); | ||
await wrappedHandler.scheduled(MOCK_SCHEDULED_CONTROLLER, MOCK_ENV, createMockExecutionContext()); | ||
|
||
expect(optionsCallback).toHaveBeenCalledTimes(1); | ||
expect(optionsCallback).toHaveBeenLastCalledWith(MOCK_ENV); | ||
}); | ||
|
||
test('flushes the event after the handler is done using the cloudflare context.waitUntil', async () => { | ||
const handler = { | ||
scheduled(_controller, _env, _context) { | ||
// empty | ||
}, | ||
} satisfies ExportedHandler; | ||
|
||
const context = createMockExecutionContext(); | ||
const wrappedHandler = withSentry(() => ({}), handler); | ||
await wrappedHandler.scheduled(MOCK_SCHEDULED_CONTROLLER, MOCK_ENV, context); | ||
|
||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(context.waitUntil).toHaveBeenCalledTimes(1); | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
expect(context.waitUntil).toHaveBeenLastCalledWith(expect.any(Promise)); | ||
}); | ||
|
||
test('creates a cloudflare client and sets it on the handler', async () => { | ||
const initAndBindSpy = vi.spyOn(SentryCore, 'initAndBind'); | ||
const handler = { | ||
scheduled(_controller, _env, context) { | ||
context.waitUntil(Promise.resolve()); | ||
}, | ||
} satisfies ExportedHandler; | ||
|
||
const wrappedHandler = withSentry(() => ({}), handler); | ||
await wrappedHandler.scheduled(MOCK_SCHEDULED_CONTROLLER, MOCK_ENV, createMockExecutionContext()); | ||
|
||
expect(initAndBindSpy).toHaveBeenCalledTimes(1); | ||
expect(initAndBindSpy).toHaveBeenLastCalledWith(CloudflareClient, expect.any(Object)); | ||
}); | ||
|
||
describe('scope instrumentation', () => { | ||
test('adds cloud resource context', async () => { | ||
const handler = { | ||
scheduled(_controller, _env, context) { | ||
SentryCore.captureMessage('test'); | ||
context.waitUntil(Promise.resolve()); | ||
}, | ||
} satisfies ExportedHandler; | ||
|
||
let sentryEvent: Event = {}; | ||
const wrappedHandler = withSentry( | ||
(env: any) => ({ | ||
dsn: env.MOCK_DSN, | ||
beforeSend(event) { | ||
sentryEvent = event; | ||
return null; | ||
}, | ||
}), | ||
handler, | ||
); | ||
await wrappedHandler.scheduled(MOCK_SCHEDULED_CONTROLLER, MOCK_ENV, createMockExecutionContext()); | ||
expect(sentryEvent.contexts?.cloud_resource).toEqual({ 'cloud.provider': 'cloudflare' }); | ||
}); | ||
}); | ||
}); | ||
|
||
function createMockExecutionContext(): ExecutionContext { | ||
return { | ||
waitUntil: vi.fn(), | ||
|