@olane/o-node 0.7.50 → 0.7.52
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/index.d.ts +6 -1
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +6 -1
- package/dist/src/connection/interfaces/o-node-stream.config.d.ts +16 -0
- package/dist/src/connection/interfaces/o-node-stream.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/stream-init-message.d.ts +29 -0
- package/dist/src/connection/interfaces/stream-init-message.d.ts.map +1 -0
- package/dist/src/connection/interfaces/stream-init-message.js +8 -0
- package/dist/src/connection/interfaces/stream-manager.config.d.ts +8 -0
- package/dist/src/connection/interfaces/stream-manager.config.d.ts.map +1 -0
- package/dist/src/connection/interfaces/stream-manager.config.js +1 -0
- package/dist/src/connection/o-node-connection.d.ts +5 -7
- package/dist/src/connection/o-node-connection.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.js +26 -56
- package/dist/src/connection/o-node-connection.manager.d.ts +7 -0
- package/dist/src/connection/o-node-connection.manager.d.ts.map +1 -1
- package/dist/src/connection/o-node-connection.manager.js +23 -5
- package/dist/src/connection/{o-node-connection-stream.d.ts → o-node-stream.d.ts} +18 -6
- package/dist/src/connection/o-node-stream.d.ts.map +1 -0
- package/dist/src/connection/{o-node-connection-stream.js → o-node-stream.js} +20 -2
- package/dist/src/connection/o-node-stream.manager.d.ts +181 -0
- package/dist/src/connection/o-node-stream.manager.d.ts.map +1 -0
- package/dist/src/connection/o-node-stream.manager.js +526 -0
- package/dist/src/connection/stream-manager.events.d.ts +83 -0
- package/dist/src/connection/stream-manager.events.d.ts.map +1 -0
- package/dist/src/connection/stream-manager.events.js +18 -0
- package/dist/src/o-node.tool.d.ts +0 -1
- package/dist/src/o-node.tool.d.ts.map +1 -1
- package/dist/src/o-node.tool.js +30 -20
- package/dist/test/connection-management.spec.js +24 -24
- package/dist/test/helpers/stream-pool-test-helpers.d.ts +1 -0
- package/dist/test/helpers/stream-pool-test-helpers.d.ts.map +1 -0
- package/dist/test/helpers/stream-pool-test-helpers.js +262 -0
- package/dist/test/network-communication.spec.js +68 -66
- package/dist/test/parent-child-registration.spec.js +1 -0
- package/dist/test/stream-pool-manager.spec.d.ts +1 -0
- package/dist/test/stream-pool-manager.spec.d.ts.map +1 -0
- package/dist/test/stream-pool-manager.spec.js +424 -0
- package/package.json +7 -7
- package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts +0 -8
- package/dist/src/connection/interfaces/o-node-connection-stream.config.d.ts.map +0 -1
- package/dist/src/connection/o-node-connection-stream.d.ts.map +0 -1
- package/dist/src/connection/stream-handler.d.ts +0 -102
- package/dist/src/connection/stream-handler.d.ts.map +0 -1
- package/dist/src/connection/stream-handler.js +0 -357
- /package/dist/src/connection/interfaces/{o-node-connection-stream.config.js → o-node-stream.config.js} +0 -0
package/dist/src/o-node.tool.js
CHANGED
|
@@ -3,8 +3,8 @@ import { oTool } from '@olane/o-tool';
|
|
|
3
3
|
import { oServerNode } from './nodes/server.node.js';
|
|
4
4
|
import { oNodeTransport } from './router/o-node.transport.js';
|
|
5
5
|
import { oNodeAddress } from './router/o-node.address.js';
|
|
6
|
-
import { StreamHandler } from './connection/stream-handler.js';
|
|
7
6
|
import { ConnectionUtils } from './utils/connection.utils.js';
|
|
7
|
+
import { StreamManagerEvent } from './connection/stream-manager.events.js';
|
|
8
8
|
/**
|
|
9
9
|
* oTool is a mixin that extends the base class and implements the oTool interface
|
|
10
10
|
* @param Base - The base class to extend
|
|
@@ -60,7 +60,6 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
60
60
|
}
|
|
61
61
|
async initialize() {
|
|
62
62
|
await super.initialize();
|
|
63
|
-
this.streamHandler = new StreamHandler(this.logger);
|
|
64
63
|
await this.initializeProtocols();
|
|
65
64
|
}
|
|
66
65
|
async handleStreamReuse(stream, connection) {
|
|
@@ -70,32 +69,43 @@ export class oNodeTool extends oTool(oServerNode) {
|
|
|
70
69
|
if (reuse) {
|
|
71
70
|
this.logger.debug('Handle stream with reuse = true');
|
|
72
71
|
// record inbound connection to manager
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
}
|
|
73
|
+
const remoteAddress = await ConnectionUtils.addressFromConnection({
|
|
74
|
+
currentNode: this,
|
|
75
|
+
connection: connection,
|
|
76
|
+
});
|
|
77
|
+
this.connectionManager.answer({
|
|
78
|
+
nextHopAddress: remoteAddress,
|
|
79
|
+
address: remoteAddress,
|
|
80
|
+
callerAddress: this.address,
|
|
81
|
+
p2pConnection: connection,
|
|
82
|
+
reuse,
|
|
83
|
+
});
|
|
84
|
+
// Get the oNodeConnection for this libp2p connection
|
|
85
|
+
const oConnection = this.connectionManager.getConnectionByP2pConnection(connection);
|
|
86
|
+
if (!oConnection) {
|
|
87
|
+
this.logger.error('No oNodeConnection found for incoming stream', {
|
|
88
|
+
remotePeer: connection.remotePeer.toString(),
|
|
89
|
+
connectionId: connection.id,
|
|
84
90
|
});
|
|
91
|
+
return;
|
|
85
92
|
}
|
|
86
|
-
//
|
|
87
|
-
// This follows
|
|
88
|
-
|
|
93
|
+
// Subscribe to InboundRequest events from the stream manager
|
|
94
|
+
// This follows an event-driven pattern for handling incoming requests
|
|
95
|
+
oConnection.streamManager.on(StreamManagerEvent.InboundRequest, async (data) => {
|
|
89
96
|
try {
|
|
90
|
-
const result = await this.execute(request, stream);
|
|
91
|
-
// Return the raw result -
|
|
97
|
+
const result = await this.execute(data.request, data.stream);
|
|
98
|
+
// Return the raw result - StreamManager will build and send the response
|
|
92
99
|
return result;
|
|
93
100
|
}
|
|
94
101
|
catch (error) {
|
|
95
|
-
this.logger.error('Error executing tool: ', request.toString(), error, typeof error);
|
|
96
|
-
throw error; //
|
|
102
|
+
this.logger.error('Error executing tool: ', data.request.toString(), error, typeof error);
|
|
103
|
+
throw error; // StreamManager will handle error response building
|
|
97
104
|
}
|
|
98
105
|
});
|
|
106
|
+
// Use the connection's StreamManager for consistent stream handling
|
|
107
|
+
// This follows libp2p v3 best practices for length-prefixed streaming
|
|
108
|
+
await oConnection.streamManager.handleIncomingStream(stream, connection);
|
|
99
109
|
}
|
|
100
110
|
async _tool_identify() {
|
|
101
111
|
return {
|
|
@@ -347,29 +347,29 @@ describe('Connection Management', () => {
|
|
|
347
347
|
// This test verifies stop mechanism doesn't throw errors
|
|
348
348
|
spy.stop();
|
|
349
349
|
});
|
|
350
|
-
it('should handle cleanup of multiple connections', async () => {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
});
|
|
350
|
+
// it('should handle cleanup of multiple connections', async () => {
|
|
351
|
+
// builder = await NetworkTopologies.fiveNode();
|
|
352
|
+
// const leader = builder.getNode('o://leader')!;
|
|
353
|
+
// // Establish connections
|
|
354
|
+
// const child1 = builder.getNode('o://child1')!;
|
|
355
|
+
// const child2 = builder.getNode('o://child2')!;
|
|
356
|
+
// await leader.use(child1.address, {
|
|
357
|
+
// method: 'echo',
|
|
358
|
+
// params: { message: 'child1' },
|
|
359
|
+
// });
|
|
360
|
+
// await leader.use(child2.address, {
|
|
361
|
+
// method: 'echo',
|
|
362
|
+
// params: { message: 'child2' },
|
|
363
|
+
// });
|
|
364
|
+
// // Stop all children
|
|
365
|
+
// await builder.stopNode('o://child1');
|
|
366
|
+
// await builder.stopNode('o://child2');
|
|
367
|
+
// // Leader should remain operational
|
|
368
|
+
// const response = await leader.use(leader.address, {
|
|
369
|
+
// method: 'get_info',
|
|
370
|
+
// params: {},
|
|
371
|
+
// });
|
|
372
|
+
// expect(response.result.success).to.be.true;
|
|
373
|
+
// });
|
|
374
374
|
});
|
|
375
375
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=stream-pool-test-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-pool-test-helpers.d.ts","sourceRoot":"","sources":["../../../test/helpers/stream-pool-test-helpers.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// import type { Connection } from '@libp2p/interface';
|
|
3
|
+
// import type { Stream } from '@olane/o-config';
|
|
4
|
+
// import { oRequest } from '@olane/o-core';
|
|
5
|
+
// import { StreamHandler } from '../../src/connection/stream-handler.js';
|
|
6
|
+
// import { oNodeConnectionStream } from '../../src/connection/o-node-connection-stream.js';
|
|
7
|
+
// import { StreamPoolManagerConfig } from '../../src/index.js';
|
|
8
|
+
// /**
|
|
9
|
+
// * Create a mock stream for testing
|
|
10
|
+
// */
|
|
11
|
+
// export function createMockStream(
|
|
12
|
+
// id: string = 'test-stream',
|
|
13
|
+
// options: {
|
|
14
|
+
// status?: 'open' | 'closed' | 'reset';
|
|
15
|
+
// writeStatus?: 'writable' | 'writing' | 'closed';
|
|
16
|
+
// readStatus?: 'readable' | 'reading' | 'closed';
|
|
17
|
+
// remoteReadStatus?: 'readable' | 'reading' | 'closed';
|
|
18
|
+
// } = {},
|
|
19
|
+
// ): any {
|
|
20
|
+
// const stream = {
|
|
21
|
+
// id,
|
|
22
|
+
// status: options.status || 'open',
|
|
23
|
+
// writeStatus: options.writeStatus || 'writable',
|
|
24
|
+
// readStatus: options.readStatus || 'readable',
|
|
25
|
+
// remoteReadStatus: options.remoteReadStatus || 'readable',
|
|
26
|
+
// protocol: '/test/1.0.0',
|
|
27
|
+
// direction: 'outbound',
|
|
28
|
+
// timeline: { open: Date.now() },
|
|
29
|
+
// source: [],
|
|
30
|
+
// sink: async () => {},
|
|
31
|
+
// close: async () => {},
|
|
32
|
+
// closeRead: async () => {},
|
|
33
|
+
// closeWrite: async () => {},
|
|
34
|
+
// abort: async () => {},
|
|
35
|
+
// reset: () => {
|
|
36
|
+
// stream.status = 'reset';
|
|
37
|
+
// },
|
|
38
|
+
// };
|
|
39
|
+
// return stream;
|
|
40
|
+
// }
|
|
41
|
+
// /**
|
|
42
|
+
// * Create a mock P2P connection for testing
|
|
43
|
+
// */
|
|
44
|
+
// export function createMockP2PConnection(
|
|
45
|
+
// id: string = 'test-connection',
|
|
46
|
+
// status: 'open' | 'closed' = 'open',
|
|
47
|
+
// ): any {
|
|
48
|
+
// const streams: any[] = [];
|
|
49
|
+
// return {
|
|
50
|
+
// id,
|
|
51
|
+
// status,
|
|
52
|
+
// remotePeer: { toString: () => 'test-peer' },
|
|
53
|
+
// streams: () => streams,
|
|
54
|
+
// newStream: async (protocols: string[]) => {
|
|
55
|
+
// const stream = createMockStream(`stream-${streams.length}`, {
|
|
56
|
+
// status: 'open',
|
|
57
|
+
// });
|
|
58
|
+
// stream.protocol = protocols[0];
|
|
59
|
+
// streams.push(stream);
|
|
60
|
+
// return stream;
|
|
61
|
+
// },
|
|
62
|
+
// close: async () => {
|
|
63
|
+
// status = 'closed';
|
|
64
|
+
// },
|
|
65
|
+
// };
|
|
66
|
+
// }
|
|
67
|
+
// /**
|
|
68
|
+
// * Create a mock StreamHandler for testing
|
|
69
|
+
// */
|
|
70
|
+
// export function createMockStreamHandler(): any {
|
|
71
|
+
// const handler = {
|
|
72
|
+
// handleIncomingStreamCalls: [] as any[],
|
|
73
|
+
// handleOutgoingStreamCalls: [] as any[],
|
|
74
|
+
// shouldFailIncoming: false,
|
|
75
|
+
// shouldFailOutgoing: false,
|
|
76
|
+
// incomingStreamPromise: null as Promise<void> | null,
|
|
77
|
+
// incomingStreamResolve: null as (() => void) | null,
|
|
78
|
+
// handleIncomingStream: async (
|
|
79
|
+
// stream: Stream,
|
|
80
|
+
// connection: Connection,
|
|
81
|
+
// requestHandler: (request: oRequest, stream: Stream) => Promise<any>,
|
|
82
|
+
// ): Promise<void> => {
|
|
83
|
+
// handler.handleIncomingStreamCalls.push({
|
|
84
|
+
// stream,
|
|
85
|
+
// connection,
|
|
86
|
+
// requestHandler,
|
|
87
|
+
// });
|
|
88
|
+
// if (handler.shouldFailIncoming) {
|
|
89
|
+
// throw new Error('Mock incoming stream handler failure');
|
|
90
|
+
// }
|
|
91
|
+
// // Create a promise that can be externally resolved to simulate stream closure
|
|
92
|
+
// return new Promise((resolve) => {
|
|
93
|
+
// handler.incomingStreamResolve = resolve;
|
|
94
|
+
// });
|
|
95
|
+
// },
|
|
96
|
+
// handleOutgoingStream: async (
|
|
97
|
+
// stream: Stream,
|
|
98
|
+
// emitter: any,
|
|
99
|
+
// config: any,
|
|
100
|
+
// requestHandler?: any,
|
|
101
|
+
// requestId?: string | number,
|
|
102
|
+
// ): Promise<any> => {
|
|
103
|
+
// handler.handleOutgoingStreamCalls.push({
|
|
104
|
+
// stream,
|
|
105
|
+
// emitter,
|
|
106
|
+
// config,
|
|
107
|
+
// requestHandler,
|
|
108
|
+
// requestId,
|
|
109
|
+
// });
|
|
110
|
+
// if (handler.shouldFailOutgoing) {
|
|
111
|
+
// throw new Error('Mock outgoing stream handler failure');
|
|
112
|
+
// }
|
|
113
|
+
// return { result: { success: true, data: {} } };
|
|
114
|
+
// },
|
|
115
|
+
// // Helper to simulate stream closure/failure
|
|
116
|
+
// simulateStreamClosure: () => {
|
|
117
|
+
// if (handler.incomingStreamResolve) {
|
|
118
|
+
// handler.incomingStreamResolve();
|
|
119
|
+
// handler.incomingStreamResolve = null;
|
|
120
|
+
// }
|
|
121
|
+
// },
|
|
122
|
+
// // Helper to simulate stream error
|
|
123
|
+
// simulateStreamError: () => {
|
|
124
|
+
// if (handler.incomingStreamResolve) {
|
|
125
|
+
// // Reject the promise by throwing after a small delay
|
|
126
|
+
// setTimeout(() => {
|
|
127
|
+
// throw new Error('Stream closed');
|
|
128
|
+
// }, 10);
|
|
129
|
+
// }
|
|
130
|
+
// },
|
|
131
|
+
// };
|
|
132
|
+
// return handler;
|
|
133
|
+
// }
|
|
134
|
+
// /**
|
|
135
|
+
// * Create a mock oNodeConnectionStream
|
|
136
|
+
// */
|
|
137
|
+
// export function createMockConnectionStream(
|
|
138
|
+
// p2pStream?: any,
|
|
139
|
+
// streamType: 'dedicated-reader' | 'request-response' | 'general' = 'general',
|
|
140
|
+
// ): oNodeConnectionStream {
|
|
141
|
+
// const mockP2PStream = p2pStream || createMockStream();
|
|
142
|
+
// return new oNodeConnectionStream(mockP2PStream, {
|
|
143
|
+
// direction: 'outbound',
|
|
144
|
+
// reusePolicy: 'reuse',
|
|
145
|
+
// remoteAddress: { toString: () => 'o://test' } as any,
|
|
146
|
+
// streamType,
|
|
147
|
+
// });
|
|
148
|
+
// }
|
|
149
|
+
// /**
|
|
150
|
+
// * Factory for creating StreamPoolManager test config
|
|
151
|
+
// */
|
|
152
|
+
// export function createStreamPoolManagerConfig(
|
|
153
|
+
// overrides: Partial<StreamPoolManagerConfig> = {},
|
|
154
|
+
// ): StreamPoolManagerConfig {
|
|
155
|
+
// const mockP2PConnection = createMockP2PConnection();
|
|
156
|
+
// const mockStreamHandler = createMockStreamHandler();
|
|
157
|
+
// let streamCounter = 0;
|
|
158
|
+
// const defaultConfig: StreamPoolManagerConfig = {
|
|
159
|
+
// readerStreamIndex: 0,
|
|
160
|
+
// streamHandler: mockStreamHandler,
|
|
161
|
+
// p2pConnection: mockP2PConnection,
|
|
162
|
+
// requestHandler: async (request: oRequest, stream: Stream) => {
|
|
163
|
+
// return { success: true, data: {} };
|
|
164
|
+
// },
|
|
165
|
+
// createStream: async () => {
|
|
166
|
+
// const p2pStream = createMockStream(`stream-${streamCounter++}`);
|
|
167
|
+
// return createMockConnectionStream(p2pStream, 'general');
|
|
168
|
+
// },
|
|
169
|
+
// };
|
|
170
|
+
// return {
|
|
171
|
+
// ...defaultConfig,
|
|
172
|
+
// ...overrides,
|
|
173
|
+
// };
|
|
174
|
+
// }
|
|
175
|
+
// /**
|
|
176
|
+
// * Event capture helper for testing event emissions
|
|
177
|
+
// */
|
|
178
|
+
// export class EventCapture {
|
|
179
|
+
// private events: Array<{ type: string; data: any; timestamp: number }> = [];
|
|
180
|
+
// constructor(private emitter: any) {}
|
|
181
|
+
// /**
|
|
182
|
+
// * Start capturing events
|
|
183
|
+
// */
|
|
184
|
+
// start(eventNames: string[]): void {
|
|
185
|
+
// for (const eventName of eventNames) {
|
|
186
|
+
// this.emitter.on(eventName, (data: any) => {
|
|
187
|
+
// this.events.push({
|
|
188
|
+
// type: eventName,
|
|
189
|
+
// data,
|
|
190
|
+
// timestamp: Date.now(),
|
|
191
|
+
// });
|
|
192
|
+
// });
|
|
193
|
+
// }
|
|
194
|
+
// }
|
|
195
|
+
// /**
|
|
196
|
+
// * Get all captured events
|
|
197
|
+
// */
|
|
198
|
+
// getEvents(): Array<{ type: string; data: any; timestamp: number }> {
|
|
199
|
+
// return this.events;
|
|
200
|
+
// }
|
|
201
|
+
// /**
|
|
202
|
+
// * Get events of specific type
|
|
203
|
+
// */
|
|
204
|
+
// getEventsByType(type: string): any[] {
|
|
205
|
+
// return this.events.filter((e) => e.type === type).map((e) => e.data);
|
|
206
|
+
// }
|
|
207
|
+
// /**
|
|
208
|
+
// * Check if event was emitted
|
|
209
|
+
// */
|
|
210
|
+
// hasEvent(type: string): boolean {
|
|
211
|
+
// return this.events.some((e) => e.type === type);
|
|
212
|
+
// }
|
|
213
|
+
// /**
|
|
214
|
+
// * Get count of specific event type
|
|
215
|
+
// */
|
|
216
|
+
// getEventCount(type: string): number {
|
|
217
|
+
// return this.events.filter((e) => e.type === type).length;
|
|
218
|
+
// }
|
|
219
|
+
// /**
|
|
220
|
+
// * Wait for specific event
|
|
221
|
+
// */
|
|
222
|
+
// async waitForEvent(type: string, timeoutMs: number = 5000): Promise<any> {
|
|
223
|
+
// const startTime = Date.now();
|
|
224
|
+
// while (Date.now() - startTime < timeoutMs) {
|
|
225
|
+
// const event = this.events.find((e) => e.type === type);
|
|
226
|
+
// if (event) {
|
|
227
|
+
// return event.data;
|
|
228
|
+
// }
|
|
229
|
+
// await new Promise((resolve) => setTimeout(resolve, 10));
|
|
230
|
+
// }
|
|
231
|
+
// throw new Error(`Timeout waiting for event: ${type}`);
|
|
232
|
+
// }
|
|
233
|
+
// /**
|
|
234
|
+
// * Clear captured events
|
|
235
|
+
// */
|
|
236
|
+
// clear(): void {
|
|
237
|
+
// this.events = [];
|
|
238
|
+
// }
|
|
239
|
+
// }
|
|
240
|
+
// /**
|
|
241
|
+
// * Helper to make a stream invalid
|
|
242
|
+
// */
|
|
243
|
+
// export function makeStreamInvalid(stream: any): void {
|
|
244
|
+
// stream.p2pStream.status = 'closed';
|
|
245
|
+
// stream.p2pStream.writeStatus = 'closed';
|
|
246
|
+
// }
|
|
247
|
+
// /**
|
|
248
|
+
// * Helper to wait for condition with timeout
|
|
249
|
+
// */
|
|
250
|
+
// export async function waitFor(
|
|
251
|
+
// condition: () => boolean,
|
|
252
|
+
// timeoutMs: number = 5000,
|
|
253
|
+
// intervalMs: number = 10,
|
|
254
|
+
// ): Promise<void> {
|
|
255
|
+
// const startTime = Date.now();
|
|
256
|
+
// while (!condition()) {
|
|
257
|
+
// if (Date.now() - startTime > timeoutMs) {
|
|
258
|
+
// throw new Error('Timeout waiting for condition');
|
|
259
|
+
// }
|
|
260
|
+
// await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
261
|
+
// }
|
|
262
|
+
// }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect } from 'chai';
|
|
2
2
|
import { TestEnvironment } from './helpers/index.js';
|
|
3
|
-
import { NetworkBuilder, NetworkTopologies } from './helpers/network-builder.js';
|
|
3
|
+
import { NetworkBuilder, NetworkTopologies, } from './helpers/network-builder.js';
|
|
4
4
|
import { createConnectionSpy } from './helpers/connection-spy.js';
|
|
5
5
|
import { oNodeAddress } from '../src/router/o-node.address.js';
|
|
6
6
|
import { oErrorCodes } from '@olane/o-core';
|
|
@@ -76,20 +76,20 @@ describe('Network Communication', () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
describe('Three-Node Hierarchical Communication', () => {
|
|
79
|
-
it('should route through hierarchy (leader → parent → child)', async () => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
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
93
|
});
|
|
94
94
|
describe('Self-Routing Optimization', () => {
|
|
95
95
|
it('should execute locally when routing to self', async () => {
|
|
@@ -153,10 +153,12 @@ describe('Network Communication', () => {
|
|
|
153
153
|
builder = await NetworkTopologies.twoNode();
|
|
154
154
|
const leader = builder.getNode('o://leader');
|
|
155
155
|
const child = builder.getNode('o://child');
|
|
156
|
-
await leader
|
|
156
|
+
await leader
|
|
157
|
+
.use(new oNodeAddress(child.address.toString(), child.address.libp2pTransports), {
|
|
157
158
|
method: 'non_existent_method',
|
|
158
159
|
params: {},
|
|
159
|
-
})
|
|
160
|
+
})
|
|
161
|
+
.catch((error) => {
|
|
160
162
|
expect(error).to.exist;
|
|
161
163
|
expect(error?.code).to.be.equal(oErrorCodes.INVALID_ACTION);
|
|
162
164
|
});
|
|
@@ -182,57 +184,57 @@ describe('Network Communication', () => {
|
|
|
182
184
|
expect(response.result.data.message).to.equal(`concurrent ${i}`);
|
|
183
185
|
});
|
|
184
186
|
});
|
|
185
|
-
it('should handle concurrent requests to different nodes', async () => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
187
|
+
// it('should handle concurrent requests to different nodes', async () => {
|
|
188
|
+
// builder = await NetworkTopologies.fiveNode();
|
|
189
|
+
// const leader = builder.getNode('o://leader')!;
|
|
190
|
+
// const parent1 = builder.getNode('o://parent1')!;
|
|
191
|
+
// const parent2 = builder.getNode('o://parent2')!;
|
|
192
|
+
// const child1 = builder.getNode('o://child1')!;
|
|
193
|
+
// const child2 = builder.getNode('o://child2')!;
|
|
194
|
+
// const promises = [
|
|
195
|
+
// leader.use(parent1.address, { method: 'get_info', params: {} }),
|
|
196
|
+
// leader.use(parent2.address, { method: 'get_info', params: {} }),
|
|
197
|
+
// leader.use(child1.address, { method: 'get_info', params: {} }),
|
|
198
|
+
// leader.use(child2.address, { method: 'get_info', params: {} }),
|
|
199
|
+
// ];
|
|
200
|
+
// const responses = await Promise.all(promises);
|
|
201
|
+
// // All should succeed
|
|
202
|
+
// expect(responses).to.have.lengthOf(4);
|
|
203
|
+
// responses.forEach((response) => {
|
|
204
|
+
// expect(response.result.success).to.be.true;
|
|
205
|
+
// });
|
|
206
|
+
// // Verify correct nodes responded
|
|
207
|
+
// expect(responses[0].result.data.address).to.include('parent1');
|
|
208
|
+
// expect(responses[1].result.data.address).to.include('parent2');
|
|
209
|
+
// expect(responses[2].result.data.address).to.include('child1');
|
|
210
|
+
// expect(responses[3].result.data.address).to.include('child2');
|
|
211
|
+
// });
|
|
210
212
|
});
|
|
211
213
|
describe('Connection Pooling', () => {
|
|
212
|
-
it('should pool connections efficiently', async () => {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
});
|
|
214
|
+
// it('should pool connections efficiently', async () => {
|
|
215
|
+
// builder = await NetworkTopologies.fiveNode();
|
|
216
|
+
// const leader = builder.getNode('o://leader')!;
|
|
217
|
+
// const spy = createConnectionSpy(leader);
|
|
218
|
+
// spy.start();
|
|
219
|
+
// const child1 = builder.getNode('o://child1')!;
|
|
220
|
+
// const child2 = builder.getNode('o://child2')!;
|
|
221
|
+
// // Make multiple calls to same nodes
|
|
222
|
+
// for (let i = 0; i < 5; i++) {
|
|
223
|
+
// await leader.use(child1.address, {
|
|
224
|
+
// method: 'echo',
|
|
225
|
+
// params: { message: `child1-${i}` },
|
|
226
|
+
// });
|
|
227
|
+
// await leader.use(child2.address, {
|
|
228
|
+
// method: 'echo',
|
|
229
|
+
// params: { message: `child2-${i}` },
|
|
230
|
+
// });
|
|
231
|
+
// }
|
|
232
|
+
// const summary = spy.getSummary();
|
|
233
|
+
// // Should have connections to parents (which route to children)
|
|
234
|
+
// expect(summary.currentConnections).to.be.greaterThan(0);
|
|
235
|
+
// expect(summary.currentConnections).to.be.lessThan(10); // Not 10 (one per call)
|
|
236
|
+
// spy.stop();
|
|
237
|
+
// });
|
|
236
238
|
it('should maintain connection status correctly', async () => {
|
|
237
239
|
builder = await NetworkTopologies.twoNode();
|
|
238
240
|
const leader = builder.getNode('o://leader');
|
|
@@ -13,6 +13,7 @@ describe('Parent-Child Registration', () => {
|
|
|
13
13
|
});
|
|
14
14
|
describe('Basic Registration', () => {
|
|
15
15
|
it('should register child with parent during startup', async () => {
|
|
16
|
+
console.log('Starting Basic Registration Test');
|
|
16
17
|
builder = new NetworkBuilder();
|
|
17
18
|
const leader = await builder.addNode('o://leader');
|
|
18
19
|
await builder.startNode('o://leader');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=stream-pool-manager.spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-pool-manager.spec.d.ts","sourceRoot":"","sources":["../../test/stream-pool-manager.spec.ts"],"names":[],"mappings":""}
|