Core Changes: - Completely rewrote CustomResolver reducer with dependency-ordered processing - Enhanced plugin initialization with proper dependency injection - Improved delta processing and property value tracking - Added robust error handling for duplicate property IDs Resolver Improvements: - Updated to use new accumulator structure - Implemented execution order processing for plugins - Enhanced debug logging and error reporting - Simplified TimestampResolver by removing unused initializer Configuration Updates: - Added TypeScript path aliases for test helpers - Improved module resolution paths Key Benefits: - More robust plugin dependency management - More efficient state updates - Enhanced type safety - Better error messages and debugging - More consistent plugin initialization This refactoring focuses on improving the robustness of the resolver, especially around plugin lifecycle management and dependency handling. The changes ensure better separation of concerns and more predictable behavior when dealing with complex plugin dependencies.
120 lines
3.4 KiB
TypeScript
120 lines
3.4 KiB
TypeScript
import Debug from 'debug';
|
|
import { createOrchestrator } from '@src/orchestration';
|
|
import type { NodeConfig, NodeHandle } from '@src/orchestration';
|
|
|
|
// Increase test timeout to 30 seconds
|
|
jest.setTimeout(30000);
|
|
|
|
const debug = Debug('rz:test:two-orchestrated');
|
|
|
|
describe('Run (Two Nodes Orchestrated)', () => {
|
|
const orchestrator = createOrchestrator('in-memory');
|
|
// Define a type that includes all required methods
|
|
type FullNodeHandle = NodeHandle & {
|
|
getRequestPort: () => number;
|
|
getApiUrl: () => string;
|
|
};
|
|
|
|
const nodes: FullNodeHandle[] = [];
|
|
const nodeIds = ['app-002-A', 'app-002-B'];
|
|
|
|
beforeAll(async () => {
|
|
|
|
// Start first node
|
|
const node1Config: NodeConfig = {
|
|
id: nodeIds[0],
|
|
};
|
|
const node1 = (await orchestrator.startNode(node1Config)) as FullNodeHandle;
|
|
|
|
// Start second node with first node as bootstrap peer
|
|
const node2Config: NodeConfig = {
|
|
id: nodeIds[1],
|
|
network: {
|
|
bootstrapPeers: [`localhost:${node1.getRequestPort()}`],
|
|
},
|
|
};
|
|
const node2 = (await orchestrator.startNode(node2Config)) as FullNodeHandle;
|
|
|
|
nodes.push(node1, node2);
|
|
|
|
// Connect the nodes
|
|
await orchestrator.connectNodes(node1, node2);
|
|
}, 120000); // Increase timeout to 120s for this hook
|
|
|
|
afterAll(async () => {
|
|
// Stop all nodes in parallel
|
|
await Promise.all(nodes.map(node => node && orchestrator.stopNode(node)));
|
|
});
|
|
|
|
test('can create a record on node0 and read it from node1', async () => {
|
|
const [node0, node1] = nodes;
|
|
const node0Url = node0.getApiUrl();
|
|
const node1Url = node1.getApiUrl();
|
|
|
|
debug(`Node 0 URL: ${node0Url}`);
|
|
debug(`Node 1 URL: ${node1Url}`);
|
|
|
|
// Create a new record on node0
|
|
const createResponse = await fetch(`${node0Url}/user`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
id: 'peon-1',
|
|
properties: {
|
|
name: 'Peon',
|
|
age: 741,
|
|
},
|
|
}),
|
|
});
|
|
|
|
const createdUser = await createResponse.json();
|
|
expect(createdUser).toMatchObject({
|
|
id: 'peon-1',
|
|
properties: {
|
|
name: 'Peon',
|
|
age: 741,
|
|
},
|
|
});
|
|
|
|
// Small delay to allow for synchronization
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
// Read the record from node1
|
|
const getResponse = await fetch(`${node1Url}/user/peon-1`);
|
|
const fetchedUser = await getResponse.json();
|
|
|
|
expect(fetchedUser).toMatchObject({
|
|
id: 'peon-1',
|
|
properties: {
|
|
name: 'Peon',
|
|
age: 741,
|
|
},
|
|
});
|
|
});
|
|
|
|
it.skip('can demonstrate network partitioning', async () => {
|
|
// This test shows how we can simulate network partitions
|
|
// For now, it's just a placeholder since we'd need to implement
|
|
// the actual partitioning logic in the InMemoryOrchestrator
|
|
const [node0, node1] = nodes;
|
|
|
|
// Simulate partition (actual implementation would use orchestrator.partitionNetwork)
|
|
debug('Simulating network partition between nodes');
|
|
// await orchestrator.partitionNetwork({
|
|
// groups: [[node0.id], [node1.id]]
|
|
// });
|
|
|
|
// Test behavior during partition...
|
|
|
|
// Heal partition
|
|
// await orchestrator.partitionNetwork({
|
|
// groups: [[node0.id, node1.id]]
|
|
// });
|
|
|
|
// Test behavior after healing...
|
|
|
|
// Mark test as passed (remove once actual test is implemented)
|
|
expect(true).toBe(true);
|
|
});
|
|
});
|