Files
upstream-jitsi-meet/tests/prosody/mod_trace_spec.js
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

124 lines
5.1 KiB
JavaScript

import assert from 'assert';
import { clearOtlpTraces, getOtlpTraces } from './helpers/test_observer.js';
import { createXmppClient } from './helpers/xmpp_client.js';
// Sender lives on a separate, plain VirtualHost from the receiver under test.
// mod_trace's iq/full hook fires once per host whose event bus a stanza
// passes through (once for the sender's own outbound processing, once for
// delivery to the recipient) — using two different hosts here means the
// hook (loaded only on the receiver's host) fires exactly once, matching
// real jicofo/JVB topology where sender and receiver are never the same host.
const SENDER_DOMAIN = 'whitelist.localhost';
/**
* Connects a sender client (on SENDER_DOMAIN) and a receiver client (on the
* given domain) and registers both for afterEach cleanup.
*
* @param {string} receiverDomain
* @param {Array} clients Cleanup array; both new clients are appended.
* @returns {Promise<[object, object]>}
*/
async function connectPair(receiverDomain, clients) {
const a = await createXmppClient({ domain: SENDER_DOMAIN });
const b = await createXmppClient({ domain: receiverDomain });
clients.push(a, b);
return [ a, b ];
}
describe('mod_trace', () => {
const clients = [];
beforeEach(() => clearOtlpTraces());
afterEach(async () => {
await Promise.all(clients.map(c => c.disconnect()));
clients.length = 0;
});
describe('when otlp_endpoint is unset', () => {
it('leaves a conference-modify IQ with traceparent unmodified and exports nothing', async () => {
const [ a, b ] = await connectPair('trace-disabled.localhost', clients);
const traceId = 'd'.repeat(32);
const parentId = 'e'.repeat(16);
await a.sendConferenceModifyIq(b.jid, { traceId,
parentId });
const iq = await b.waitForIq(s => s.getChild('conference-modify', 'jitsi:colibri2'));
const cm = iq.getChild('conference-modify', 'jitsi:colibri2');
const tp = cm.getChild('traceparent');
assert.ok(tp, 'traceparent element should still be present');
assert.strictEqual(tp.attrs.trace_id, traceId);
assert.strictEqual(tp.attrs.parent_id, parentId,
'parent_id must be left untouched when the module is disabled');
const traces = await getOtlpTraces();
assert.strictEqual(traces.length, 0, 'no span should be exported when otlp_endpoint is unset');
});
});
describe('when otlp_endpoint is set', () => {
it('leaves a conference-modify IQ without traceparent unmodified and exports nothing', async () => {
const [ a, b ] = await connectPair('trace.localhost', clients);
await a.sendConferenceModifyIq(b.jid);
const iq = await b.waitForIq(s => s.getChild('conference-modify', 'jitsi:colibri2'));
const cm = iq.getChild('conference-modify', 'jitsi:colibri2');
assert.ok(!cm.getChild('traceparent'),
'no traceparent should be added when the sender did not include one');
// Give Prosody a moment to (not) export before asserting the negative.
await new Promise(r => setTimeout(r, 300));
const traces = await getOtlpTraces();
assert.strictEqual(traces.length, 0);
});
it('rewrites the traceparent parent_id and exports a span for a conference-modify IQ', async () => {
const [ a, b ] = await connectPair('trace.localhost', clients);
const traceId = 'a'.repeat(32);
const parentId = 'b'.repeat(16);
await a.sendConferenceModifyIq(b.jid, { traceId,
parentId });
const iq = await b.waitForIq(s => s.getChild('conference-modify', 'jitsi:colibri2'));
const cm = iq.getChild('conference-modify', 'jitsi:colibri2');
const tp = cm.getChild('traceparent');
assert.ok(tp, 'traceparent element should still be present');
assert.strictEqual(tp.attrs.trace_id, traceId, 'trace_id must be preserved');
assert.notStrictEqual(tp.attrs.parent_id, parentId, 'parent_id must be rewritten to the new span id');
assert.match(tp.attrs.parent_id, /^[0-9a-f]{16}$/, 'rewritten parent_id must be a 16-hex-char span id');
// Give Prosody a moment to POST the export before polling.
await new Promise(r => setTimeout(r, 300));
const traces = await getOtlpTraces();
assert.strictEqual(traces.length, 1, 'exactly one export request should have been made');
const [ resourceSpan ] = traces[0].resource_spans;
const [ scopeSpan ] = resourceSpan.scope_spans;
const [ span ] = scopeSpan.spans;
assert.strictEqual(scopeSpan.scope.name, 'muc');
assert.strictEqual(span.name, 'colibri.conference-modify');
assert.strictEqual(span.trace_id, traceId);
assert.strictEqual(span.parent_span_id, parentId,
'exported span must record the original parent_id as its own parent');
});
});
});