From 72f3691755d6f3374b0a68fac68012344422a067 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 14:14:57 +0000 Subject: [PATCH 1/6] test(e2e): Route all buffered events through listeners --- dev-packages/test-utils/src/event-proxy-server.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index 58c39de95c8c..64c9cec0bbfe 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -128,7 +128,7 @@ export async function startProxyServer( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const searchParams = new URL(eventCallbackRequest.url!, 'http://justsomerandombasesothattheurlisparseable.com/') .searchParams; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unused-vars const listenerTimestamp = Number(searchParams.get('timestamp')!); const callbackListener = (data: string): void => { @@ -138,9 +138,9 @@ export async function startProxyServer( eventCallbackListeners.add(callbackListener); eventBuffer.forEach(bufferedEvent => { - if (bufferedEvent.timestamp >= listenerTimestamp) { - callbackListener(bufferedEvent.data); - } + // if (bufferedEvent.timestamp >= listenerTimestamp) { + callbackListener(bufferedEvent.data); + // } }); eventCallbackRequest.on('close', () => { From 90636bc17ccec6d3f0b0f515f709868de8f0e202 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 14:42:11 +0000 Subject: [PATCH 2/6] simplify --- .../aws-serverless-esm/start-event-proxy.mjs | 1 - .../test-utils/src/event-proxy-server.ts | 307 ++++++------------ 2 files changed, 107 insertions(+), 201 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs index e74f395b6237..86605fcb7b9a 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs +++ b/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs @@ -3,5 +3,4 @@ import { startEventProxyServer } from '@sentry-internal/test-utils'; startEventProxyServer({ port: 3031, proxyServerName: 'aws-serverless-esm', - forwardToSentry: false, }); diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index 64c9cec0bbfe..5f25dfa38174 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -1,5 +1,3 @@ -/* eslint-disable max-lines */ - import * as fs from 'fs'; import * as http from 'http'; import type { AddressInfo } from 'net'; @@ -18,11 +16,6 @@ interface EventProxyServerOptions { port: number; /** The name for the proxy server used for referencing it with listener functions */ proxyServerName: string; - /** - * Whether or not to forward the event to sentry. @default `false` - * This is helpful when you can't register a tunnel in the SDK setup (e.g. lambda layer without Sentry.init call) - */ - forwardToSentry?: boolean; } interface SentryRequestCallbackData { @@ -36,15 +29,18 @@ interface EventCallbackListener { (data: string): void; } +type SentryResponseStatusCode = number; +type SentryResponseBody = string; +type SentryResponseHeaders = Record | undefined; + type OnRequest = ( eventCallbackListeners: Set, proxyRequest: http.IncomingMessage, proxyRequestBody: string, eventBuffer: BufferedEvent[], -) => Promise<[number, string, Record | undefined]>; +) => Promise<[SentryResponseStatusCode, SentryResponseBody, SentryResponseHeaders]>; interface BufferedEvent { - timestamp: number; data: string; } @@ -90,7 +86,7 @@ export async function startProxyServer( const callback: OnRequest = onRequest || (async (eventCallbackListeners, proxyRequest, proxyRequestBody, eventBuffer) => { - eventBuffer.push({ data: proxyRequestBody, timestamp: getNanosecondTimestamp() }); + eventBuffer.push({ data: proxyRequestBody }); eventCallbackListeners.forEach(listener => { listener(proxyRequestBody); @@ -125,12 +121,6 @@ export async function startProxyServer( eventCallbackResponse.statusCode = 200; eventCallbackResponse.setHeader('connection', 'keep-alive'); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const searchParams = new URL(eventCallbackRequest.url!, 'http://justsomerandombasesothattheurlisparseable.com/') - .searchParams; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unused-vars - const listenerTimestamp = Number(searchParams.get('timestamp')!); - const callbackListener = (data: string): void => { eventCallbackResponse.write(data.concat('\n'), 'utf8'); }; @@ -138,9 +128,7 @@ export async function startProxyServer( eventCallbackListeners.add(callbackListener); eventBuffer.forEach(bufferedEvent => { - // if (bufferedEvent.timestamp >= listenerTimestamp) { callbackListener(bufferedEvent.data); - // } }); eventCallbackRequest.on('close', () => { @@ -172,9 +160,7 @@ export async function startEventProxyServer(options: EventProxyServerOptions): P await startProxyServer(options, async (eventCallbackListeners, proxyRequest, proxyRequestBody, eventBuffer) => { const envelopeHeader: EnvelopeItem[0] = JSON.parse(proxyRequestBody.split('\n')[0] as string); - const shouldForwardEventToSentry = options.forwardToSentry || false; - - if (!envelopeHeader.dsn && shouldForwardEventToSentry) { + if (!envelopeHeader.dsn) { // eslint-disable-next-line no-console console.log( '[event-proxy-server] Warn: No dsn on envelope header. Maybe a client-report was received. Proxy request body:', @@ -184,69 +170,28 @@ export async function startEventProxyServer(options: EventProxyServerOptions): P return [200, '{}', {}]; } - if (!shouldForwardEventToSentry) { - const data: SentryRequestCallbackData = { - envelope: parseEnvelope(proxyRequestBody), - rawProxyRequestBody: proxyRequestBody, - rawSentryResponseBody: '', - sentryResponseStatusCode: 200, - }; - eventCallbackListeners.forEach(listener => { - listener(Buffer.from(JSON.stringify(data)).toString('base64')); - }); - - return [ - 200, - '{}', - { - 'Access-Control-Allow-Origin': '*', - }, - ]; - } - - const { origin, pathname, host } = new URL(envelopeHeader.dsn as string); - - const projectId = pathname.substring(1); - const sentryIngestUrl = `${origin}/api/${projectId}/envelope/`; - - proxyRequest.headers.host = host; - - const reqHeaders: Record = {}; - for (const [key, value] of Object.entries(proxyRequest.headers)) { - reqHeaders[key] = value as string; - } - - // Fetch does not like this - delete reqHeaders['transfer-encoding']; - - return fetch(sentryIngestUrl, { - body: proxyRequestBody, - headers: reqHeaders, - method: proxyRequest.method, - }).then(async res => { - const rawSentryResponseBody = await res.text(); - const data: SentryRequestCallbackData = { - envelope: parseEnvelope(proxyRequestBody), - rawProxyRequestBody: proxyRequestBody, - rawSentryResponseBody, - sentryResponseStatusCode: res.status, - }; - - const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - - eventBuffer.push({ data: dataString, timestamp: getNanosecondTimestamp() }); + const data: SentryRequestCallbackData = { + envelope: parseEnvelope(proxyRequestBody), + rawProxyRequestBody: proxyRequestBody, + rawSentryResponseBody: '', + sentryResponseStatusCode: 200, + }; - eventCallbackListeners.forEach(listener => { - listener(dataString); - }); + const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - const resHeaders: Record = {}; - for (const [key, value] of res.headers.entries()) { - resHeaders[key] = value; - } + eventBuffer.push({ data: dataString }); - return [res.status, rawSentryResponseBody, resHeaders]; + eventCallbackListeners.forEach(listener => { + listener(dataString); }); + + return [ + 200, + '{}', + { + 'Access-Control-Allow-Origin': '*', + }, + ]; }); } @@ -258,28 +203,24 @@ export async function waitForPlainRequest( const eventCallbackServerPort = await retrieveCallbackServerPort(proxyServerName); return new Promise((resolve, reject) => { - const request = http.request( - `http://localhost:${eventCallbackServerPort}/?timestamp=${getNanosecondTimestamp()}`, - {}, - response => { - let eventContents = ''; - - response.on('error', err => { - reject(err); - }); + const request = http.request(`http://localhost:${eventCallbackServerPort}/`, {}, response => { + let eventContents = ''; - response.on('data', (chunk: Buffer) => { - const chunkString = chunk.toString('utf8'); + response.on('error', err => { + reject(err); + }); - eventContents = eventContents.concat(chunkString); + response.on('data', (chunk: Buffer) => { + const chunkString = chunk.toString('utf8'); - if (callback(eventContents)) { - response.destroy(); - return resolve(eventContents); - } - }); - }, - ); + eventContents = eventContents.concat(chunkString); + + if (callback(eventContents)) { + response.destroy(); + return resolve(eventContents); + } + }); + }); request.end(); }); @@ -289,53 +230,48 @@ export async function waitForPlainRequest( export async function waitForRequest( proxyServerName: string, callback: (eventData: SentryRequestCallbackData) => Promise | boolean, - timestamp: number = getNanosecondTimestamp(), ): Promise { const eventCallbackServerPort = await retrieveCallbackServerPort(proxyServerName); return new Promise((resolve, reject) => { - const request = http.request( - `http://localhost:${eventCallbackServerPort}/?timestamp=${timestamp}`, - {}, - response => { - let eventContents = ''; - - response.on('error', err => { - reject(err); - }); + const request = http.request(`http://localhost:${eventCallbackServerPort}/`, {}, response => { + let eventContents = ''; + + response.on('error', err => { + reject(err); + }); - response.on('data', (chunk: Buffer) => { - const chunkString = chunk.toString('utf8'); - chunkString.split('').forEach(char => { - if (char === '\n') { - const eventCallbackData: SentryRequestCallbackData = JSON.parse( - Buffer.from(eventContents, 'base64').toString('utf8'), + response.on('data', (chunk: Buffer) => { + const chunkString = chunk.toString('utf8'); + chunkString.split('').forEach(char => { + if (char === '\n') { + const eventCallbackData: SentryRequestCallbackData = JSON.parse( + Buffer.from(eventContents, 'base64').toString('utf8'), + ); + const callbackResult = callback(eventCallbackData); + if (typeof callbackResult !== 'boolean') { + callbackResult.then( + match => { + if (match) { + response.destroy(); + resolve(eventCallbackData); + } + }, + err => { + throw err; + }, ); - const callbackResult = callback(eventCallbackData); - if (typeof callbackResult !== 'boolean') { - callbackResult.then( - match => { - if (match) { - response.destroy(); - resolve(eventCallbackData); - } - }, - err => { - throw err; - }, - ); - } else if (callbackResult) { - response.destroy(); - resolve(eventCallbackData); - } - eventContents = ''; - } else { - eventContents = eventContents.concat(char); + } else if (callbackResult) { + response.destroy(); + resolve(eventCallbackData); } - }); + eventContents = ''; + } else { + eventContents = eventContents.concat(char); + } }); - }, - ); + }); + }); request.end(); }); @@ -345,23 +281,18 @@ export async function waitForRequest( export function waitForEnvelopeItem( proxyServerName: string, callback: (envelopeItem: EnvelopeItem) => Promise | boolean, - timestamp: number = getNanosecondTimestamp(), ): Promise { return new Promise((resolve, reject) => { - waitForRequest( - proxyServerName, - async eventData => { - const envelopeItems = eventData.envelope[1]; - for (const envelopeItem of envelopeItems) { - if (await callback(envelopeItem)) { - resolve(envelopeItem); - return true; - } + waitForRequest(proxyServerName, async eventData => { + const envelopeItems = eventData.envelope[1]; + for (const envelopeItem of envelopeItems) { + if (await callback(envelopeItem)) { + resolve(envelopeItem); + return true; } - return false; - }, - timestamp, - ).catch(reject); + } + return false; + }).catch(reject); }); } @@ -370,20 +301,15 @@ export function waitForError( proxyServerName: string, callback: (errorEvent: Event) => Promise | boolean, ): Promise { - const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem( - proxyServerName, - async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); - return true; - } - return false; - }, - timestamp, - ).catch(reject); + waitForEnvelopeItem(proxyServerName, async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as Event))) { + resolve(envelopeItemBody as Event); + return true; + } + return false; + }).catch(reject); }); } @@ -392,20 +318,15 @@ export function waitForSession( proxyServerName: string, callback: (session: SerializedSession) => Promise | boolean, ): Promise { - const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem( - proxyServerName, - async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'session' && (await callback(envelopeItemBody as SerializedSession))) { - resolve(envelopeItemBody as SerializedSession); - return true; - } - return false; - }, - timestamp, - ).catch(reject); + waitForEnvelopeItem(proxyServerName, async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'session' && (await callback(envelopeItemBody as SerializedSession))) { + resolve(envelopeItemBody as SerializedSession); + return true; + } + return false; + }).catch(reject); }); } @@ -414,20 +335,15 @@ export function waitForTransaction( proxyServerName: string, callback: (transactionEvent: Event) => Promise | boolean, ): Promise { - const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem( - proxyServerName, - async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); - return true; - } - return false; - }, - timestamp, - ).catch(reject); + waitForEnvelopeItem(proxyServerName, async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as Event))) { + resolve(envelopeItemBody as Event); + return true; + } + return false; + }).catch(reject); }); } @@ -448,12 +364,3 @@ async function retrieveCallbackServerPort(serverName: string): Promise { throw e; } } - -/** - * We do nanosecond checking because the waitFor* calls and the fetch requests may come very shortly after one another. - */ -function getNanosecondTimestamp(): number { - const NS_PER_SEC = 1e9; - const [seconds, nanoseconds] = process.hrtime(); - return seconds * NS_PER_SEC + nanoseconds; -} From 918a0641f44be1ca7daa4def5b6b7bf53b21f0cb Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 15:22:48 +0000 Subject: [PATCH 3/6] parallelize test registry publish --- dev-packages/e2e-tests/publish-packages.ts | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dev-packages/e2e-tests/publish-packages.ts b/dev-packages/e2e-tests/publish-packages.ts index 2be19b173bd3..408d046977a2 100644 --- a/dev-packages/e2e-tests/publish-packages.ts +++ b/dev-packages/e2e-tests/publish-packages.ts @@ -13,9 +13,22 @@ const packageTarballPaths = glob.sync('packages/*/sentry-*.tgz', { // Publish built packages to the fake registry packageTarballPaths.forEach(tarballPath => { // `--userconfig` flag needs to be before `publish` - childProcess.execSync(`npm --userconfig ${__dirname}/test-registry.npmrc publish ${tarballPath}`, { - cwd: repositoryRoot, // Can't use __dirname here because npm would try to publish `@sentry-internal/e2e-tests` - encoding: 'utf8', - stdio: 'inherit', - }); + childProcess.exec( + `npm --userconfig ${__dirname}/test-registry.npmrc publish ${tarballPath}`, + { + cwd: repositoryRoot, // Can't use __dirname here because npm would try to publish `@sentry-internal/e2e-tests` + encoding: 'utf8', + }, + (err, stdout, stderr) => { + // eslint-disable-next-line no-console + console.log(stdout); + // eslint-disable-next-line no-console + console.log(stderr); + if (err) { + // eslint-disable-next-line no-console + console.error(err); + process.exit(1); + } + }, + ); }); From fb068d3497101c7bcb709c1e44e46a70c4061c3c Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 15:25:00 +0000 Subject: [PATCH 4/6] yeet --- .../test-utils/src/event-proxy-server.ts | 220 +++++++++++------- 1 file changed, 134 insertions(+), 86 deletions(-) diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index 5f25dfa38174..c8e444ddc2e8 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-lines */ import * as fs from 'fs'; import * as http from 'http'; import type { AddressInfo } from 'net'; @@ -41,6 +42,7 @@ type OnRequest = ( ) => Promise<[SentryResponseStatusCode, SentryResponseBody, SentryResponseHeaders]>; interface BufferedEvent { + timestamp: number; data: string; } @@ -86,7 +88,7 @@ export async function startProxyServer( const callback: OnRequest = onRequest || (async (eventCallbackListeners, proxyRequest, proxyRequestBody, eventBuffer) => { - eventBuffer.push({ data: proxyRequestBody }); + eventBuffer.push({ data: proxyRequestBody, timestamp: getNanosecondTimestamp() }); eventCallbackListeners.forEach(listener => { listener(proxyRequestBody); @@ -121,6 +123,12 @@ export async function startProxyServer( eventCallbackResponse.statusCode = 200; eventCallbackResponse.setHeader('connection', 'keep-alive'); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const searchParams = new URL(eventCallbackRequest.url!, 'http://justsomerandombasesothattheurlisparseable.com/') + .searchParams; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const listenerTimestamp = Number(searchParams.get('timestamp')!); + const callbackListener = (data: string): void => { eventCallbackResponse.write(data.concat('\n'), 'utf8'); }; @@ -128,7 +136,9 @@ export async function startProxyServer( eventCallbackListeners.add(callbackListener); eventBuffer.forEach(bufferedEvent => { - callbackListener(bufferedEvent.data); + if (bufferedEvent.timestamp >= listenerTimestamp) { + callbackListener(bufferedEvent.data); + } }); eventCallbackRequest.on('close', () => { @@ -179,7 +189,7 @@ export async function startEventProxyServer(options: EventProxyServerOptions): P const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - eventBuffer.push({ data: dataString }); + eventBuffer.push({ data: dataString, timestamp: getNanosecondTimestamp() }); eventCallbackListeners.forEach(listener => { listener(dataString); @@ -203,24 +213,28 @@ export async function waitForPlainRequest( const eventCallbackServerPort = await retrieveCallbackServerPort(proxyServerName); return new Promise((resolve, reject) => { - const request = http.request(`http://localhost:${eventCallbackServerPort}/`, {}, response => { - let eventContents = ''; - - response.on('error', err => { - reject(err); - }); + const request = http.request( + `http://localhost:${eventCallbackServerPort}/?timestamp=${getNanosecondTimestamp()}`, + {}, + response => { + let eventContents = ''; + + response.on('error', err => { + reject(err); + }); - response.on('data', (chunk: Buffer) => { - const chunkString = chunk.toString('utf8'); + response.on('data', (chunk: Buffer) => { + const chunkString = chunk.toString('utf8'); - eventContents = eventContents.concat(chunkString); + eventContents = eventContents.concat(chunkString); - if (callback(eventContents)) { - response.destroy(); - return resolve(eventContents); - } - }); - }); + if (callback(eventContents)) { + response.destroy(); + return resolve(eventContents); + } + }); + }, + ); request.end(); }); @@ -230,48 +244,53 @@ export async function waitForPlainRequest( export async function waitForRequest( proxyServerName: string, callback: (eventData: SentryRequestCallbackData) => Promise | boolean, + timestamp: number = getNanosecondTimestamp(), ): Promise { const eventCallbackServerPort = await retrieveCallbackServerPort(proxyServerName); return new Promise((resolve, reject) => { - const request = http.request(`http://localhost:${eventCallbackServerPort}/`, {}, response => { - let eventContents = ''; - - response.on('error', err => { - reject(err); - }); - - response.on('data', (chunk: Buffer) => { - const chunkString = chunk.toString('utf8'); - chunkString.split('').forEach(char => { - if (char === '\n') { - const eventCallbackData: SentryRequestCallbackData = JSON.parse( - Buffer.from(eventContents, 'base64').toString('utf8'), - ); - const callbackResult = callback(eventCallbackData); - if (typeof callbackResult !== 'boolean') { - callbackResult.then( - match => { - if (match) { - response.destroy(); - resolve(eventCallbackData); - } - }, - err => { - throw err; - }, + const request = http.request( + `http://localhost:${eventCallbackServerPort}/?timestamp=${timestamp}`, + {}, + response => { + let eventContents = ''; + + response.on('error', err => { + reject(err); + }); + + response.on('data', (chunk: Buffer) => { + const chunkString = chunk.toString('utf8'); + chunkString.split('').forEach(char => { + if (char === '\n') { + const eventCallbackData: SentryRequestCallbackData = JSON.parse( + Buffer.from(eventContents, 'base64').toString('utf8'), ); - } else if (callbackResult) { - response.destroy(); - resolve(eventCallbackData); + const callbackResult = callback(eventCallbackData); + if (typeof callbackResult !== 'boolean') { + callbackResult.then( + match => { + if (match) { + response.destroy(); + resolve(eventCallbackData); + } + }, + err => { + throw err; + }, + ); + } else if (callbackResult) { + response.destroy(); + resolve(eventCallbackData); + } + eventContents = ''; + } else { + eventContents = eventContents.concat(char); } - eventContents = ''; - } else { - eventContents = eventContents.concat(char); - } + }); }); - }); - }); + }, + ); request.end(); }); @@ -281,18 +300,23 @@ export async function waitForRequest( export function waitForEnvelopeItem( proxyServerName: string, callback: (envelopeItem: EnvelopeItem) => Promise | boolean, + timestamp: number = getNanosecondTimestamp(), ): Promise { return new Promise((resolve, reject) => { - waitForRequest(proxyServerName, async eventData => { - const envelopeItems = eventData.envelope[1]; - for (const envelopeItem of envelopeItems) { - if (await callback(envelopeItem)) { - resolve(envelopeItem); - return true; + waitForRequest( + proxyServerName, + async eventData => { + const envelopeItems = eventData.envelope[1]; + for (const envelopeItem of envelopeItems) { + if (await callback(envelopeItem)) { + resolve(envelopeItem); + return true; + } } - } - return false; - }).catch(reject); + return false; + }, + timestamp, + ).catch(reject); }); } @@ -301,15 +325,20 @@ export function waitForError( proxyServerName: string, callback: (errorEvent: Event) => Promise | boolean, ): Promise { + const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem(proxyServerName, async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); - return true; - } - return false; - }).catch(reject); + waitForEnvelopeItem( + proxyServerName, + async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'event' && (await callback(envelopeItemBody as Event))) { + resolve(envelopeItemBody as Event); + return true; + } + return false; + }, + timestamp, + ).catch(reject); }); } @@ -318,15 +347,20 @@ export function waitForSession( proxyServerName: string, callback: (session: SerializedSession) => Promise | boolean, ): Promise { + const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem(proxyServerName, async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'session' && (await callback(envelopeItemBody as SerializedSession))) { - resolve(envelopeItemBody as SerializedSession); - return true; - } - return false; - }).catch(reject); + waitForEnvelopeItem( + proxyServerName, + async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'session' && (await callback(envelopeItemBody as SerializedSession))) { + resolve(envelopeItemBody as SerializedSession); + return true; + } + return false; + }, + timestamp, + ).catch(reject); }); } @@ -335,15 +369,20 @@ export function waitForTransaction( proxyServerName: string, callback: (transactionEvent: Event) => Promise | boolean, ): Promise { + const timestamp = getNanosecondTimestamp(); return new Promise((resolve, reject) => { - waitForEnvelopeItem(proxyServerName, async envelopeItem => { - const [envelopeItemHeader, envelopeItemBody] = envelopeItem; - if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as Event))) { - resolve(envelopeItemBody as Event); - return true; - } - return false; - }).catch(reject); + waitForEnvelopeItem( + proxyServerName, + async envelopeItem => { + const [envelopeItemHeader, envelopeItemBody] = envelopeItem; + if (envelopeItemHeader.type === 'transaction' && (await callback(envelopeItemBody as Event))) { + resolve(envelopeItemBody as Event); + return true; + } + return false; + }, + timestamp, + ).catch(reject); }); } @@ -364,3 +403,12 @@ async function retrieveCallbackServerPort(serverName: string): Promise { throw e; } } + +/** + * We do nanosecond checking because the waitFor* calls and the fetch requests may come very shortly after one another. + */ +function getNanosecondTimestamp(): number { + const NS_PER_SEC = 1e9; + const [seconds, nanoseconds] = process.hrtime(); + return seconds * NS_PER_SEC + nanoseconds; +} From da65cc060c9b84012f696730c0c338394fbcbca1 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 15:29:54 +0000 Subject: [PATCH 5/6] fast --- dev-packages/e2e-tests/Dockerfile.publish-packages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/Dockerfile.publish-packages b/dev-packages/e2e-tests/Dockerfile.publish-packages index 4d5b2ba3abf3..88fd7f116728 100644 --- a/dev-packages/e2e-tests/Dockerfile.publish-packages +++ b/dev-packages/e2e-tests/Dockerfile.publish-packages @@ -3,4 +3,4 @@ ARG NODE_VERSION=18.18.0 FROM node:${NODE_VERSION} WORKDIR /sentry-javascript/dev-packages/e2e-tests -CMD [ "yarn", "ts-node", "publish-packages.ts" ] +CMD [ "yarn", "ts-node", "publish-packages.ts", "--transpile-only" ] From ba0cd815dcf57e3f2d7b616c0200c9233ee50e71 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 15:48:06 +0000 Subject: [PATCH 6/6] remove last bit of funkyness --- dev-packages/test-utils/src/event-proxy-server.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index c8e444ddc2e8..17922a4f90aa 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -168,18 +168,6 @@ export async function startProxyServer( */ export async function startEventProxyServer(options: EventProxyServerOptions): Promise { await startProxyServer(options, async (eventCallbackListeners, proxyRequest, proxyRequestBody, eventBuffer) => { - const envelopeHeader: EnvelopeItem[0] = JSON.parse(proxyRequestBody.split('\n')[0] as string); - - if (!envelopeHeader.dsn) { - // eslint-disable-next-line no-console - console.log( - '[event-proxy-server] Warn: No dsn on envelope header. Maybe a client-report was received. Proxy request body:', - proxyRequestBody, - ); - - return [200, '{}', {}]; - } - const data: SentryRequestCallbackData = { envelope: parseEnvelope(proxyRequestBody), rawProxyRequestBody: proxyRequestBody,