Skip to content

Commit

Permalink
test: add e2e test for stream timeouts
Browse files Browse the repository at this point in the history
  • Loading branch information
chargome authored and mydea committed Jul 24, 2024
1 parent b44e053 commit 83a6ae9
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const wait = time => {
});
};

async function eventsHandler(request, response) {
async function sseHandler(request, response, timeout = false) {
response.headers = {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
Expand All @@ -30,12 +30,17 @@ async function eventsHandler(request, response) {

for (let index = 0; index < 10; index++) {
response.write(`data: ${new Date().toISOString()}\n\n`);
if (timeout) {
await wait(10000);
}
}

response.end();
}

app.get('/sse', eventsHandler);
app.get('/sse', (req, res) => sseHandler(req, res));

app.get('/sse-timeout', (req, res) => sseHandler(req, res, true));

app.listen(PORT, () => {
console.log(`SSE service listening at http://localhost:${PORT}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import * as Sentry from '@sentry/react';
// biome-ignore lint/nursery/noUnusedImports: Need React import for JSX
import * as React from 'react';

const fetchSSE = async () => {
const fetchSSE = async ({ timeout }: { timeout: boolean }) => {
Sentry.startSpanManual({ name: 'sse stream using fetch' }, async span => {
const res = await Sentry.startSpan({ name: 'sse fetch call' }, async () => {
return await fetch('http://localhost:8080/sse');
const endpoint = `http://localhost:8080/${timeout ? 'sse-timeout' : 'sse'}`;
return await fetch(endpoint);
});

const stream = res.body;
Expand Down Expand Up @@ -34,9 +35,14 @@ const fetchSSE = async () => {

const SSE = () => {
return (
<button id="fetch-button" onClick={fetchSSE}>
Fetch SSE
</button>
<>
<button id="fetch-button" onClick={() => fetchSSE({ timeout: false })}>
Fetch SSE
</button>
<button id="fetch-timeout-button" onClick={() => fetchSSE({ timeout: true })}>
Fetch timeout SSE
</button>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,37 @@ test('Waits for sse streaming when creating spans', async ({ page }) => {
expect(resolveDuration).toBe(0);
expect(resolveBodyDuration).toBe(2);
});

test('Aborts when stream takes longer than 5s', async ({ page }) => {
await page.goto('/sse');

const transactionPromise = waitForTransaction('react-router-6', async transactionEvent => {
return !!transactionEvent?.transaction && transactionEvent.contexts?.trace?.op === 'pageload';
});

const fetchButton = page.locator('id=fetch-timeout-button');
await fetchButton.click();

const rootSpan = await transactionPromise;
const sseFetchCall = rootSpan.spans?.filter(span => span.description === 'sse fetch call')[0] as SpanJSON;
const httpGet = rootSpan.spans?.filter(
span => span.description === 'GET http://localhost:8080/sse-timeout',
)[0] as SpanJSON;

expect(sseFetchCall).not.toBeUndefined();
expect(httpGet).not.toBeUndefined();

expect(sseFetchCall?.timestamp).not.toBeUndefined();
expect(sseFetchCall?.start_timestamp).not.toBeUndefined();
expect(httpGet?.timestamp).not.toBeUndefined();
expect(httpGet?.start_timestamp).not.toBeUndefined();

// http headers get sent instantly from the server
const resolveDuration = Math.round((sseFetchCall.timestamp as number) - sseFetchCall.start_timestamp);

// body streams after 10s but client should abort reading after 5s
const resolveBodyDuration = Math.round((httpGet.timestamp as number) - httpGet.start_timestamp);

expect(resolveDuration).toBe(0);
expect(resolveBodyDuration).toBe(7);
});

0 comments on commit 83a6ae9

Please sign in to comment.