Full SDK workspace: core, contracts, sdk, cli, browser-host, browser-kit, federation, omega-core, oracle, self-healing, strategies, tools, emacs. Clean extraction from the development monorepo. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
180 lines
7.4 KiB
TypeScript
180 lines
7.4 KiB
TypeScript
/**
|
|
* FlowPad Cross-Realm Integration Test
|
|
*
|
|
* This test verifies the EXACT pattern FlowPad uses for cross-realm communication:
|
|
* 1. FlowPad (browser) creates CrossRealmRouter with tab realm
|
|
* 2. FlowPad calls viaRemote("daemon@matrix-3/daemon.matrix-3", "introspect")
|
|
* 3. CrossRealmRouter routes to CrossRealmClient (cross-realm)
|
|
* 4. CrossRealmClient publishes to daemon's mailbox topic
|
|
* 5. Daemon's EdgeGateway receives, routes to internal handler
|
|
* 6. Handler responds, EdgeGateway sends reply
|
|
* 7. FlowPad's CrossRealmClient receives reply
|
|
*
|
|
* This is a LOOPBACK test - both FlowPad and daemon are simulated in-process
|
|
* connected via a shared InMemory backbone.
|
|
*/
|
|
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { FederationPeer, TabInstanceResolver } from '@open-matrix/federation/federation_peer';
|
|
import { InMemoryFilterBroker } from '@open-matrix/federation/transport/inmem';
|
|
import { WIRE_PROFILES } from '@open-matrix/federation/wire_profile';
|
|
import { getInternalTopic } from '@open-matrix/federation/topics';
|
|
|
|
/**
|
|
* Test the exact FlowPad pattern: viaRemote to daemon@matrix-3
|
|
*/
|
|
test('FlowPad cross-realm to daemon@matrix-3 (full loopback)', async () => {
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// BACKBONE: Shared InMemory broker simulating HiveMQ
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
const backbone = new InMemoryFilterBroker();
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// FLOWPAD SIDE: CrossRealmRouter with tab realm
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
const flowpadLocalBus = new InMemoryFilterBroker();
|
|
|
|
// FlowPad's tab-isolated realm
|
|
const flowpadTabRealm = 'flowpad.tab-abc123';
|
|
|
|
const flowpadRouter = new FederationPeer({
|
|
localRealm: flowpadTabRealm,
|
|
localBus: flowpadLocalBus,
|
|
instanceResolver: new TabInstanceResolver(flowpadTabRealm),
|
|
backbone: backbone, // Connect to shared backbone
|
|
});
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// DAEMON SIDE: EdgeGateway processing incoming requests
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
const daemonLocalBus = new InMemoryFilterBroker();
|
|
const daemonRealm = 'daemon@matrix-3';
|
|
|
|
// Create EdgeGateway for daemon realm
|
|
const daemonEdge = new FederationPeer({
|
|
localRealm: daemonRealm,
|
|
backbone,
|
|
localBus: daemonLocalBus,
|
|
profile: WIRE_PROFILES.mxenv1,
|
|
internalTimeoutMs: 3000,
|
|
});
|
|
|
|
// Start daemon EdgeGateway (subscribes to mailbox topics)
|
|
daemonEdge.start();
|
|
|
|
// Set up daemon's internal handler for introspect
|
|
const daemonInternalTopic = getInternalTopic(daemonRealm, 'daemon.matrix-3.accepts.introspect');
|
|
console.log(`[Test] Daemon subscribing to: ${daemonInternalTopic}`);
|
|
|
|
daemonLocalBus.subscribe(daemonInternalTopic, (topic, payload) => {
|
|
console.log(`[Test] Daemon received on ${topic}:`, payload);
|
|
const request = JSON.parse(payload);
|
|
|
|
// Send reply to the replyTo topic
|
|
const reply = {
|
|
correlationId: request.correlationId,
|
|
ok: true,
|
|
result: {
|
|
type: 'DaemonProject',
|
|
name: 'matrix-3',
|
|
children: ['file1.ts', 'file2.ts'],
|
|
},
|
|
};
|
|
|
|
console.log(`[Test] Daemon replying to: ${request.replyTo}`);
|
|
daemonLocalBus.publish(request.replyTo, JSON.stringify(reply));
|
|
});
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// TEST: FlowPad calls viaRemote to daemon
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
console.log(`[Test] FlowPad invoking: daemon@matrix-3/daemon.matrix-3.accepts.introspect`);
|
|
|
|
const result = await flowpadRouter.invoke<{ type: string; name: string; children: string[] }>(
|
|
'daemon@matrix-3/daemon.matrix-3.accepts.introspect',
|
|
{},
|
|
5000
|
|
);
|
|
|
|
console.log(`[Test] Result:`, result);
|
|
|
|
// Verify result
|
|
assert.equal(result.type, 'DaemonProject');
|
|
assert.equal(result.name, 'matrix-3');
|
|
assert.deepEqual(result.children, ['file1.ts', 'file2.ts']);
|
|
|
|
// Cleanup
|
|
daemonEdge.stop();
|
|
flowpadRouter.stop();
|
|
});
|
|
|
|
/**
|
|
* Test that base realm matching works: flowpad → flowpad.tab-xxx is LOCAL
|
|
*/
|
|
test('FlowPad local routing: flowpad → flowpad.tab-xxx is LOCAL', async () => {
|
|
const localBus = new InMemoryFilterBroker();
|
|
|
|
const tabRealm = 'flowpad.tab-abc123';
|
|
|
|
const router = new FederationPeer({
|
|
localRealm: tabRealm,
|
|
localBus: localBus,
|
|
instanceResolver: new TabInstanceResolver(tabRealm),
|
|
});
|
|
|
|
// Set up local handler on the tab realm topic using browser local bus format.
|
|
// TabInstanceResolver returns semantic path for browser local bus.
|
|
const localTopic = `${tabRealm}.tree.accepts.introspect`;
|
|
console.log(`[Test] Local handler subscribing to: ${localTopic}`);
|
|
|
|
localBus.subscribe(localTopic, (topic, payload) => {
|
|
console.log(`[Test] Local handler received on ${topic}`);
|
|
const request = JSON.parse(payload);
|
|
const reply = {
|
|
ok: true,
|
|
result: { type: 'FractalTree', local: true },
|
|
};
|
|
localBus.publish(request.replyTo, JSON.stringify(reply));
|
|
});
|
|
|
|
// FlowPad uses base realm "flowpad" in the URI (not the full tab realm)
|
|
// The router should still route locally because "flowpad" is the base of "flowpad.tab-abc123"
|
|
const result = await router.invoke<{ type: string; local: boolean }>(
|
|
'flowpad/tree.accepts.introspect',
|
|
{},
|
|
1000
|
|
);
|
|
|
|
console.log(`[Test] Result:`, result);
|
|
|
|
assert.equal(result.type, 'FractalTree');
|
|
assert.equal(result.local, true);
|
|
|
|
router.stop();
|
|
});
|
|
|
|
/**
|
|
* Test different realm = CROSS-REALM (not local)
|
|
*/
|
|
test('FlowPad to daemon is CROSS-REALM (not local)', async () => {
|
|
const localBus = new InMemoryFilterBroker();
|
|
|
|
const tabRealm = 'flowpad.tab-abc123';
|
|
|
|
const router = new FederationPeer({
|
|
localRealm: tabRealm,
|
|
localBus: localBus,
|
|
instanceResolver: new TabInstanceResolver(tabRealm),
|
|
// No backbone transport - should throw on cross-realm
|
|
});
|
|
|
|
// daemon@matrix-3 is a DIFFERENT realm - should require backbone
|
|
await assert.rejects(
|
|
() => router.invoke('daemon@matrix-3/daemon.matrix-3.accepts.introspect', {}, 1000),
|
|
/No backbone transport/
|
|
);
|
|
|
|
router.stop();
|
|
});
|