From ea20c21b157edd0912313228ea22199895a5a3b8 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 19:25:39 +0200 Subject: [PATCH] test(e2e): Fix event buffering (#13233) --- .../e2e-tests/Dockerfile.publish-packages | 2 +- dev-packages/e2e-tests/publish-packages.ts | 23 +++- .../aws-serverless-esm/start-event-proxy.mjs | 1 - .../test-utils/src/event-proxy-server.ts | 103 ++++-------------- 4 files changed, 42 insertions(+), 87 deletions(-) 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" ] 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); + } + }, + ); }); 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 58c39de95c8c..17922a4f90aa 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -1,5 +1,4 @@ /* eslint-disable max-lines */ - import * as fs from 'fs'; import * as http from 'http'; import type { AddressInfo } from 'net'; @@ -18,11 +17,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,12 +30,16 @@ 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; @@ -170,83 +168,28 @@ 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); + const data: SentryRequestCallbackData = { + envelope: parseEnvelope(proxyRequestBody), + rawProxyRequestBody: proxyRequestBody, + rawSentryResponseBody: '', + sentryResponseStatusCode: 200, + }; - const shouldForwardEventToSentry = options.forwardToSentry || false; + const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - if (!envelopeHeader.dsn && shouldForwardEventToSentry) { - // 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, '{}', {}]; - } - - 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() }); - - eventCallbackListeners.forEach(listener => { - listener(dataString); - }); - - const resHeaders: Record = {}; - for (const [key, value] of res.headers.entries()) { - resHeaders[key] = value; - } + eventBuffer.push({ data: dataString, timestamp: getNanosecondTimestamp() }); - return [res.status, rawSentryResponseBody, resHeaders]; + eventCallbackListeners.forEach(listener => { + listener(dataString); }); + + return [ + 200, + '{}', + { + 'Access-Control-Allow-Origin': '*', + }, + ]; }); }