Skip to content

Commit e8a8f6f

Browse files
authored
test(node): Cover httpIntegration outgoing request span hooks
`outgoingRequestHook`, `outgoingResponseHook` and `outgoingRequestApplyCustomAttributes` had no coverage after #23396 dropped the incoming `instrumentation.*` assertions without replacing the outgoing side. Each hook derives its attribute from the objects it is handed, so a hook wired to the wrong span, request or response fails rather than passing silently.
1 parent 9e6f6f3 commit e8a8f6f

2 files changed

Lines changed: 91 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/node');
3+
4+
const url = process.env.SERVER_URL;
5+
6+
Sentry.init({
7+
traceLifecycle: 'static',
8+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
9+
release: '1.0',
10+
tracesSampleRate: 1.0,
11+
transport: loggingTransport,
12+
13+
integrations: [
14+
Sentry.httpIntegration({
15+
// Each hook derives its attribute from the objects it is handed, so a hook that fires with
16+
// the wrong span, request or response fails the assertion rather than passing silently.
17+
outgoingRequestHook: (span, request) => {
18+
span.setAttribute('outgoingRequestHook', request.method);
19+
},
20+
outgoingResponseHook: (span, response) => {
21+
span.setAttribute('outgoingResponseHook', response.statusCode);
22+
},
23+
outgoingRequestApplyCustomAttributes: (span, request, response) => {
24+
span.setAttribute('outgoingRequestApplyCustomAttributes', `${request.method} ${response.statusCode}`);
25+
},
26+
}),
27+
],
28+
});
29+
30+
const http = require('http');
31+
32+
// express must be required after Sentry is initialized
33+
const express = require('express');
34+
const cors = require('cors');
35+
const { startExpressServerAndSendPortToRunner } = require('@sentry-internal/node-integration-tests');
36+
37+
const app = express();
38+
39+
app.use(cors());
40+
41+
app.get('/testOutgoing', (_req, response) => {
42+
makeHttpRequest(`${url}/api/users/42`).then(() => {
43+
response.send({ response: 'done' });
44+
});
45+
});
46+
47+
Sentry.setupExpressErrorHandler(app);
48+
49+
startExpressServerAndSendPortToRunner(app);
50+
51+
function makeHttpRequest(url) {
52+
return new Promise((resolve, reject) => {
53+
http
54+
.get(url, res => {
55+
res.on('data', () => {});
56+
res.on('end', () => {
57+
resolve();
58+
});
59+
})
60+
.on('error', error => {
61+
reject(error);
62+
});
63+
});
64+
}

‎dev-packages/node-integration-tests/suites/tracing/httpIntegration/test.ts‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,33 @@ describe('httpIntegration', () => {
5656
});
5757
});
5858

59+
describe('outgoing request span hooks', () => {
60+
test('runs outgoingRequestHook, outgoingResponseHook and outgoingRequestApplyCustomAttributes', async () => {
61+
const [SERVER_URL, closeTestServer] = await createTestServer()
62+
.get('/api/users/42', () => {}, 200)
63+
.start();
64+
65+
const runner = createRunner(__dirname, 'server-outgoingHooks.js')
66+
.withEnv({ SERVER_URL })
67+
.expect({
68+
transaction: event => {
69+
const clientSpans = event.spans?.filter(span => span.op === 'http.client');
70+
expect(clientSpans).toHaveLength(1);
71+
72+
// All three hooks run before the span ends, so every attribute has to survive to the envelope.
73+
const data = clientSpans![0]?.data;
74+
expect(data?.['outgoingRequestHook']).toBe('GET');
75+
expect(data?.['outgoingResponseHook']).toBe(200);
76+
expect(data?.['outgoingRequestApplyCustomAttributes']).toBe('GET 200');
77+
},
78+
})
79+
.start();
80+
runner.makeRequest('get', '/testOutgoing');
81+
await runner.completed();
82+
closeTestServer();
83+
});
84+
});
85+
5986
describe('http.server spans', () => {
6087
createEsmAndCjsTests(__dirname, 'server.mjs', 'instrument.mjs', (createRunner, test) => {
6188
test('captures correct attributes for GET requests', async () => {

0 commit comments

Comments
 (0)