hivecast-sdk/packages/federation/tests/integration/edge-gateway-routing.spec.ts

211 lines
6.2 KiB
TypeScript
Raw Permalink Normal View History

/**
* EdgeGateway Routing Integration Tests
*
* Tests the EdgeGateway's ability to route messages between
* backbone and local bus using in-memory transports.
*/
import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import {
FederationPeer, ExactInstanceResolver,
WIRE_PROFILES,
InMemoryFilterBroker,
getLegacyIngressTopic,
} from '@open-matrix/federation';
describe('EdgeGateway Routing', () => {
it('routes inbound request from backbone to local bus', async () => {
const REALM = 'test-realm';
// Create in-memory brokers
const backbone = new InMemoryFilterBroker();
const localBus = new InMemoryFilterBroker();
// Create EdgeGateway
const gateway = new FederationPeer({
localRealm: REALM,
profile: WIRE_PROFILES.matrix3,
backbone,
localBus,
});
gateway.start();
// Subscribe to internal topic on local bus (simulating a handler)
// Internal topic format: <toPath> (realm is a transport concern)
let receivedRequest: unknown = null;
localBus.subscribe(`test.component.accepts.ping`, (topic, payload) => {
receivedRequest = JSON.parse(payload);
});
// Allow subscriptions to propagate
await new Promise(r => setTimeout(r, 50));
// Send request to backbone mailbox using LEGACY format (flat fields)
const request = {
toRealm: REALM,
toPath: 'test.component.accepts.ping',
fromRealm: 'client-realm',
replyTo: '_reply', // just the path, not an object
correlationId: 'test-123',
body: { message: 'hello' },
};
backbone.publish(getLegacyIngressTopic(REALM), JSON.stringify(request));
// Wait for message to be routed
await new Promise(r => setTimeout(r, 100));
assert.ok(receivedRequest, 'Should receive request on local bus');
assert.strictEqual((receivedRequest as { correlationId: string }).correlationId, 'test-123');
gateway.stop();
});
it('routes reply from local bus back to backbone', async () => {
const REALM = 'test-realm';
const CLIENT_REALM = 'client-realm';
const backbone = new InMemoryFilterBroker();
const localBus = new InMemoryFilterBroker();
const gateway = new FederationPeer({
localRealm: REALM,
profile: WIRE_PROFILES.matrix3,
backbone,
localBus,
internalTimeoutMs: 5000,
});
gateway.start();
// Subscribe to client's mailbox on backbone (where reply should go)
let receivedReply: unknown = null;
backbone.subscribe(getLegacyIngressTopic(CLIENT_REALM), (topic, payload) => {
receivedReply = JSON.parse(payload);
});
// Set up handler on local bus that will reply
// Internal topic format: <toPath> (realm is a transport concern)
localBus.subscribe(`test.component.accepts.echo`, (topic, payload) => {
const req = JSON.parse(payload) as { replyTo: string; correlationId: string; params: unknown };
// Send reply to the replyTo topic
localBus.publish(req.replyTo, JSON.stringify({
ok: true,
correlationId: req.correlationId,
result: { echo: 'hello back' },
}));
});
await new Promise(r => setTimeout(r, 50));
// Send request from client using LEGACY format (flat fields)
const request = {
toRealm: REALM,
toPath: 'test.component.accepts.echo',
fromRealm: CLIENT_REALM,
replyTo: '_reply', // just the path
correlationId: 'echo-456',
body: { message: 'hello' },
};
backbone.publish(getLegacyIngressTopic(REALM), JSON.stringify(request));
// Wait for round-trip
await new Promise(r => setTimeout(r, 200));
assert.ok(receivedReply, 'Should receive reply on backbone');
gateway.stop();
});
it('uses exact mailbox topic (no wildcards)', async () => {
const REALM = 'my-realm';
const backbone = new InMemoryFilterBroker();
const localBus = new InMemoryFilterBroker();
// Track what topics are subscribed
const subscribedTopics: string[] = [];
const originalSubscribe = backbone.subscribe.bind(backbone);
backbone.subscribe = (topic: string, handler: (t: string, p: string) => void) => {
subscribedTopics.push(topic);
return originalSubscribe(topic, handler);
};
const gateway = new FederationPeer({
localRealm: REALM,
profile: WIRE_PROFILES.matrix3,
backbone,
localBus,
});
gateway.start();
// Verify subscribed topic is exact mailbox, not wildcard
const mailboxTopic = getLegacyIngressTopic(REALM);
assert.ok(
subscribedTopics.includes(mailboxTopic),
`Should subscribe to exact mailbox: ${mailboxTopic}`
);
assert.ok(
!subscribedTopics.some(t => t.includes('#') || t.includes('+')),
'Should NOT use wildcards on backbone subscription'
);
gateway.stop();
});
it('metrics track inbound requests', async () => {
const REALM = 'metrics-realm';
const backbone = new InMemoryFilterBroker();
const localBus = new InMemoryFilterBroker();
const gateway = new FederationPeer({
localRealm: REALM,
profile: WIRE_PROFILES.matrix3,
backbone,
localBus,
});
gateway.start();
// Set up a handler so request completes
// Internal topic format: <toPath> (realm is a transport concern)
localBus.subscribe(`test.accepts.cmd`, (topic, payload) => {
const req = JSON.parse(payload) as { replyTo: string; correlationId: string };
localBus.publish(req.replyTo, JSON.stringify({ ok: true, correlationId: req.correlationId }));
});
await new Promise(r => setTimeout(r, 50));
const initialMetrics = gateway.getMetrics();
// Send a request using LEGACY format (flat fields)
const request = {
toRealm: REALM,
toPath: 'test.accepts.cmd',
fromRealm: 'other',
replyTo: '_reply', // just the path
correlationId: 'metrics-1',
body: {},
};
backbone.publish(getLegacyIngressTopic(REALM), JSON.stringify(request));
await new Promise(r => setTimeout(r, 200));
const finalMetrics = gateway.getMetrics();
assert.ok(
finalMetrics.inboundRequests > initialMetrics.inboundRequests,
'Inbound requests should increase'
);
gateway.stop();
});
});