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>
459 lines
14 KiB
TypeScript
459 lines
14 KiB
TypeScript
/**
|
|
* Layer 6: Runtime Unit Tests
|
|
*
|
|
* Tests for runtime infrastructure: RealmRegistry, ShardAllocator, etc.
|
|
*/
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { RealmRegistry, type RealmEndpoint } from '@open-matrix/federation/runtime/realm_registry';
|
|
import {
|
|
ShardAllocator,
|
|
DEFAULT_SHARD,
|
|
allocateShardForTab,
|
|
getGlobalShardAllocator,
|
|
} from '@open-matrix/federation/runtime/shard_allocator';
|
|
|
|
// ============================================================================
|
|
// RealmRegistry Tests
|
|
// ============================================================================
|
|
|
|
test('RealmRegistry: register and resolve single endpoint', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('acme.com', [
|
|
{ type: 'nats', url: 'nats://broker.acme.com', priority: 0 },
|
|
]);
|
|
|
|
const endpoint = registry.resolve('acme.com');
|
|
assert.ok(endpoint !== null);
|
|
assert.equal(endpoint.type, 'nats');
|
|
assert.equal(endpoint.url, 'nats://broker.acme.com');
|
|
assert.equal(endpoint.priority, 0);
|
|
});
|
|
|
|
test('RealmRegistry: resolve returns highest priority endpoint', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('example.com', [
|
|
{ type: 'ws', url: 'ws://secondary.example.com', priority: 10 },
|
|
{ type: 'nats', url: 'nats://primary.example.com', priority: 0 },
|
|
{ type: 'wss', url: 'wss://backup.example.com', priority: 20 },
|
|
]);
|
|
|
|
const endpoint = registry.resolve('example.com');
|
|
assert.ok(endpoint !== null);
|
|
assert.equal(endpoint.priority, 0);
|
|
assert.equal(endpoint.url, 'nats://primary.example.com');
|
|
});
|
|
|
|
test('RealmRegistry: resolveAll returns sorted endpoints', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('multi.com', [
|
|
{ type: 'wss', url: 'wss://c.multi.com', priority: 30 },
|
|
{ type: 'ws', url: 'ws://a.multi.com', priority: 10 },
|
|
{ type: 'nats', url: 'nats://b.multi.com', priority: 20 },
|
|
]);
|
|
|
|
const endpoints = registry.resolveAll('multi.com');
|
|
assert.equal(endpoints.length, 3);
|
|
assert.equal(endpoints[0].priority, 10);
|
|
assert.equal(endpoints[1].priority, 20);
|
|
assert.equal(endpoints[2].priority, 30);
|
|
});
|
|
|
|
test('RealmRegistry: resolve returns null for unknown realm', () => {
|
|
const registry = new RealmRegistry();
|
|
const endpoint = registry.resolve('unknown.realm');
|
|
assert.equal(endpoint, null);
|
|
});
|
|
|
|
test('RealmRegistry: resolveAll returns empty array for unknown realm', () => {
|
|
const registry = new RealmRegistry();
|
|
const endpoints = registry.resolveAll('unknown.realm');
|
|
assert.deepEqual(endpoints, []);
|
|
});
|
|
|
|
test('RealmRegistry: has() checks realm registration', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
assert.equal(registry.has('test.com'), false);
|
|
|
|
registry.register('test.com', [
|
|
{ type: 'nats', url: 'nats://test.com', priority: 0 },
|
|
]);
|
|
|
|
assert.equal(registry.has('test.com'), true);
|
|
assert.equal(registry.has('other.com'), false);
|
|
});
|
|
|
|
test('RealmRegistry: realms() lists all registered realms', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('alpha.com', [{ type: 'nats', url: 'nats://alpha.com', priority: 0 }]);
|
|
registry.register('beta.com', [{ type: 'nats', url: 'nats://beta.com', priority: 0 }]);
|
|
registry.register('gamma.com', [{ type: 'nats', url: 'nats://gamma.com', priority: 0 }]);
|
|
|
|
const realms = registry.realms();
|
|
assert.equal(realms.length, 3);
|
|
assert.ok(realms.includes('alpha.com'));
|
|
assert.ok(realms.includes('beta.com'));
|
|
assert.ok(realms.includes('gamma.com'));
|
|
});
|
|
|
|
test('RealmRegistry: register merges endpoints', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
// Register initial endpoint
|
|
registry.register('merge.com', [
|
|
{ type: 'nats', url: 'nats://a.merge.com', priority: 10 },
|
|
]);
|
|
|
|
// Register additional endpoint
|
|
registry.register('merge.com', [
|
|
{ type: 'ws', url: 'ws://b.merge.com', priority: 5 },
|
|
]);
|
|
|
|
const endpoints = registry.resolveAll('merge.com');
|
|
assert.equal(endpoints.length, 2);
|
|
|
|
// ws has higher priority (lower number)
|
|
assert.equal(endpoints[0].type, 'ws');
|
|
assert.equal(endpoints[1].type, 'nats');
|
|
});
|
|
|
|
test('RealmRegistry: register updates existing endpoint by type+url', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('update.com', [
|
|
{ type: 'nats', url: 'nats://broker.update.com', priority: 10 },
|
|
]);
|
|
|
|
// Update same type+url with different priority
|
|
registry.register('update.com', [
|
|
{ type: 'nats', url: 'nats://broker.update.com', priority: 5, shard: '01' },
|
|
]);
|
|
|
|
const endpoints = registry.resolveAll('update.com');
|
|
assert.equal(endpoints.length, 1);
|
|
assert.equal(endpoints[0].priority, 5);
|
|
assert.equal(endpoints[0].shard, '01');
|
|
});
|
|
|
|
test('RealmRegistry: deregister removes entire realm', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('remove.com', [
|
|
{ type: 'nats', url: 'nats://remove.com', priority: 0 },
|
|
{ type: 'ws', url: 'ws://remove.com', priority: 1 },
|
|
]);
|
|
|
|
assert.equal(registry.has('remove.com'), true);
|
|
|
|
registry.deregister('remove.com');
|
|
|
|
assert.equal(registry.has('remove.com'), false);
|
|
assert.equal(registry.resolve('remove.com'), null);
|
|
});
|
|
|
|
test('RealmRegistry: deregister removes specific endpoint', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('partial.com', [
|
|
{ type: 'nats', url: 'nats://a.partial.com', priority: 0 },
|
|
{ type: 'ws', url: 'ws://b.partial.com', priority: 1 },
|
|
]);
|
|
|
|
registry.deregister('partial.com', { type: 'nats', url: 'nats://a.partial.com', priority: 0 });
|
|
|
|
const endpoints = registry.resolveAll('partial.com');
|
|
assert.equal(endpoints.length, 1);
|
|
assert.equal(endpoints[0].type, 'ws');
|
|
});
|
|
|
|
test('RealmRegistry: deregister last endpoint removes realm', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('single.com', [
|
|
{ type: 'nats', url: 'nats://single.com', priority: 0 },
|
|
]);
|
|
|
|
registry.deregister('single.com', { type: 'nats', url: 'nats://single.com', priority: 0 });
|
|
|
|
assert.equal(registry.has('single.com'), false);
|
|
});
|
|
|
|
test('RealmRegistry: watch notifies on changes', () => {
|
|
const registry = new RealmRegistry();
|
|
const notifications: RealmEndpoint[][] = [];
|
|
|
|
const unsub = registry.watch('watch.com', (endpoints) => {
|
|
notifications.push([...endpoints]);
|
|
});
|
|
|
|
// Register
|
|
registry.register('watch.com', [
|
|
{ type: 'nats', url: 'nats://watch.com', priority: 0 },
|
|
]);
|
|
|
|
assert.equal(notifications.length, 1);
|
|
assert.equal(notifications[0].length, 1);
|
|
|
|
// Add another endpoint
|
|
registry.register('watch.com', [
|
|
{ type: 'ws', url: 'ws://watch.com', priority: 1 },
|
|
]);
|
|
|
|
assert.equal(notifications.length, 2);
|
|
assert.equal(notifications[1].length, 2);
|
|
|
|
// Deregister
|
|
registry.deregister('watch.com');
|
|
|
|
assert.equal(notifications.length, 3);
|
|
assert.equal(notifications[2].length, 0);
|
|
|
|
unsub();
|
|
});
|
|
|
|
test('RealmRegistry: watch unsub stops notifications', () => {
|
|
const registry = new RealmRegistry();
|
|
let notificationCount = 0;
|
|
|
|
const unsub = registry.watch('unsub.com', () => {
|
|
notificationCount++;
|
|
});
|
|
|
|
registry.register('unsub.com', [{ type: 'nats', url: 'nats://unsub.com', priority: 0 }]);
|
|
assert.equal(notificationCount, 1);
|
|
|
|
unsub();
|
|
|
|
registry.register('unsub.com', [{ type: 'ws', url: 'ws://unsub.com', priority: 1 }]);
|
|
assert.equal(notificationCount, 1); // No change after unsub
|
|
});
|
|
|
|
test('RealmRegistry: resolve uses cache', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('cache.com', [
|
|
{ type: 'nats', url: 'nats://cache.com', priority: 0 },
|
|
]);
|
|
|
|
const first = registry.resolve('cache.com');
|
|
const second = registry.resolve('cache.com');
|
|
|
|
// Both should return the same object (cached)
|
|
assert.equal(first, second);
|
|
});
|
|
|
|
test('RealmRegistry: register invalidates cache', () => {
|
|
const registry = new RealmRegistry();
|
|
|
|
registry.register('invalidate.com', [
|
|
{ type: 'nats', url: 'nats://old.invalidate.com', priority: 10 },
|
|
]);
|
|
|
|
const before = registry.resolve('invalidate.com');
|
|
assert.equal(before?.url, 'nats://old.invalidate.com');
|
|
|
|
// Register new higher-priority endpoint
|
|
registry.register('invalidate.com', [
|
|
{ type: 'nats', url: 'nats://new.invalidate.com', priority: 0 },
|
|
]);
|
|
|
|
const after = registry.resolve('invalidate.com');
|
|
assert.equal(after?.url, 'nats://new.invalidate.com');
|
|
});
|
|
|
|
// ============================================================================
|
|
// ShardAllocator Tests
|
|
// ============================================================================
|
|
|
|
test('ShardAllocator: allocate always returns DEFAULT_SHARD', () => {
|
|
const allocator = new ShardAllocator();
|
|
|
|
// Different realms should all get same shard (single-shard model)
|
|
assert.equal(allocator.allocate('realm-1'), DEFAULT_SHARD);
|
|
assert.equal(allocator.allocate('realm-2'), DEFAULT_SHARD);
|
|
assert.equal(allocator.allocate('realm-3'), DEFAULT_SHARD);
|
|
});
|
|
|
|
test('ShardAllocator: get always returns DEFAULT_SHARD', () => {
|
|
const allocator = new ShardAllocator();
|
|
|
|
assert.equal(allocator.get('any-realm'), DEFAULT_SHARD);
|
|
assert.equal(allocator.get('another-realm'), DEFAULT_SHARD);
|
|
});
|
|
|
|
test('ShardAllocator: release is no-op', () => {
|
|
const allocator = new ShardAllocator();
|
|
|
|
// Should not throw
|
|
allocator.release('realm');
|
|
allocator.release('nonexistent');
|
|
|
|
// Get still works
|
|
assert.equal(allocator.get('realm'), DEFAULT_SHARD);
|
|
});
|
|
|
|
test('ShardAllocator: allocations returns empty map (single-shard model)', () => {
|
|
const allocator = new ShardAllocator();
|
|
|
|
allocator.allocate('realm-1');
|
|
allocator.allocate('realm-2');
|
|
|
|
// Single-shard model doesn't track allocations
|
|
const allocations = allocator.allocations();
|
|
assert.equal(allocations.size, 0);
|
|
});
|
|
|
|
test('DEFAULT_SHARD is "00"', () => {
|
|
assert.equal(DEFAULT_SHARD, '00');
|
|
});
|
|
|
|
test('allocateShardForTab always returns DEFAULT_SHARD', () => {
|
|
assert.equal(allocateShardForTab('flowpad'), DEFAULT_SHARD);
|
|
assert.equal(allocateShardForTab('flowpad.tab-abc'), DEFAULT_SHARD);
|
|
assert.equal(allocateShardForTab('matrix-3'), DEFAULT_SHARD);
|
|
});
|
|
|
|
test('getGlobalShardAllocator returns singleton', () => {
|
|
const a1 = getGlobalShardAllocator();
|
|
const a2 = getGlobalShardAllocator();
|
|
|
|
assert.equal(a1, a2);
|
|
});
|
|
|
|
// ============================================================================
|
|
// TransportSelector Tests (if exported)
|
|
// ============================================================================
|
|
|
|
test('TransportSelector: disabled mode returns memory endpoint', async () => {
|
|
const { TransportSelector } = await import('../../src/runtime/transport_selector');
|
|
const registry = new RealmRegistry();
|
|
|
|
// In 'disabled' mode, always returns memory endpoint
|
|
const selector = new TransportSelector(registry, 'disabled');
|
|
const endpoint = await selector.select('any.realm');
|
|
|
|
assert.equal(endpoint.type, 'memory');
|
|
assert.equal(endpoint.url, '');
|
|
});
|
|
|
|
test('TransportSelector: auto mode checks registry first', async () => {
|
|
const { TransportSelector } = await import('../../src/runtime/transport_selector');
|
|
const registry = new RealmRegistry();
|
|
|
|
// Register an endpoint
|
|
registry.register('selectable.com', [
|
|
{ type: 'nats', url: 'nats://selectable.com', priority: 0 },
|
|
]);
|
|
|
|
// In auto mode, it will check registry and probe
|
|
// Since we can't easily probe NATS in tests, just verify getCandidates behavior
|
|
const selector = new TransportSelector(registry, 'auto');
|
|
|
|
// Auto mode with no working probes falls back to memory
|
|
const endpoint = await selector.select('selectable.com');
|
|
// Falls back to memory since NATS probe fails without real server
|
|
assert.equal(endpoint.type, 'memory');
|
|
});
|
|
|
|
// ============================================================================
|
|
// TransportPool Tests
|
|
// ============================================================================
|
|
|
|
test('TransportPool: stores and retrieves transport', async () => {
|
|
const { TransportPool } = await import('../../src/runtime/transport_pool');
|
|
const pool = new TransportPool();
|
|
|
|
const mockTransport = {
|
|
publish: () => {},
|
|
subscribe: () => () => {},
|
|
};
|
|
const mockEndpoint = { type: 'memory' as const, url: 'memory://test', priority: 0 };
|
|
|
|
pool.set('test-realm', mockEndpoint, mockTransport);
|
|
|
|
const result = pool.get('test-realm');
|
|
assert.ok(result !== undefined && result !== null);
|
|
assert.equal(result!.transport, mockTransport);
|
|
assert.equal(result!.endpoint, mockEndpoint);
|
|
});
|
|
|
|
test('TransportPool: returns null for unknown realm', async () => {
|
|
const { TransportPool } = await import('../../src/runtime/transport_pool');
|
|
const pool = new TransportPool();
|
|
|
|
const result = pool.get('nonexistent');
|
|
assert.equal(result, null);
|
|
});
|
|
|
|
test('TransportPool: clear removes all entries', async () => {
|
|
const { TransportPool } = await import('../../src/runtime/transport_pool');
|
|
const pool = new TransportPool();
|
|
|
|
const mockTransport = {
|
|
publish: () => {},
|
|
subscribe: () => () => {},
|
|
};
|
|
const mockEndpoint = { type: 'memory' as const, url: 'memory://test', priority: 0 };
|
|
|
|
pool.set('realm-1', mockEndpoint, mockTransport);
|
|
pool.set('realm-2', mockEndpoint, mockTransport);
|
|
|
|
pool.clear();
|
|
|
|
assert.equal(pool.get('realm-1'), null);
|
|
assert.equal(pool.get('realm-2'), null);
|
|
});
|
|
|
|
// ============================================================================
|
|
// Clock Tests
|
|
// ============================================================================
|
|
|
|
test('SystemClock: nowMs returns number', async () => {
|
|
const { SystemClock } = await import('../../src/runtime/clock');
|
|
const clock = new SystemClock();
|
|
|
|
const now = clock.nowMs();
|
|
assert.equal(typeof now, 'number');
|
|
assert.ok(now > 0);
|
|
});
|
|
|
|
test('SystemClock: nowIso returns ISO string', async () => {
|
|
const { SystemClock } = await import('../../src/runtime/clock');
|
|
const clock = new SystemClock();
|
|
|
|
const iso = clock.nowIso();
|
|
assert.equal(typeof iso, 'string');
|
|
assert.ok(iso.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/));
|
|
});
|
|
|
|
test('TestClock: returns configured time', async () => {
|
|
const { TestClock } = await import('../../src/runtime/clock');
|
|
const fixedTime = 1700000000000;
|
|
const clock = new TestClock(fixedTime);
|
|
|
|
assert.equal(clock.nowMs(), fixedTime);
|
|
|
|
// ISO should match fixed time
|
|
const iso = clock.nowIso();
|
|
const parsed = new Date(iso).getTime();
|
|
assert.equal(parsed, fixedTime);
|
|
});
|
|
|
|
test('TestClock: advanceMs moves time forward', async () => {
|
|
const { TestClock } = await import('../../src/runtime/clock');
|
|
const clock = new TestClock(1000);
|
|
|
|
assert.equal(clock.nowMs(), 1000);
|
|
|
|
clock.advanceMs(500);
|
|
assert.equal(clock.nowMs(), 1500);
|
|
|
|
clock.advanceMs(1000);
|
|
assert.equal(clock.nowMs(), 2500);
|
|
});
|