@olane/o-node 0.7.13-alpha.0 → 0.7.13-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts +1 -0
- package/dist/src/connection/interfaces/o-node-connection-manager.config.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.d.ts +0 -1
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +0 -8
- package/dist/src/connection/o-node-connection.manager.d.ts +41 -4
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +187 -45
- package/dist/src/connection/stream-handler.d.ts.map +1 -1
- package/dist/src/connection/stream-handler.js +0 -2
- package/dist/src/managers/o-connection-heartbeat.manager.d.ts.map +1 -1
- package/dist/src/managers/o-connection-heartbeat.manager.js +15 -1
- package/dist/src/managers/o-reconnection.manager.d.ts.map +1 -1
- package/dist/src/managers/o-reconnection.manager.js +12 -7
- package/dist/src/o-node.d.ts +19 -0
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +89 -11
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +5 -0
- package/dist/src/router/o-node.router.d.ts.map +1 -1
- package/dist/src/router/o-node.router.js +16 -6
- package/dist/src/router/o-node.routing-policy.d.ts.map +1 -1
- package/dist/src/router/o-node.routing-policy.js +4 -0
- package/dist/test/connection-management.spec.d.ts +2 -0
- package/dist/test/connection-management.spec.d.ts.map +1 -0
- package/dist/test/connection-management.spec.js +370 -0
- package/dist/test/helpers/connection-spy.d.ts +124 -0
- package/dist/test/helpers/connection-spy.d.ts.map +1 -0
- package/dist/test/helpers/connection-spy.js +229 -0
- package/dist/test/helpers/index.d.ts +6 -0
- package/dist/test/helpers/index.d.ts.map +1 -0
- package/dist/test/helpers/index.js +12 -0
- package/dist/test/helpers/network-builder.d.ts +109 -0
- package/dist/test/helpers/network-builder.d.ts.map +1 -0
- package/dist/test/helpers/network-builder.js +309 -0
- package/dist/test/helpers/simple-node-builder.d.ts +50 -0
- package/dist/test/helpers/simple-node-builder.d.ts.map +1 -0
- package/dist/test/helpers/simple-node-builder.js +66 -0
- package/dist/test/helpers/test-environment.d.ts +140 -0
- package/dist/test/helpers/test-environment.d.ts.map +1 -0
- package/dist/test/helpers/test-environment.js +184 -0
- package/dist/test/helpers/test-node.tool.d.ts +31 -0
- package/dist/test/helpers/test-node.tool.d.ts.map +1 -1
- package/dist/test/helpers/test-node.tool.js +49 -0
- package/dist/test/leader-transport-validation.spec.d.ts +2 -0
- package/dist/test/leader-transport-validation.spec.d.ts.map +1 -0
- package/dist/test/leader-transport-validation.spec.js +177 -0
- package/dist/test/network-communication.spec.d.ts +2 -0
- package/dist/test/network-communication.spec.d.ts.map +1 -0
- package/dist/test/network-communication.spec.js +256 -0
- package/dist/test/o-node.spec.d.ts +2 -0
- package/dist/test/o-node.spec.d.ts.map +1 -0
- package/dist/test/o-node.spec.js +247 -0
- package/dist/test/parent-child-registration.spec.d.ts +2 -0
- package/dist/test/parent-child-registration.spec.d.ts.map +1 -0
- package/dist/test/parent-child-registration.spec.js +177 -0
- package/dist/test/search-resolver.spec.d.ts +2 -0
- package/dist/test/search-resolver.spec.d.ts.map +1 -0
- package/dist/test/search-resolver.spec.js +648 -0
- package/package.json +12 -7
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TestEnvironment - Core test setup and lifecycle management for O-Network nodes
|
|
3
|
+
*
|
|
4
|
+
* Provides automatic cleanup, node factories, and common test utilities
|
|
5
|
+
* to eliminate boilerplate in O-Network package tests.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* describe('MyTool', () => {
|
|
10
|
+
* const env = new TestEnvironment();
|
|
11
|
+
*
|
|
12
|
+
* afterEach(async () => {
|
|
13
|
+
* await env.cleanup();
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* it('should work', async () => {
|
|
17
|
+
* const node = await env.createNode(MyTool);
|
|
18
|
+
* expect(node.state).to.equal(NodeState.RUNNING);
|
|
19
|
+
* });
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { NodeState } from '@olane/o-core';
|
|
24
|
+
/**
|
|
25
|
+
* Core test environment class for O-Network testing
|
|
26
|
+
*
|
|
27
|
+
* Manages node lifecycle, automatic cleanup, and provides
|
|
28
|
+
* factory methods for common test scenarios.
|
|
29
|
+
*
|
|
30
|
+
* Note: This class does not include leader-related utilities to avoid
|
|
31
|
+
* circular dependencies with @olane/o-leader. Packages that need leader
|
|
32
|
+
* functionality should implement their own test utilities.
|
|
33
|
+
*/
|
|
34
|
+
export class TestEnvironment {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.nodes = [];
|
|
37
|
+
this.cleanupCallbacks = [];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a node
|
|
41
|
+
*
|
|
42
|
+
* @param NodeClass - Node class to instantiate
|
|
43
|
+
* @param config - Node configuration
|
|
44
|
+
* @param autoStart - Whether to start node automatically (default: true)
|
|
45
|
+
* @returns Node instance
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const node = await env.createNode(MyTool, {
|
|
50
|
+
* address: new oNodeAddress('o://test')
|
|
51
|
+
* });
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
async createNode(NodeClass, config = {}, autoStart = true) {
|
|
55
|
+
const node = new NodeClass({
|
|
56
|
+
parent: null,
|
|
57
|
+
leader: null,
|
|
58
|
+
...config,
|
|
59
|
+
});
|
|
60
|
+
this.track(node);
|
|
61
|
+
if (autoStart) {
|
|
62
|
+
await node.start();
|
|
63
|
+
}
|
|
64
|
+
return node;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Track a node for automatic cleanup
|
|
68
|
+
*
|
|
69
|
+
* @param node - Node instance to track
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* const node = new MyNode({});
|
|
74
|
+
* env.track(node);
|
|
75
|
+
* await node.start();
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
track(node) {
|
|
79
|
+
this.nodes.push(node);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Register a cleanup callback
|
|
83
|
+
*
|
|
84
|
+
* Useful for cleaning up external resources (databases, files, etc.)
|
|
85
|
+
*
|
|
86
|
+
* @param callback - Async cleanup function
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const db = await createTestDB();
|
|
91
|
+
* env.onCleanup(async () => {
|
|
92
|
+
* await db.close();
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
onCleanup(callback) {
|
|
97
|
+
this.cleanupCallbacks.push(callback);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Stop all tracked nodes and execute cleanup callbacks
|
|
101
|
+
*
|
|
102
|
+
* Stops nodes in reverse order (children before parents)
|
|
103
|
+
* Call this in afterEach hooks.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* afterEach(async () => {
|
|
108
|
+
* await env.cleanup();
|
|
109
|
+
* });
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
async cleanup() {
|
|
113
|
+
// Stop nodes in reverse order (children first)
|
|
114
|
+
const nodesToStop = [...this.nodes].reverse();
|
|
115
|
+
for (const node of nodesToStop) {
|
|
116
|
+
try {
|
|
117
|
+
if (node.state === NodeState.RUNNING) {
|
|
118
|
+
await node.stop();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error('Error stopping node:', error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Execute cleanup callbacks
|
|
126
|
+
for (const callback of this.cleanupCallbacks) {
|
|
127
|
+
try {
|
|
128
|
+
await callback();
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error('Error in cleanup callback:', error);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Clear tracking
|
|
135
|
+
this.nodes = [];
|
|
136
|
+
this.cleanupCallbacks = [];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get all tracked nodes
|
|
140
|
+
*
|
|
141
|
+
* @returns Array of tracked node instances
|
|
142
|
+
*/
|
|
143
|
+
getNodes() {
|
|
144
|
+
return [...this.nodes];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get count of tracked nodes
|
|
148
|
+
*
|
|
149
|
+
* @returns Number of tracked nodes
|
|
150
|
+
*/
|
|
151
|
+
getNodeCount() {
|
|
152
|
+
return this.nodes.length;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Check if all tracked nodes are stopped
|
|
156
|
+
*
|
|
157
|
+
* @returns True if all nodes are stopped
|
|
158
|
+
*/
|
|
159
|
+
allNodesStopped() {
|
|
160
|
+
return this.nodes.every(node => node.state === NodeState.STOPPED);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Wait for a condition to be true
|
|
164
|
+
*
|
|
165
|
+
* @param condition - Function that returns true when condition is met
|
|
166
|
+
* @param timeoutMs - Maximum time to wait in milliseconds (default: 5000)
|
|
167
|
+
* @param intervalMs - Check interval in milliseconds (default: 100)
|
|
168
|
+
* @returns Promise that resolves when condition is met or rejects on timeout
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* await env.waitFor(() => tool.isReady, 10000);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
async waitFor(condition, timeoutMs = 5000, intervalMs = 100) {
|
|
176
|
+
const startTime = Date.now();
|
|
177
|
+
while (!condition()) {
|
|
178
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
179
|
+
throw new Error(`Timeout waiting for condition after ${timeoutMs}ms`);
|
|
180
|
+
}
|
|
181
|
+
await new Promise(resolve => setTimeout(resolve, intervalMs));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -1,14 +1,45 @@
|
|
|
1
1
|
import { oNodeTool } from '../../src/o-node.tool.js';
|
|
2
|
+
import { oNodeToolConfig } from '../../src/interfaces/o-node.tool-config.js';
|
|
3
|
+
import { Libp2pConfig } from '@olane/o-config';
|
|
2
4
|
/**
|
|
3
5
|
* Test-only extension of oNodeTool that adds streaming test methods.
|
|
4
6
|
* This class should only be used in test files and is not part of the production code.
|
|
7
|
+
*
|
|
8
|
+
* Compatible with TestEnvironment for automatic cleanup and lifecycle management.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { TestEnvironment } from './helpers/index.js';
|
|
13
|
+
* import { TestNodeTool } from './helpers/test-node.tool.js';
|
|
14
|
+
*
|
|
15
|
+
* const env = new TestEnvironment();
|
|
16
|
+
* const tool = new TestNodeTool({ address: new oNodeAddress('o://test') });
|
|
17
|
+
* await tool.start();
|
|
18
|
+
* // TestEnvironment will handle cleanup automatically
|
|
19
|
+
* ```
|
|
5
20
|
*/
|
|
6
21
|
export declare class TestNodeTool extends oNodeTool {
|
|
22
|
+
constructor(config: oNodeToolConfig);
|
|
23
|
+
configure(): Promise<Libp2pConfig>;
|
|
7
24
|
/**
|
|
8
25
|
* Test method that emits chunks for 10 seconds at 100ms intervals.
|
|
9
26
|
* Used for testing streaming functionality across hierarchical networks.
|
|
10
27
|
*
|
|
28
|
+
* This method demonstrates streaming responses with AsyncGenerator,
|
|
29
|
+
* which is a common pattern for real-time data processing and long-running operations.
|
|
30
|
+
*
|
|
11
31
|
* @returns AsyncGenerator that yields 100 chunks over 10 seconds
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const response = await tool.use(tool.address, {
|
|
35
|
+
* method: 'test_stream',
|
|
36
|
+
* params: {}
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* for await (const chunk of response) {
|
|
40
|
+
* console.log(`Received chunk ${chunk.chunk}`);
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
12
43
|
*/
|
|
13
44
|
_tool_test_stream(): AsyncGenerator<any>;
|
|
14
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-node.tool.d.ts","sourceRoot":"","sources":["../../../test/helpers/test-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"test-node.tool.d.ts","sourceRoot":"","sources":["../../../test/helpers/test-node.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,YAAa,SAAQ,SAAS;gBAC7B,MAAM,EAAE,eAAe;IAO7B,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;IAcxC;;;;;;;;;;;;;;;;;;;OAmBG;IACI,iBAAiB,IAAI,cAAc,CAAC,GAAG,CAAC;CAiBhD"}
|
|
@@ -1,14 +1,61 @@
|
|
|
1
1
|
import { oNodeTool } from '../../src/o-node.tool.js';
|
|
2
|
+
import { oNodeAddress } from '../../src/index.js';
|
|
2
3
|
/**
|
|
3
4
|
* Test-only extension of oNodeTool that adds streaming test methods.
|
|
4
5
|
* This class should only be used in test files and is not part of the production code.
|
|
6
|
+
*
|
|
7
|
+
* Compatible with TestEnvironment for automatic cleanup and lifecycle management.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { TestEnvironment } from './helpers/index.js';
|
|
12
|
+
* import { TestNodeTool } from './helpers/test-node.tool.js';
|
|
13
|
+
*
|
|
14
|
+
* const env = new TestEnvironment();
|
|
15
|
+
* const tool = new TestNodeTool({ address: new oNodeAddress('o://test') });
|
|
16
|
+
* await tool.start();
|
|
17
|
+
* // TestEnvironment will handle cleanup automatically
|
|
18
|
+
* ```
|
|
5
19
|
*/
|
|
6
20
|
export class TestNodeTool extends oNodeTool {
|
|
21
|
+
constructor(config) {
|
|
22
|
+
super({
|
|
23
|
+
...config,
|
|
24
|
+
address: new oNodeAddress('o://test')
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async configure() {
|
|
28
|
+
const config = await super.configure();
|
|
29
|
+
config.connectionGater = {
|
|
30
|
+
denyDialPeer: (peerId) => {
|
|
31
|
+
return false;
|
|
32
|
+
},
|
|
33
|
+
// who can call us?
|
|
34
|
+
denyInboundEncryptedConnection: (peerId, maConn) => {
|
|
35
|
+
return false;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
return config;
|
|
39
|
+
}
|
|
7
40
|
/**
|
|
8
41
|
* Test method that emits chunks for 10 seconds at 100ms intervals.
|
|
9
42
|
* Used for testing streaming functionality across hierarchical networks.
|
|
10
43
|
*
|
|
44
|
+
* This method demonstrates streaming responses with AsyncGenerator,
|
|
45
|
+
* which is a common pattern for real-time data processing and long-running operations.
|
|
46
|
+
*
|
|
11
47
|
* @returns AsyncGenerator that yields 100 chunks over 10 seconds
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const response = await tool.use(tool.address, {
|
|
51
|
+
* method: 'test_stream',
|
|
52
|
+
* params: {}
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* for await (const chunk of response) {
|
|
56
|
+
* console.log(`Received chunk ${chunk.chunk}`);
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
12
59
|
*/
|
|
13
60
|
async *_tool_test_stream() {
|
|
14
61
|
const totalDuration = 10000; // 10 seconds
|
|
@@ -17,9 +64,11 @@ export class TestNodeTool extends oNodeTool {
|
|
|
17
64
|
for (let i = 0; i < totalChunks; i++) {
|
|
18
65
|
yield {
|
|
19
66
|
chunk: i + 1,
|
|
67
|
+
total: totalChunks,
|
|
20
68
|
timestamp: new Date().toISOString(),
|
|
21
69
|
nodeAddress: this.address.toString(),
|
|
22
70
|
message: `Chunk ${i + 1} of ${totalChunks}`,
|
|
71
|
+
progress: ((i + 1) / totalChunks) * 100,
|
|
23
72
|
};
|
|
24
73
|
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
25
74
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leader-transport-validation.spec.d.ts","sourceRoot":"","sources":["../../test/leader-transport-validation.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { TestEnvironment } from './helpers/index.js';
|
|
3
|
+
import { oNodeTool } from '../src/o-node.tool.js';
|
|
4
|
+
import { oNodeAddress, oNodeTransport } from '../src/index.js';
|
|
5
|
+
describe('Leader Transport Validation', () => {
|
|
6
|
+
const env = new TestEnvironment();
|
|
7
|
+
afterEach(async () => {
|
|
8
|
+
await env.cleanup();
|
|
9
|
+
});
|
|
10
|
+
describe('Node with leader configuration', () => {
|
|
11
|
+
it('should fail to start when leader has no transports', async () => {
|
|
12
|
+
const leaderAddress = new oNodeAddress('o://leader', []); // Empty transports
|
|
13
|
+
const node = new oNodeTool({
|
|
14
|
+
address: new oNodeAddress('o://child'),
|
|
15
|
+
leader: leaderAddress,
|
|
16
|
+
parent: null,
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
await node.start();
|
|
20
|
+
expect.fail('Expected node.start() to throw an error');
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
expect(error.message).to.include('Leader address is defined');
|
|
24
|
+
expect(error.message).to.include('but has no transports');
|
|
25
|
+
expect(error.message).to.include('o://leader');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
it('should fail to start when leader has undefined transports', async () => {
|
|
29
|
+
const leaderAddress = new oNodeAddress('o://leader');
|
|
30
|
+
// Explicitly set transports to undefined
|
|
31
|
+
leaderAddress.transports = undefined;
|
|
32
|
+
const node = new oNodeTool({
|
|
33
|
+
address: new oNodeAddress('o://child'),
|
|
34
|
+
leader: leaderAddress,
|
|
35
|
+
parent: null,
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
await node.start();
|
|
39
|
+
expect.fail('Expected node.start() to throw an error');
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
expect(error.message).to.include('Leader address is defined');
|
|
43
|
+
expect(error.message).to.include('but has no transports');
|
|
44
|
+
expect(error.message).to.include('o://leader');
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
it('should fail to start when leader has null transports', async () => {
|
|
48
|
+
const leaderAddress = new oNodeAddress('o://leader');
|
|
49
|
+
// Explicitly set transports to null
|
|
50
|
+
leaderAddress.transports = null;
|
|
51
|
+
const node = new oNodeTool({
|
|
52
|
+
address: new oNodeAddress('o://child'),
|
|
53
|
+
leader: leaderAddress,
|
|
54
|
+
parent: null,
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
await node.start();
|
|
58
|
+
expect.fail('Expected node.start() to throw an error');
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
expect(error.message).to.include('Leader address is defined');
|
|
62
|
+
expect(error.message).to.include('but has no transports');
|
|
63
|
+
expect(error.message).to.include('o://leader');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
it('should start successfully when leader has valid transports', async () => {
|
|
67
|
+
const leaderAddress = new oNodeAddress('o://leader', [
|
|
68
|
+
new oNodeTransport('/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWTest123'),
|
|
69
|
+
]);
|
|
70
|
+
const node = new oNodeTool({
|
|
71
|
+
address: new oNodeAddress('o://child'),
|
|
72
|
+
leader: leaderAddress,
|
|
73
|
+
parent: null,
|
|
74
|
+
});
|
|
75
|
+
// Should not throw
|
|
76
|
+
await node.start();
|
|
77
|
+
expect(node.state).to.not.equal('STOPPED');
|
|
78
|
+
await node.stop();
|
|
79
|
+
});
|
|
80
|
+
it('should start successfully when leader has multiple transports', async () => {
|
|
81
|
+
const leaderAddress = new oNodeAddress('o://leader', [
|
|
82
|
+
new oNodeTransport('/ip4/127.0.0.1/tcp/4001/p2p/12D3KooWTest123'),
|
|
83
|
+
new oNodeTransport('/ip4/192.168.1.1/tcp/4001/p2p/12D3KooWTest123'),
|
|
84
|
+
]);
|
|
85
|
+
const node = new oNodeTool({
|
|
86
|
+
address: new oNodeAddress('o://child'),
|
|
87
|
+
leader: leaderAddress,
|
|
88
|
+
parent: null,
|
|
89
|
+
});
|
|
90
|
+
// Should not throw
|
|
91
|
+
await node.start();
|
|
92
|
+
expect(node.state).to.not.equal('STOPPED');
|
|
93
|
+
await node.stop();
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
describe('Node without leader configuration', () => {
|
|
97
|
+
it('should start successfully when leader is null', async () => {
|
|
98
|
+
const node = new oNodeTool({
|
|
99
|
+
address: new oNodeAddress('o://standalone'),
|
|
100
|
+
leader: null,
|
|
101
|
+
parent: null,
|
|
102
|
+
});
|
|
103
|
+
// Should not throw
|
|
104
|
+
await node.start();
|
|
105
|
+
expect(node.state).to.not.equal('STOPPED');
|
|
106
|
+
await node.stop();
|
|
107
|
+
});
|
|
108
|
+
it('should start successfully when leader is undefined', async () => {
|
|
109
|
+
const node = new oNodeTool({
|
|
110
|
+
address: new oNodeAddress('o://standalone'),
|
|
111
|
+
leader: undefined, // Explicitly undefined
|
|
112
|
+
parent: null,
|
|
113
|
+
});
|
|
114
|
+
// Should not throw
|
|
115
|
+
await node.start();
|
|
116
|
+
expect(node.state).to.not.equal('STOPPED');
|
|
117
|
+
await node.stop();
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe('Leader node (self-referential)', () => {
|
|
121
|
+
it('should start successfully as a leader without transports validation', async () => {
|
|
122
|
+
const node = new oNodeTool({
|
|
123
|
+
address: new oNodeAddress('o://leader'),
|
|
124
|
+
leader: null, // Leader nodes don't need a leader reference
|
|
125
|
+
parent: null,
|
|
126
|
+
type: 'LEADER', // Set as leader node
|
|
127
|
+
});
|
|
128
|
+
// Should not throw - leader nodes don't need leader transports
|
|
129
|
+
await node.start();
|
|
130
|
+
expect(node.state).to.not.equal('STOPPED');
|
|
131
|
+
await node.stop();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe('Error message content', () => {
|
|
135
|
+
it('should provide helpful error message with leader address', async () => {
|
|
136
|
+
const leaderAddress = new oNodeAddress('o://my-custom-leader', []);
|
|
137
|
+
const node = new oNodeTool({
|
|
138
|
+
address: new oNodeAddress('o://child'),
|
|
139
|
+
leader: leaderAddress,
|
|
140
|
+
parent: null,
|
|
141
|
+
});
|
|
142
|
+
try {
|
|
143
|
+
await node.start();
|
|
144
|
+
expect.fail('Expected node.start() to throw an error');
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
expect(error.message).to.include('o://my-custom-leader');
|
|
148
|
+
expect(error.message).to.include('Non-leader nodes require leader transports');
|
|
149
|
+
expect(error.message).to.include('Please provide transports');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('Validation timing', () => {
|
|
154
|
+
it('should fail before p2pNode creation (fast fail)', async () => {
|
|
155
|
+
const leaderAddress = new oNodeAddress('o://leader', []);
|
|
156
|
+
const node = new oNodeTool({
|
|
157
|
+
address: new oNodeAddress('o://child'),
|
|
158
|
+
leader: leaderAddress,
|
|
159
|
+
parent: null,
|
|
160
|
+
});
|
|
161
|
+
const startTime = Date.now();
|
|
162
|
+
try {
|
|
163
|
+
await node.start();
|
|
164
|
+
expect.fail('Expected node.start() to throw an error');
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const duration = Date.now() - startTime;
|
|
168
|
+
// Validation should happen very quickly (< 100ms)
|
|
169
|
+
// If it takes longer, it means we're doing expensive operations before validation
|
|
170
|
+
expect(duration).to.be.lessThan(100);
|
|
171
|
+
expect(error.message).to.include('Leader address is defined');
|
|
172
|
+
// Verify p2pNode was never created
|
|
173
|
+
expect(node.p2pNode).to.be.undefined;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network-communication.spec.d.ts","sourceRoot":"","sources":["../../test/network-communication.spec.ts"],"names":[],"mappings":""}
|