@reproapp/node-sdk 0.0.49 → 0.0.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +83 -31
- package/dist/ingest/client.d.ts +2 -2
- package/dist/ingest/client.js +33 -7
- package/dist/live-capture-limits.d.ts +19 -0
- package/dist/live-capture-limits.js +207 -0
- package/dist/semantic-serialization.d.ts +1 -0
- package/dist/semantic-serialization.js +33 -1
- package/package.json +7 -2
- package/src/index.ts +103 -31
- package/src/ingest/client.ts +36 -10
- package/src/live-capture-limits.ts +177 -0
- package/src/semantic-serialization.ts +30 -0
- package/test/background-continuous-traffic.testcontainers.test.js +100 -0
- package/test/fixtures/live-capture-limits-server.js +21 -0
- package/test/ingest-throttle-retention.test.js +41 -0
- package/test/live-broker-limits.testcontainers.test.js +86 -0
- package/test/live-capture-limits.test.js +99 -0
- package/test/live-capture-limits.testcontainers.test.js +78 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
process.env.REPRO_SDK_BACKGROUND_IDLE_DELAY_MS = '0';
|
|
2
|
+
process.env.REPRO_SDK_BACKGROUND_BUSY_IDLE_DELAY_MS = '0';
|
|
3
|
+
process.env.REPRO_SDK_BACKGROUND_MAX_DEFER_MS = '30';
|
|
4
|
+
process.env.TRACE_IDLE_FLUSH_MS = '10';
|
|
5
|
+
process.env.TRACE_LINGER_AFTER_FINISH_MS = '0';
|
|
6
|
+
const assert = require('node:assert/strict');
|
|
7
|
+
const http = require('node:http');
|
|
8
|
+
const { GenericContainer, Wait } = require('testcontainers');
|
|
9
|
+
const { initRepro } = require('../dist');
|
|
10
|
+
const { flushIngestQueue } = require('../dist/ingest/client');
|
|
11
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
const posts = [];
|
|
15
|
+
const sink = http.createServer((req, res) => {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
18
|
+
req.on('end', () => { posts.push(JSON.parse(Buffer.concat(chunks))); res.writeHead(202); res.end('{}'); });
|
|
19
|
+
});
|
|
20
|
+
await new Promise(resolve => sink.listen(0, '127.0.0.1', resolve));
|
|
21
|
+
let mongo, app;
|
|
22
|
+
try {
|
|
23
|
+
mongo = await new GenericContainer('mongo:7').withExposedPorts(27017).withWaitStrategy(Wait.forListeningPorts()).start();
|
|
24
|
+
const config = { tenantId: 'TENANT_limits', appId: 'APP_limits', appSecret: 'test',
|
|
25
|
+
privacy: { environment: 'dev', captureRaw: true }, ingestBase: `http://127.0.0.1:${sink.address().port}`,
|
|
26
|
+
tracing: { fullValueCapture: true, disableFunctionTypes: ['constructor'], logFunctionCalls: false } };
|
|
27
|
+
await initRepro(config);
|
|
28
|
+
app = await require('./fixtures/live-capture-limits-server').start(config, `mongodb://${mongo.getHost()}:${mongo.getMappedPort(27017)}/limits`);
|
|
29
|
+
for (const mode of ['live', 'staging']) {
|
|
30
|
+
const response = await fetch(`http://127.0.0.1:${app.server.address().port}/shipment?__repro_sid=S_${mode}&__repro_aid=A_${mode}&__repro_mode=${mode}`);
|
|
31
|
+
assert.equal(response.status, 200);
|
|
32
|
+
const actual = await response.json();
|
|
33
|
+
assert.equal(actual.rows.length, 157, 'recording must not alter the application response');
|
|
34
|
+
assert.equal(actual.rows[156].id, 156);
|
|
35
|
+
}
|
|
36
|
+
const deadline = Date.now() + 30_000;
|
|
37
|
+
let events = [];
|
|
38
|
+
do {
|
|
39
|
+
await flushIngestQueue();
|
|
40
|
+
events = posts.flatMap(post => post.events || []);
|
|
41
|
+
if (events.filter(event => event.event_type === 'request_capture_manifest').length >= 2) break;
|
|
42
|
+
await sleep(100);
|
|
43
|
+
} while (Date.now() < deadline);
|
|
44
|
+
for (const mode of ['live', 'staging']) {
|
|
45
|
+
const scoped = events.filter(event => event.session_id === `S_${mode}`);
|
|
46
|
+
const request = scoped.find(event => event.event_type === 'backend_request')?.payload?.request;
|
|
47
|
+
assert(request, `missing ${mode} request`);
|
|
48
|
+
const values = scoped.flatMap(event => [...(event.payload?.traceValues || []), ...(event.payload?.requestValues || []), ...(event.payload?.dbValues || [])]);
|
|
49
|
+
if (request.respBodyValueCapture?.valueId) assert(values.some(value => value.id === request.respBodyValueCapture.valueId), 'response reference must resolve');
|
|
50
|
+
const body = values.find(value => value.id === request.respBodyValueCapture?.valueId)?.value || request.respBody;
|
|
51
|
+
assert(body?.rows, `missing ${mode} response body`);
|
|
52
|
+
assert.equal(body.rows.length, mode === 'live' ? 101 : 157, JSON.stringify({ mode, capture: request.respBodyValueCapture, valueTargets: values.map(value => value.target) }));
|
|
53
|
+
if (mode === 'live') {
|
|
54
|
+
assert.equal(body.rows[100].originalCount, 157);
|
|
55
|
+
assert.equal(request.respBodyValueCapture.complete, false);
|
|
56
|
+
}
|
|
57
|
+
const changes = scoped.filter(event => event.event_type === 'db_change').flatMap(event => event.payload?.db || []);
|
|
58
|
+
const read = changes.find(change => change.op === 'findOne');
|
|
59
|
+
assert(read, `missing ${mode} database query`);
|
|
60
|
+
const result = values.find(value => value.id === read.resultMetaValueCapture?.valueId)?.value || read.resultMeta;
|
|
61
|
+
const resultText = JSON.stringify(result);
|
|
62
|
+
assert(resultText?.includes('SHIP-LIMIT'), `missing ${mode} database result ${JSON.stringify(read)}`);
|
|
63
|
+
assert.equal(resultText.includes('"id":156'), mode === 'staging', 'query results must follow the same mode as responses');
|
|
64
|
+
if (mode === 'live') assert.equal(read.resultMetaValueCapture.complete, false);
|
|
65
|
+
const trace = scoped.flatMap(event => event.payload?.trace || []).find(event => event.fn === 'inspectShipment' && event.type === 'enter');
|
|
66
|
+
assert(trace, `missing ${mode} function arguments`);
|
|
67
|
+
const args = values.find(value => value.id === trace.argsValueCapture?.valueId)?.value || trace.args;
|
|
68
|
+
assert.equal(args[0].rows.length, mode === 'live' ? 101 : 157);
|
|
69
|
+
}
|
|
70
|
+
console.log('real Mongo + Express + instrumented traces: live bounds and exact staging evidence passed');
|
|
71
|
+
} finally {
|
|
72
|
+
if (app) await app.close();
|
|
73
|
+
await flushIngestQueue();
|
|
74
|
+
await new Promise(resolve => sink.close(resolve));
|
|
75
|
+
if (mongo) await mongo.stop();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
main().catch(error => { console.error(error); process.exitCode = 1; });
|