@olane/o-node 0.7.12 → 0.7.13-alpha.1
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 +33 -4
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +153 -44
- 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 +5 -0
- package/dist/src/o-node.d.ts.map +1 -1
- package/dist/src/o-node.js +46 -8
- 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/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,256 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { TestEnvironment } from './helpers/index.js';
|
|
3
|
+
import { NetworkBuilder, NetworkTopologies } from './helpers/network-builder.js';
|
|
4
|
+
import { createConnectionSpy } from './helpers/connection-spy.js';
|
|
5
|
+
import { oNodeAddress } from '../src/router/o-node.address.js';
|
|
6
|
+
import { oErrorCodes } from '@olane/o-core';
|
|
7
|
+
describe('Network Communication', () => {
|
|
8
|
+
const env = new TestEnvironment();
|
|
9
|
+
let builder;
|
|
10
|
+
afterEach(async () => {
|
|
11
|
+
if (builder) {
|
|
12
|
+
await builder.cleanup();
|
|
13
|
+
}
|
|
14
|
+
await env.cleanup();
|
|
15
|
+
});
|
|
16
|
+
describe('Two-Node Direct Communication', () => {
|
|
17
|
+
it('should establish connection between parent and child', async () => {
|
|
18
|
+
builder = await NetworkTopologies.twoNode();
|
|
19
|
+
const leader = builder.getNode('o://leader');
|
|
20
|
+
const child = builder.getNode('o://child');
|
|
21
|
+
// Verify child has leader transports
|
|
22
|
+
expect(child.address.libp2pTransports.length).to.be.greaterThan(0);
|
|
23
|
+
// Create connection spy
|
|
24
|
+
const spy = createConnectionSpy(leader);
|
|
25
|
+
spy.start();
|
|
26
|
+
// Make a call from leader to child
|
|
27
|
+
const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
28
|
+
method: 'echo',
|
|
29
|
+
params: { message: 'hello from leader' },
|
|
30
|
+
});
|
|
31
|
+
expect(response.result.success).to.be.true;
|
|
32
|
+
expect(response.result.data.message).to.equal('hello from leader');
|
|
33
|
+
expect(response.result.data.nodeAddress).to.include('child');
|
|
34
|
+
// Verify connection was established
|
|
35
|
+
const summary = spy.getSummary();
|
|
36
|
+
expect(summary.currentConnections).to.be.greaterThan(0);
|
|
37
|
+
spy.stop();
|
|
38
|
+
});
|
|
39
|
+
it('should allow bidirectional communication', async () => {
|
|
40
|
+
builder = await NetworkTopologies.twoNode();
|
|
41
|
+
const leader = builder.getNode('o://leader');
|
|
42
|
+
const child = builder.getNode('o://child');
|
|
43
|
+
// Leader → Child
|
|
44
|
+
const response1 = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
45
|
+
method: 'echo',
|
|
46
|
+
params: { message: 'from leader' },
|
|
47
|
+
});
|
|
48
|
+
expect(response1.result.success).to.be.true;
|
|
49
|
+
expect(response1.result.data.message).to.equal('from leader');
|
|
50
|
+
// Child → Leader
|
|
51
|
+
const response2 = await child.use(new oNodeAddress(leader.address.toString(), leader.address.libp2pTransports), {
|
|
52
|
+
method: 'get_info',
|
|
53
|
+
params: {},
|
|
54
|
+
});
|
|
55
|
+
expect(response2.result.success).to.be.true;
|
|
56
|
+
expect(response2.result.data.address).to.include('leader');
|
|
57
|
+
});
|
|
58
|
+
it('should reuse connections for multiple requests', async () => {
|
|
59
|
+
builder = await NetworkTopologies.twoNode();
|
|
60
|
+
const leader = builder.getNode('o://leader');
|
|
61
|
+
const child = builder.getNode('o://child');
|
|
62
|
+
const spy = createConnectionSpy(leader);
|
|
63
|
+
spy.start();
|
|
64
|
+
// Make multiple requests
|
|
65
|
+
for (let i = 0; i < 5; i++) {
|
|
66
|
+
const response = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
67
|
+
method: 'echo',
|
|
68
|
+
params: { message: `request ${i}` },
|
|
69
|
+
});
|
|
70
|
+
expect(response.result.success).to.be.true;
|
|
71
|
+
}
|
|
72
|
+
// Should have only 1 connection (reused)
|
|
73
|
+
const summary = spy.getSummary();
|
|
74
|
+
expect(summary.currentConnections).to.equal(1);
|
|
75
|
+
spy.stop();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
describe('Three-Node Hierarchical Communication', () => {
|
|
79
|
+
it('should route through hierarchy (leader → parent → child)', async () => {
|
|
80
|
+
builder = await NetworkTopologies.threeNode();
|
|
81
|
+
const leader = builder.getNode('o://leader');
|
|
82
|
+
const parent = builder.getNode('o://parent');
|
|
83
|
+
const child = builder.getNode('o://child');
|
|
84
|
+
// Leader → Child (should route through parent)
|
|
85
|
+
const response = await leader.use(child.address, {
|
|
86
|
+
method: 'echo',
|
|
87
|
+
params: { message: 'hello from leader' },
|
|
88
|
+
});
|
|
89
|
+
expect(response.result.success).to.be.true;
|
|
90
|
+
expect(response.result.data.message).to.equal('hello from leader');
|
|
91
|
+
expect(response.result.data.nodeAddress).to.include('child');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('Self-Routing Optimization', () => {
|
|
95
|
+
it('should execute locally when routing to self', async () => {
|
|
96
|
+
builder = await NetworkTopologies.twoNode();
|
|
97
|
+
const leader = builder.getNode('o://leader');
|
|
98
|
+
const spy = createConnectionSpy(leader);
|
|
99
|
+
spy.start();
|
|
100
|
+
const initialStreamCount = spy.getTotalStreamCount();
|
|
101
|
+
// Call self
|
|
102
|
+
const response = await leader.use(leader.address, {
|
|
103
|
+
method: 'get_info',
|
|
104
|
+
params: {},
|
|
105
|
+
});
|
|
106
|
+
expect(response.result.success).to.be.true;
|
|
107
|
+
expect(response.result.data.address).to.include('leader');
|
|
108
|
+
// Stream count should not increase (no network call)
|
|
109
|
+
const finalStreamCount = spy.getTotalStreamCount();
|
|
110
|
+
expect(finalStreamCount).to.equal(initialStreamCount);
|
|
111
|
+
spy.stop();
|
|
112
|
+
});
|
|
113
|
+
it('should handle self-routing with different address formats', async () => {
|
|
114
|
+
builder = new NetworkBuilder();
|
|
115
|
+
const leader = await builder.addNode('o://leader');
|
|
116
|
+
// Call with exact address
|
|
117
|
+
const response1 = await leader.use(leader.address, {
|
|
118
|
+
method: 'get_info',
|
|
119
|
+
params: {},
|
|
120
|
+
});
|
|
121
|
+
expect(response1.result.success).to.be.true;
|
|
122
|
+
// Call with address string (should also detect self)
|
|
123
|
+
const response2 = await leader.use(new oNodeAddress('o://leader'), {
|
|
124
|
+
method: 'get_info',
|
|
125
|
+
params: {},
|
|
126
|
+
});
|
|
127
|
+
expect(response2.result.success).to.be.true;
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe('Method Execution', () => {
|
|
131
|
+
it('should execute tool methods correctly', async () => {
|
|
132
|
+
builder = await NetworkTopologies.twoNode();
|
|
133
|
+
const leader = builder.getNode('o://leader');
|
|
134
|
+
const child = builder.getNode('o://child');
|
|
135
|
+
// Test echo method
|
|
136
|
+
const echoResponse = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
137
|
+
method: 'echo',
|
|
138
|
+
params: { message: 'test message' },
|
|
139
|
+
});
|
|
140
|
+
expect(echoResponse.result.success).to.be.true;
|
|
141
|
+
expect(echoResponse.result.data.message).to.equal('test message');
|
|
142
|
+
expect(echoResponse.result.data.timestamp).to.be.a('number');
|
|
143
|
+
// Test get_info method
|
|
144
|
+
const infoResponse = await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
145
|
+
method: 'get_info',
|
|
146
|
+
params: {},
|
|
147
|
+
});
|
|
148
|
+
expect(infoResponse.result.success).to.be.true;
|
|
149
|
+
expect(infoResponse.result.data.address).to.be.a('string');
|
|
150
|
+
expect(infoResponse.result.data.callCount).to.equal(1); // One echo call
|
|
151
|
+
});
|
|
152
|
+
it('should handle method not found errors', async () => {
|
|
153
|
+
builder = await NetworkTopologies.twoNode();
|
|
154
|
+
const leader = builder.getNode('o://leader');
|
|
155
|
+
const child = builder.getNode('o://child');
|
|
156
|
+
await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
157
|
+
method: 'non_existent_method',
|
|
158
|
+
params: {},
|
|
159
|
+
}).catch((error) => {
|
|
160
|
+
expect(error).to.exist;
|
|
161
|
+
expect(error?.code).to.be.equal(oErrorCodes.INVALID_ACTION);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
describe('Concurrent Requests', () => {
|
|
166
|
+
it('should handle concurrent requests to same node', async () => {
|
|
167
|
+
builder = await NetworkTopologies.twoNode();
|
|
168
|
+
const leader = builder.getNode('o://leader');
|
|
169
|
+
const child = builder.getNode('o://child');
|
|
170
|
+
const promises = [];
|
|
171
|
+
for (let i = 0; i < 10; i++) {
|
|
172
|
+
promises.push(leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
173
|
+
method: 'echo',
|
|
174
|
+
params: { message: `concurrent ${i}` },
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
const responses = await Promise.all(promises);
|
|
178
|
+
// All should succeed
|
|
179
|
+
expect(responses).to.have.lengthOf(10);
|
|
180
|
+
responses.forEach((response, i) => {
|
|
181
|
+
expect(response.result.success).to.be.true;
|
|
182
|
+
expect(response.result.data.message).to.equal(`concurrent ${i}`);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
it('should handle concurrent requests to different nodes', async () => {
|
|
186
|
+
builder = await NetworkTopologies.fiveNode();
|
|
187
|
+
const leader = builder.getNode('o://leader');
|
|
188
|
+
const parent1 = builder.getNode('o://parent1');
|
|
189
|
+
const parent2 = builder.getNode('o://parent2');
|
|
190
|
+
const child1 = builder.getNode('o://child1');
|
|
191
|
+
const child2 = builder.getNode('o://child2');
|
|
192
|
+
const promises = [
|
|
193
|
+
leader.use(parent1.address, { method: 'get_info', params: {} }),
|
|
194
|
+
leader.use(parent2.address, { method: 'get_info', params: {} }),
|
|
195
|
+
leader.use(child1.address, { method: 'get_info', params: {} }),
|
|
196
|
+
leader.use(child2.address, { method: 'get_info', params: {} }),
|
|
197
|
+
];
|
|
198
|
+
const responses = await Promise.all(promises);
|
|
199
|
+
// All should succeed
|
|
200
|
+
expect(responses).to.have.lengthOf(4);
|
|
201
|
+
responses.forEach((response) => {
|
|
202
|
+
expect(response.result.success).to.be.true;
|
|
203
|
+
});
|
|
204
|
+
// Verify correct nodes responded
|
|
205
|
+
expect(responses[0].result.data.address).to.include('parent1');
|
|
206
|
+
expect(responses[1].result.data.address).to.include('parent2');
|
|
207
|
+
expect(responses[2].result.data.address).to.include('child1');
|
|
208
|
+
expect(responses[3].result.data.address).to.include('child2');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
describe('Connection Pooling', () => {
|
|
212
|
+
it('should pool connections efficiently', async () => {
|
|
213
|
+
builder = await NetworkTopologies.fiveNode();
|
|
214
|
+
const leader = builder.getNode('o://leader');
|
|
215
|
+
const spy = createConnectionSpy(leader);
|
|
216
|
+
spy.start();
|
|
217
|
+
const child1 = builder.getNode('o://child1');
|
|
218
|
+
const child2 = builder.getNode('o://child2');
|
|
219
|
+
// Make multiple calls to same nodes
|
|
220
|
+
for (let i = 0; i < 5; i++) {
|
|
221
|
+
await leader.use(child1.address, {
|
|
222
|
+
method: 'echo',
|
|
223
|
+
params: { message: `child1-${i}` },
|
|
224
|
+
});
|
|
225
|
+
await leader.use(child2.address, {
|
|
226
|
+
method: 'echo',
|
|
227
|
+
params: { message: `child2-${i}` },
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
const summary = spy.getSummary();
|
|
231
|
+
// Should have connections to parents (which route to children)
|
|
232
|
+
expect(summary.currentConnections).to.be.greaterThan(0);
|
|
233
|
+
expect(summary.currentConnections).to.be.lessThan(10); // Not 10 (one per call)
|
|
234
|
+
spy.stop();
|
|
235
|
+
});
|
|
236
|
+
it('should maintain connection status correctly', async () => {
|
|
237
|
+
builder = await NetworkTopologies.twoNode();
|
|
238
|
+
const leader = builder.getNode('o://leader');
|
|
239
|
+
const child = builder.getNode('o://child');
|
|
240
|
+
const spy = createConnectionSpy(leader);
|
|
241
|
+
spy.start();
|
|
242
|
+
// Make initial request to establish connection
|
|
243
|
+
await leader.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
244
|
+
method: 'echo',
|
|
245
|
+
params: { message: 'test' },
|
|
246
|
+
});
|
|
247
|
+
// Get connection stats
|
|
248
|
+
const stats = spy.getConnectionStats();
|
|
249
|
+
expect(stats.length).to.be.greaterThan(0);
|
|
250
|
+
const connection = stats[0];
|
|
251
|
+
expect(connection.status).to.equal('open');
|
|
252
|
+
expect(connection.peerId).to.be.a('string');
|
|
253
|
+
spy.stop();
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"o-node.spec.d.ts","sourceRoot":"","sources":["../../test/o-node.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { NodeState } from '@olane/o-core';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { assertRunning, assertStopped } from '@olane/o-test';
|
|
4
|
+
import { TestEnvironment } from './helpers/index.js';
|
|
5
|
+
import { oNodeTool } from '../src/o-node.tool.js';
|
|
6
|
+
import { oNodeAddress } from '../src/index.js';
|
|
7
|
+
describe('oNode', () => {
|
|
8
|
+
const env = new TestEnvironment();
|
|
9
|
+
afterEach(async () => {
|
|
10
|
+
await env.cleanup();
|
|
11
|
+
});
|
|
12
|
+
describe('Lifecycle', () => {
|
|
13
|
+
it('should be able to start a single node with no leader', async () => {
|
|
14
|
+
const node = new oNodeTool({
|
|
15
|
+
address: new oNodeAddress('o://test'),
|
|
16
|
+
leader: null,
|
|
17
|
+
parent: null,
|
|
18
|
+
});
|
|
19
|
+
await node.start();
|
|
20
|
+
// Use o-test assertion helpers
|
|
21
|
+
assertRunning(node);
|
|
22
|
+
const transports = node.transports;
|
|
23
|
+
// expect(transports.length).to.equal(1);
|
|
24
|
+
// expect(transports[0].toString()).to.contain('/memory');
|
|
25
|
+
await node.stop();
|
|
26
|
+
assertStopped(node);
|
|
27
|
+
// Also verify with traditional chai for backward compatibility
|
|
28
|
+
expect(node.state).to.equal(NodeState.STOPPED);
|
|
29
|
+
});
|
|
30
|
+
it('should initialize with correct address', async () => {
|
|
31
|
+
const testAddress = new oNodeAddress('o://test-node');
|
|
32
|
+
const node = new oNodeTool({
|
|
33
|
+
address: testAddress,
|
|
34
|
+
leader: null,
|
|
35
|
+
parent: null,
|
|
36
|
+
});
|
|
37
|
+
await node.start();
|
|
38
|
+
expect(node.address.value).to.equal('o://test-node');
|
|
39
|
+
assertRunning(node);
|
|
40
|
+
await node.stop();
|
|
41
|
+
});
|
|
42
|
+
it('should handle start and stop lifecycle correctly', async () => {
|
|
43
|
+
const node = new oNodeTool({
|
|
44
|
+
address: new oNodeAddress('o://lifecycle-test'),
|
|
45
|
+
leader: null,
|
|
46
|
+
parent: null,
|
|
47
|
+
});
|
|
48
|
+
// Initially not started
|
|
49
|
+
expect(node.state).to.equal(NodeState.STOPPED);
|
|
50
|
+
// Start node
|
|
51
|
+
await node.start();
|
|
52
|
+
assertRunning(node);
|
|
53
|
+
// Stop node
|
|
54
|
+
await node.stop();
|
|
55
|
+
assertStopped(node);
|
|
56
|
+
// Verify state is properly reset
|
|
57
|
+
expect(node.state).to.equal(NodeState.STOPPED);
|
|
58
|
+
});
|
|
59
|
+
it('should allow restart after stop with state reset', async () => {
|
|
60
|
+
const node = new oNodeTool({
|
|
61
|
+
address: new oNodeAddress('o://restart-test'),
|
|
62
|
+
leader: null,
|
|
63
|
+
parent: null,
|
|
64
|
+
seed: 'restart-test-seed',
|
|
65
|
+
});
|
|
66
|
+
// First start
|
|
67
|
+
await node.start();
|
|
68
|
+
assertRunning(node);
|
|
69
|
+
// Verify node has transports after start
|
|
70
|
+
expect(node.address.libp2pTransports.length).to.be.greaterThan(0);
|
|
71
|
+
const firstPeerId = node.peerId.toString();
|
|
72
|
+
// Stop the node
|
|
73
|
+
await node.stop();
|
|
74
|
+
assertStopped(node);
|
|
75
|
+
// After stop, state should be reset
|
|
76
|
+
expect(node.p2pNode).to.be.undefined;
|
|
77
|
+
expect(node.peerId).to.be.undefined;
|
|
78
|
+
expect(node.connectionManager).to.be.undefined;
|
|
79
|
+
// Restart should now work
|
|
80
|
+
await node.start();
|
|
81
|
+
assertRunning(node);
|
|
82
|
+
// Verify node is functional after restart
|
|
83
|
+
expect(node.peerId.toString()).to.equal(firstPeerId); // Same seed = same peerId
|
|
84
|
+
expect(node.address.libp2pTransports.length).to.be.greaterThan(0);
|
|
85
|
+
await node.stop();
|
|
86
|
+
});
|
|
87
|
+
it('should reset address to staticAddress with no transports', async () => {
|
|
88
|
+
const staticAddress = new oNodeAddress('o://address-reset-test');
|
|
89
|
+
const node = new oNodeTool({
|
|
90
|
+
address: staticAddress,
|
|
91
|
+
leader: null,
|
|
92
|
+
parent: null,
|
|
93
|
+
});
|
|
94
|
+
// Verify initial state
|
|
95
|
+
expect(node.address.value).to.equal('o://address-reset-test');
|
|
96
|
+
expect(node.address.transports).to.have.length(0);
|
|
97
|
+
// Start node
|
|
98
|
+
await node.start();
|
|
99
|
+
assertRunning(node);
|
|
100
|
+
// After start, address should have transports
|
|
101
|
+
expect(node.address.transports.length).to.be.greaterThan(0);
|
|
102
|
+
const transportsDuringRun = node.address.transports.length;
|
|
103
|
+
// Stop node
|
|
104
|
+
await node.stop();
|
|
105
|
+
assertStopped(node);
|
|
106
|
+
// After stop, address should be reset to staticAddress with no transports
|
|
107
|
+
expect(node.address.value).to.equal('o://address-reset-test');
|
|
108
|
+
expect(node.address.transports).to.have.length(0);
|
|
109
|
+
// Restart to verify it works
|
|
110
|
+
await node.start();
|
|
111
|
+
assertRunning(node);
|
|
112
|
+
expect(node.address.transports.length).to.be.greaterThan(0);
|
|
113
|
+
await node.stop();
|
|
114
|
+
});
|
|
115
|
+
it('should reset errors array on stop', async () => {
|
|
116
|
+
const node = new oNodeTool({
|
|
117
|
+
address: new oNodeAddress('o://errors-reset-test'),
|
|
118
|
+
leader: null,
|
|
119
|
+
parent: null,
|
|
120
|
+
});
|
|
121
|
+
await node.start();
|
|
122
|
+
assertRunning(node);
|
|
123
|
+
// Simulate adding errors
|
|
124
|
+
node.errors.push(new Error('Test error'));
|
|
125
|
+
expect(node.errors).to.have.length(1);
|
|
126
|
+
await node.stop();
|
|
127
|
+
assertStopped(node);
|
|
128
|
+
// Errors should be cleared
|
|
129
|
+
expect(node.errors).to.have.length(0);
|
|
130
|
+
});
|
|
131
|
+
it('should reset metrics on stop', async () => {
|
|
132
|
+
const node = new oNodeTool({
|
|
133
|
+
address: new oNodeAddress('o://metrics-reset-test'),
|
|
134
|
+
leader: null,
|
|
135
|
+
parent: null,
|
|
136
|
+
});
|
|
137
|
+
await node.start();
|
|
138
|
+
assertRunning(node);
|
|
139
|
+
// Make some calls to accumulate metrics
|
|
140
|
+
await node.use(node.address, {
|
|
141
|
+
method: 'get_libp2p_metrics',
|
|
142
|
+
params: {},
|
|
143
|
+
});
|
|
144
|
+
// Verify metrics were recorded
|
|
145
|
+
const metricsBeforeStop = node.metrics.successCount;
|
|
146
|
+
expect(metricsBeforeStop).to.be.greaterThan(0);
|
|
147
|
+
await node.stop();
|
|
148
|
+
assertStopped(node);
|
|
149
|
+
// Metrics should be reset
|
|
150
|
+
expect(node.metrics.successCount).to.equal(0);
|
|
151
|
+
expect(node.metrics.errorCount).to.equal(0);
|
|
152
|
+
});
|
|
153
|
+
it('should support multiple restart cycles', async () => {
|
|
154
|
+
const node = new oNodeTool({
|
|
155
|
+
address: new oNodeAddress('o://multi-restart-test'),
|
|
156
|
+
leader: null,
|
|
157
|
+
parent: null,
|
|
158
|
+
seed: 'multi-restart-seed',
|
|
159
|
+
});
|
|
160
|
+
const peerId = node.peerId?.toString();
|
|
161
|
+
// First cycle
|
|
162
|
+
await node.start();
|
|
163
|
+
assertRunning(node);
|
|
164
|
+
expect(node.p2pNode).to.exist;
|
|
165
|
+
await node.stop();
|
|
166
|
+
assertStopped(node);
|
|
167
|
+
expect(node.p2pNode).to.be.undefined;
|
|
168
|
+
// Second cycle
|
|
169
|
+
await node.start();
|
|
170
|
+
assertRunning(node);
|
|
171
|
+
expect(node.p2pNode).to.exist;
|
|
172
|
+
await node.stop();
|
|
173
|
+
assertStopped(node);
|
|
174
|
+
expect(node.p2pNode).to.be.undefined;
|
|
175
|
+
// Third cycle
|
|
176
|
+
await node.start();
|
|
177
|
+
assertRunning(node);
|
|
178
|
+
expect(node.p2pNode).to.exist;
|
|
179
|
+
// Verify node is still functional
|
|
180
|
+
const response = await node.use(node.address, {
|
|
181
|
+
method: 'get_libp2p_metrics',
|
|
182
|
+
params: {},
|
|
183
|
+
});
|
|
184
|
+
expect(response.result.success).to.be.true;
|
|
185
|
+
await node.stop();
|
|
186
|
+
assertStopped(node);
|
|
187
|
+
});
|
|
188
|
+
it('should reset didRegister flag on stop', async () => {
|
|
189
|
+
const node = new oNodeTool({
|
|
190
|
+
address: new oNodeAddress('o://didregister-test'),
|
|
191
|
+
leader: null,
|
|
192
|
+
parent: null,
|
|
193
|
+
});
|
|
194
|
+
await node.start();
|
|
195
|
+
assertRunning(node);
|
|
196
|
+
// After start, didRegister might be true (depending on if registration happened)
|
|
197
|
+
// For standalone nodes without leader, it stays false, but let's verify the reset works
|
|
198
|
+
await node.stop();
|
|
199
|
+
assertStopped(node);
|
|
200
|
+
// Should be able to restart
|
|
201
|
+
await node.start();
|
|
202
|
+
assertRunning(node);
|
|
203
|
+
await node.stop();
|
|
204
|
+
});
|
|
205
|
+
it('should clear p2p node after stop', async () => {
|
|
206
|
+
const node = new oNodeTool({
|
|
207
|
+
address: new oNodeAddress('o://clear-test'),
|
|
208
|
+
leader: null,
|
|
209
|
+
parent: null,
|
|
210
|
+
seed: 'clear-test-seed',
|
|
211
|
+
});
|
|
212
|
+
await node.start();
|
|
213
|
+
assertRunning(node);
|
|
214
|
+
// Test basic functionality before stop
|
|
215
|
+
const response1 = await node.use(node.address, {
|
|
216
|
+
method: 'get_libp2p_metrics',
|
|
217
|
+
params: {},
|
|
218
|
+
});
|
|
219
|
+
expect(response1.result.success).to.be.true;
|
|
220
|
+
expect(response1.result.data).to.exist;
|
|
221
|
+
// Verify p2pNode exists
|
|
222
|
+
expect(node.p2pNode).to.exist;
|
|
223
|
+
await node.stop();
|
|
224
|
+
assertStopped(node);
|
|
225
|
+
// p2pNode should be cleared (allowing restart)
|
|
226
|
+
expect(node.p2pNode).to.be.undefined;
|
|
227
|
+
});
|
|
228
|
+
it('should clean up resources properly on stop', async () => {
|
|
229
|
+
const node = new oNodeTool({
|
|
230
|
+
address: new oNodeAddress('o://cleanup-test'),
|
|
231
|
+
leader: null,
|
|
232
|
+
parent: null,
|
|
233
|
+
});
|
|
234
|
+
await node.start();
|
|
235
|
+
assertRunning(node);
|
|
236
|
+
// Verify p2p node exists and is started
|
|
237
|
+
expect(node.p2pNode).to.exist;
|
|
238
|
+
expect(node.p2pNode.status).to.equal('started');
|
|
239
|
+
await node.stop();
|
|
240
|
+
assertStopped(node);
|
|
241
|
+
// Verify resources are cleaned up
|
|
242
|
+
expect(node.p2pNode).to.be.undefined;
|
|
243
|
+
expect(node.connectionManager).to.be.undefined;
|
|
244
|
+
expect(node.connectionHeartbeatManager).to.be.undefined;
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parent-child-registration.spec.d.ts","sourceRoot":"","sources":["../../test/parent-child-registration.spec.ts"],"names":[],"mappings":""}
|