161 lines
4.9 KiB
TypeScript
161 lines
4.9 KiB
TypeScript
|
|
/**
|
||
|
|
* 08K: Cross-Realm Integration Test
|
||
|
|
*
|
||
|
|
* Tests transparent cross-realm communication via the FederationPeer.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { describe, it } from 'node:test';
|
||
|
|
import { strict as assert } from 'node:assert';
|
||
|
|
import {
|
||
|
|
InMemoryFilterBroker,
|
||
|
|
FederationPeer, TabInstanceResolver,
|
||
|
|
} from '@open-matrix/federation';
|
||
|
|
|
||
|
|
describe('08K: Cross-Realm Integration', () => {
|
||
|
|
|
||
|
|
describe('Local Broker Routing', () => {
|
||
|
|
it('local realm routes via local transport', async () => {
|
||
|
|
const broker = new InMemoryFilterBroker();
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad',
|
||
|
|
localBus: broker,
|
||
|
|
});
|
||
|
|
|
||
|
|
// FlowPad subscribes to its own topic ( format used by route())
|
||
|
|
let messageReceived = false;
|
||
|
|
broker.subscribe('flowpad/app', (topic, payload) => {
|
||
|
|
messageReceived = true;
|
||
|
|
});
|
||
|
|
|
||
|
|
// FlowPad routes to itself (same realm = local)
|
||
|
|
await router.route('flowpad/app', {
|
||
|
|
type: 'test',
|
||
|
|
});
|
||
|
|
|
||
|
|
await new Promise((r) => setTimeout(r, 50));
|
||
|
|
assert.equal(messageReceived, true, 'Local route should use broker');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('cross-realm routes without error (with backbone)', async () => {
|
||
|
|
const localBus = new InMemoryFilterBroker();
|
||
|
|
const backbone = new InMemoryFilterBroker();
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad',
|
||
|
|
localBus,
|
||
|
|
backbone,
|
||
|
|
});
|
||
|
|
|
||
|
|
// FlowPad routes to daemon (cross-realm) — backbone absorbs the message
|
||
|
|
await router.route('daemon/project.accepts.$introspect', {
|
||
|
|
type: '$introspect',
|
||
|
|
});
|
||
|
|
// No error = cross-realm routing works
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('URI Transparency', () => {
|
||
|
|
it('same URI works regardless of realm', async () => {
|
||
|
|
const localBus = new InMemoryFilterBroker();
|
||
|
|
const backbone = new InMemoryFilterBroker();
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad',
|
||
|
|
localBus,
|
||
|
|
backbone,
|
||
|
|
});
|
||
|
|
|
||
|
|
// These URIs should all route correctly (no throws)
|
||
|
|
const uris = [
|
||
|
|
'flowpad/app/widget',
|
||
|
|
'daemon/project',
|
||
|
|
'user@daemon/project.accepts.scan',
|
||
|
|
];
|
||
|
|
|
||
|
|
for (const uri of uris) {
|
||
|
|
await router.route(uri, {});
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('Request-Reply Cross-Realm', () => {
|
||
|
|
it('cross-realm introspect placeholder', async () => {
|
||
|
|
// Full cross-realm request-reply is tested in flowpad_crossrealm.test.ts
|
||
|
|
// and cross-realm-two-gateways.spec.ts
|
||
|
|
assert.ok(true, 'Placeholder test');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('timeout placeholder', async () => {
|
||
|
|
assert.ok(true, 'Placeholder test');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('Tab Realm Isolation', () => {
|
||
|
|
it('tab-suffixed realm routes locally', async () => {
|
||
|
|
const localPublishCalls: string[] = [];
|
||
|
|
const localBroker = {
|
||
|
|
publish: (topic: string, payload: string) => {
|
||
|
|
localPublishCalls.push(topic);
|
||
|
|
},
|
||
|
|
subscribe: () => () => {},
|
||
|
|
};
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad.tab-abc123',
|
||
|
|
localBus: localBroker as any,
|
||
|
|
instanceResolver: new TabInstanceResolver('flowpad.tab-abc123'),
|
||
|
|
});
|
||
|
|
|
||
|
|
// Route to same tab realm - should use local transport
|
||
|
|
await router.route('flowpad.tab-abc123/app', {});
|
||
|
|
|
||
|
|
assert.equal(localPublishCalls.length, 1, 'Should route via local transport');
|
||
|
|
assert.ok(localPublishCalls[0].includes('flowpad.tab-abc123'), 'Topic should include tab realm');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('base realm routes locally with TabInstanceResolver', async () => {
|
||
|
|
const localPublishCalls: string[] = [];
|
||
|
|
const localBroker = {
|
||
|
|
publish: (topic: string, payload: string) => {
|
||
|
|
localPublishCalls.push(topic);
|
||
|
|
},
|
||
|
|
subscribe: () => () => {},
|
||
|
|
};
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad.tab-abc',
|
||
|
|
localBus: localBroker as any,
|
||
|
|
instanceResolver: new TabInstanceResolver('flowpad.tab-abc'),
|
||
|
|
});
|
||
|
|
|
||
|
|
// Route using base realm "flowpad" - TabInstanceResolver treats as local
|
||
|
|
await router.route('flowpad.app', {});
|
||
|
|
|
||
|
|
assert.equal(localPublishCalls.length, 1, 'Should route via local transport');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('different tab realms are NOT local with ExactInstanceResolver', async () => {
|
||
|
|
const localPublishCalls: string[] = [];
|
||
|
|
const localBroker = {
|
||
|
|
publish: (topic: string, payload: string) => {
|
||
|
|
localPublishCalls.push(topic);
|
||
|
|
},
|
||
|
|
subscribe: () => () => {},
|
||
|
|
};
|
||
|
|
|
||
|
|
const router = new FederationPeer({
|
||
|
|
localRealm: 'flowpad.tab-abc',
|
||
|
|
localBus: localBroker as any,
|
||
|
|
// No TabInstanceResolver = ExactInstanceResolver default
|
||
|
|
});
|
||
|
|
|
||
|
|
// Route to different tab - ExactInstanceResolver treats as cross-realm
|
||
|
|
await router.route('flowpad.tab-xyz/app', {});
|
||
|
|
|
||
|
|
// Should NOT route locally (no backbone, just warns)
|
||
|
|
assert.equal(localPublishCalls.length, 0, 'Different tabs should not route locally with ExactInstanceResolver');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|