Skip to content

Commit e3b4662

Browse files
committed
ci: smoke test setTraceAttributes
1 parent 4a9441f commit e3b4662

File tree

4 files changed

+469
-2
lines changed

4 files changed

+469
-2
lines changed

Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,13 @@ smoke-sdk-http-ts-programmaticImports: build-smoke-images smoke-tests/collector/
3939
@echo ""
4040
cd smoke-tests && bats ./smoke-sdk-http-ts-programmaticImports.bats --report-formatter junit --output ./ --verbose-run
4141

42-
smoke-sdk: smoke-sdk-http-ts smoke-sdk-grpc-ts
42+
smoke-setTraceAttributes: build-smoke-images smoke-tests/collector/data.json
43+
@echo ""
44+
@echo "+++ Running setTraceAttributes smoke tests for TypeScript."
45+
@echo ""
46+
cd smoke-tests && bats ./smoke-setTraceAttributes.bats --report-formatter junit --output ./ --verbose-run
47+
48+
smoke-sdk: smoke-sdk-http-ts smoke-sdk-grpc-ts smoke-setTraceAttributes
4349

4450
smoke: docker_compose_present
4551
@echo ""
@@ -56,7 +62,7 @@ unsmoke: docker_compose_present
5662
#: use this for local smoke testing
5763
resmoke: unsmoke smoke
5864

59-
.PHONY: clean-smoke-tests build-smoke-images example smoke unsmoke resmoke smoke-sdk-grpc-ts smoke-sdk-http-ts smoke-sdk-http-ts-programmaticImports smoke-sdk
65+
.PHONY: clean-smoke-tests build-smoke-images example smoke unsmoke resmoke smoke-sdk-grpc-ts smoke-sdk-http-ts smoke-sdk-http-ts-programmaticImports smoke-setTraceAttributes smoke-sdk
6066

6167
.PHONY: docker_compose_present
6268
docker_compose_present:

smoke-tests/hello-node-express-ts/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,49 @@ You can now curl the app:
3434
curl localhost:3000
3535
Hello, World!
3636
```
37+
38+
### Testing setTraceAttributes API
39+
40+
A comprehensive smoke test endpoint is available at `/test-trace-attributes` that tests various scenarios for the `setTraceAttributes` API.
41+
42+
#### Manual testing
43+
44+
```bash
45+
curl localhost:3000/test-trace-attributes
46+
```
47+
48+
#### Automated smoke tests with BATS
49+
50+
Run the complete BATS smoke test suite (includes Docker Compose setup):
51+
52+
```bash
53+
# From the root of the repository
54+
make smoke-setTraceAttributes
55+
56+
# Or run all smoke tests including setTraceAttributes
57+
make smoke-sdk
58+
```
59+
60+
These tests will:
61+
- Build Docker images for the app
62+
- Start the collector and app containers
63+
- Execute the `/test-trace-attributes` endpoint
64+
- Verify that trace attributes are correctly captured in telemetry data
65+
- Check attribute isolation between concurrent spans
66+
- Validate attribute types and special characters
67+
68+
#### Test coverage
69+
70+
This endpoint tests:
71+
1. **Basic attribute setting** - Simple string attributes
72+
2. **Multiple attribute types** - Strings, numbers, booleans, and arrays
73+
3. **Nested spans** - Attributes in parent, child, and grandchild spans
74+
4. **Overwriting attributes** - Setting the same key multiple times
75+
5. **Special characters** - Keys with dots, hyphens, and spaces
76+
6. **Empty attributes** - Empty objects
77+
7. **Large number of attributes** - 50+ attributes
78+
8. **Concurrent spans** - Multiple concurrent spans with different attributes
79+
9. **Async operations** - Attributes before and after async operations
80+
10. **Null/undefined values** - Handling of null and undefined attribute values
81+
82+
The response will include a JSON object with test results and confirmation that all tests completed successfully.

smoke-tests/hello-node-express-ts/index.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,206 @@ app.get('/logs', (_req: Request, res: Response) => {
122122
res.status(200).json({ message: 'Logs generated successfully' });
123123
});
124124

125+
// Smoke test endpoint for setTraceAttributes API
126+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
127+
app.get(
128+
'/test-trace-attributes',
129+
async (_req: Request, res: Response, next: NextFunction) => {
130+
try {
131+
const tracer: Tracer = trace.getTracer('trace-attributes-test');
132+
const results: { [key: string]: string } = {};
133+
134+
// Test 1: Basic attribute setting
135+
await tracer.startActiveSpan('test-basic-attributes', (span: Span) => {
136+
HyperDX.setTraceAttributes({
137+
userId: 'user-123',
138+
requestId: 'req-456',
139+
testName: 'basic-attributes',
140+
});
141+
pinoLogger.info('Test 1: Set basic trace attributes');
142+
results.test1 = 'basic-attributes-set';
143+
span.end();
144+
});
145+
146+
// Test 2: Multiple attribute types
147+
await tracer.startActiveSpan('test-multiple-types', (span: Span) => {
148+
HyperDX.setTraceAttributes({
149+
stringAttr: 'value',
150+
numberAttr: 42,
151+
booleanAttr: true,
152+
arrayAttr: ['a', 'b', 'c'],
153+
testName: 'multiple-types',
154+
});
155+
pinoLogger.info('Test 2: Set multiple attribute types');
156+
results.test2 = 'multiple-types-set';
157+
span.end();
158+
});
159+
160+
// Test 3: Nested spans with attributes
161+
await tracer.startActiveSpan('test-nested-spans', async (parentSpan) => {
162+
HyperDX.setTraceAttributes({
163+
level: 'parent',
164+
testName: 'nested-spans',
165+
});
166+
pinoLogger.info('Test 3: Parent span attributes');
167+
168+
await tracer.startActiveSpan('child-span', async (childSpan) => {
169+
HyperDX.setTraceAttributes({
170+
level: 'child',
171+
childId: 'child-1',
172+
});
173+
pinoLogger.info('Test 3: Child span attributes');
174+
175+
await tracer.startActiveSpan('grandchild-span', (grandchildSpan) => {
176+
HyperDX.setTraceAttributes({
177+
level: 'grandchild',
178+
grandchildId: 'grandchild-1',
179+
});
180+
pinoLogger.info('Test 3: Grandchild span attributes');
181+
grandchildSpan.end();
182+
});
183+
184+
childSpan.end();
185+
});
186+
187+
results.test3 = 'nested-spans-set';
188+
parentSpan.end();
189+
});
190+
191+
// Test 4: Setting attributes multiple times (overwrite)
192+
await tracer.startActiveSpan('test-overwrite', (span: Span) => {
193+
HyperDX.setTraceAttributes({
194+
key: 'value1',
195+
testName: 'overwrite',
196+
});
197+
HyperDX.setTraceAttributes({
198+
key: 'value2', // This should overwrite the previous value
199+
additionalKey: 'additional-value',
200+
});
201+
pinoLogger.info('Test 4: Overwrite attributes');
202+
results.test4 = 'overwrite-set';
203+
span.end();
204+
});
205+
206+
// Test 5: Attributes with special characters
207+
await tracer.startActiveSpan('test-special-chars', (span: Span) => {
208+
HyperDX.setTraceAttributes({
209+
'user.id': 'user-123',
210+
'request-id': 'req-456',
211+
'foo.bar.baz': 'nested-key',
212+
'key with spaces': 'value with spaces',
213+
testName: 'special-chars',
214+
});
215+
pinoLogger.info('Test 5: Special characters in attribute keys');
216+
results.test5 = 'special-chars-set';
217+
span.end();
218+
});
219+
220+
// Test 6: Empty attributes
221+
await tracer.startActiveSpan('test-empty-attributes', (span: Span) => {
222+
HyperDX.setTraceAttributes({});
223+
pinoLogger.info('Test 6: Empty attributes object');
224+
results.test6 = 'empty-attributes-set';
225+
span.end();
226+
});
227+
228+
// Test 7: Large number of attributes
229+
await tracer.startActiveSpan('test-many-attributes', (span: Span) => {
230+
const manyAttributes: { [key: string]: string } = {
231+
testName: 'many-attributes',
232+
};
233+
for (let i = 0; i < 50; i++) {
234+
manyAttributes[`attr${i}`] = `value${i}`;
235+
}
236+
HyperDX.setTraceAttributes(manyAttributes);
237+
pinoLogger.info('Test 7: Large number of attributes (50)');
238+
results.test7 = 'many-attributes-set';
239+
span.end();
240+
});
241+
242+
// Test 8: Concurrent attribute setting
243+
await Promise.all([
244+
tracer.startActiveSpan('concurrent-1', async (span) => {
245+
HyperDX.setTraceAttributes({
246+
spanId: '1',
247+
value: 'concurrent-a',
248+
testName: 'concurrent-1',
249+
});
250+
pinoLogger.info('Test 8: Concurrent span 1');
251+
await new Promise((resolve) => setTimeout(resolve, 10));
252+
span.end();
253+
}),
254+
tracer.startActiveSpan('concurrent-2', async (span) => {
255+
HyperDX.setTraceAttributes({
256+
spanId: '2',
257+
value: 'concurrent-b',
258+
testName: 'concurrent-2',
259+
});
260+
pinoLogger.info('Test 8: Concurrent span 2');
261+
await new Promise((resolve) => setTimeout(resolve, 10));
262+
span.end();
263+
}),
264+
tracer.startActiveSpan('concurrent-3', async (span) => {
265+
HyperDX.setTraceAttributes({
266+
spanId: '3',
267+
value: 'concurrent-c',
268+
testName: 'concurrent-3',
269+
});
270+
pinoLogger.info('Test 8: Concurrent span 3');
271+
await new Promise((resolve) => setTimeout(resolve, 10));
272+
span.end();
273+
}),
274+
]);
275+
results.test8 = 'concurrent-attributes-set';
276+
277+
// Test 9: Attributes in async operations
278+
await tracer.startActiveSpan('test-async', async (span) => {
279+
HyperDX.setTraceAttributes({
280+
stage: 'before-async',
281+
testName: 'async',
282+
});
283+
pinoLogger.info('Test 9: Before async operation');
284+
285+
await new Promise((resolve) => setTimeout(resolve, 20));
286+
287+
HyperDX.setTraceAttributes({
288+
stage: 'after-async',
289+
});
290+
pinoLogger.info('Test 9: After async operation');
291+
292+
results.test9 = 'async-attributes-set';
293+
span.end();
294+
});
295+
296+
// Test 10: Attributes with null/undefined values
297+
await tracer.startActiveSpan('test-null-undefined', (span: Span) => {
298+
HyperDX.setTraceAttributes({
299+
nullAttr: null as any,
300+
undefinedAttr: undefined as any,
301+
validAttr: 'valid',
302+
testName: 'null-undefined',
303+
});
304+
pinoLogger.info('Test 10: Null and undefined values');
305+
results.test10 = 'null-undefined-set';
306+
span.end();
307+
});
308+
309+
pinoLogger.info(
310+
{ results },
311+
'All setTraceAttributes smoke tests completed',
312+
);
313+
res.status(200).json({
314+
message: 'setTraceAttributes smoke tests completed successfully',
315+
results,
316+
testsRun: Object.keys(results).length,
317+
});
318+
} catch (err) {
319+
pinoLogger.error({ err }, 'Error in setTraceAttributes smoke tests');
320+
next(err);
321+
}
322+
},
323+
);
324+
125325
function sleepy(): Promise<void> {
126326
return new Promise((resolve) => {
127327
setTimeout(() => {

0 commit comments

Comments
 (0)