@olane/o-leader 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/leader.mixin.d.ts.map +1 -1
- package/dist/src/leader.mixin.js +3 -1
- package/dist/test/leader-reconnection.spec.d.ts +2 -0
- package/dist/test/leader-reconnection.spec.d.ts.map +1 -0
- package/dist/test/leader-reconnection.spec.js +791 -0
- package/package.json +10 -10
- package/dist/test/address-resolution-integration.spec.d.ts +0 -1
- package/dist/test/address-resolution-integration.spec.d.ts.map +0 -1
- package/dist/test/address-resolution-integration.spec.js +0 -821
- package/dist/test/basic.spec.d.ts +0 -1
- package/dist/test/basic.spec.d.ts.map +0 -1
- package/dist/test/basic.spec.js +0 -1
- package/dist/test/hierarchical-streaming.spec.d.ts +0 -2
- package/dist/test/hierarchical-streaming.spec.d.ts.map +0 -1
- package/dist/test/hierarchical-streaming.spec.js +0 -364
- package/dist/test/registry-memory.spec.d.ts +0 -1
- package/dist/test/registry-memory.spec.d.ts.map +0 -1
- package/dist/test/registry-memory.spec.js +0 -533
- package/dist/test/stream.spec.d.ts +0 -1
- package/dist/test/stream.spec.d.ts.map +0 -1
- package/dist/test/stream.spec.js +0 -1
|
@@ -1,821 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// import { expect } from 'chai';
|
|
3
|
-
// import { oLeaderNode } from '../src/leader.node.js';
|
|
4
|
-
// import { oNode } from '@olane/o-node';
|
|
5
|
-
// import { oNodeAddress } from '@olane/o-node';
|
|
6
|
-
// import { oAddress, RestrictedAddresses, NodeState } from '@olane/o-core';
|
|
7
|
-
// import { oRegistrationParams } from '@olane/o-protocol';
|
|
8
|
-
// describe('Address Resolution Integration Tests', () => {
|
|
9
|
-
// describe('Leader + Registry + Resolver Integration', () => {
|
|
10
|
-
// let leader: oLeaderNode;
|
|
11
|
-
// beforeEach(async () => {
|
|
12
|
-
// leader = new oLeaderNode({
|
|
13
|
-
// name: 'test-leader',
|
|
14
|
-
// parent: null,
|
|
15
|
-
// leader: null,
|
|
16
|
-
// network: {
|
|
17
|
-
// listeners: [],
|
|
18
|
-
// },
|
|
19
|
-
// });
|
|
20
|
-
// await leader.start();
|
|
21
|
-
// });
|
|
22
|
-
// afterEach(async () => {
|
|
23
|
-
// if (leader && leader.state === NodeState.RUNNING) {
|
|
24
|
-
// await leader.stop();
|
|
25
|
-
// }
|
|
26
|
-
// });
|
|
27
|
-
// it('should start leader with registry as child', async () => {
|
|
28
|
-
// expect(leader.state).to.equal(NodeState.RUNNING);
|
|
29
|
-
// expect(leader.address.value).to.equal(RestrictedAddresses.LEADER);
|
|
30
|
-
// // Verify registry is a child
|
|
31
|
-
// const registryChild = leader.hierarchyManager.getChild(
|
|
32
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
33
|
-
// );
|
|
34
|
-
// expect(registryChild).to.not.be.null;
|
|
35
|
-
// expect(registryChild?.value).to.equal(RestrictedAddresses.REGISTRY);
|
|
36
|
-
// });
|
|
37
|
-
// it('should be able to register a node in the registry', async () => {
|
|
38
|
-
// const registrationParams: oRegistrationParams = {
|
|
39
|
-
// _connectionId: 'test-connection',
|
|
40
|
-
// _requestMethod: 'test-method',
|
|
41
|
-
// peerId: 'peer-embeddings',
|
|
42
|
-
// address: 'o://leader/services/embeddings',
|
|
43
|
-
// staticAddress: 'o://embeddings-text',
|
|
44
|
-
// protocols: ['/embeddings/1.0.0'],
|
|
45
|
-
// transports: ['/ip4/127.0.0.1/tcp/6001'],
|
|
46
|
-
// };
|
|
47
|
-
// const result = await leader.use(
|
|
48
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
49
|
-
// {
|
|
50
|
-
// method: 'commit',
|
|
51
|
-
// params: registrationParams,
|
|
52
|
-
// },
|
|
53
|
-
// );
|
|
54
|
-
// expect(result.result.success).to.be.true;
|
|
55
|
-
// });
|
|
56
|
-
// it('should be able to search for registered nodes', async () => {
|
|
57
|
-
// // Register a node
|
|
58
|
-
// const registrationParams: oRegistrationParams = {
|
|
59
|
-
// _connectionId: 'test-connection',
|
|
60
|
-
// _requestMethod: 'test-method',
|
|
61
|
-
// peerId: 'peer-search-test',
|
|
62
|
-
// address: 'o://leader/services/search-test',
|
|
63
|
-
// staticAddress: 'o://search-test',
|
|
64
|
-
// protocols: ['/test/1.0.0'],
|
|
65
|
-
// transports: ['/ip4/127.0.0.1/tcp/7001'],
|
|
66
|
-
// };
|
|
67
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
68
|
-
// method: 'commit',
|
|
69
|
-
// params: registrationParams,
|
|
70
|
-
// });
|
|
71
|
-
// // Search for the node
|
|
72
|
-
// const searchResult = await leader.use(
|
|
73
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
74
|
-
// {
|
|
75
|
-
// method: 'search',
|
|
76
|
-
// params: { staticAddress: 'o://search-test' },
|
|
77
|
-
// },
|
|
78
|
-
// );
|
|
79
|
-
// expect(searchResult.result.data).to.be.an('array');
|
|
80
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
81
|
-
// expect((searchResult.result.data as any[])[0].peerId).to.equal(
|
|
82
|
-
// 'peer-search-test',
|
|
83
|
-
// );
|
|
84
|
-
// });
|
|
85
|
-
// it('should resolve address using search resolver', async () => {
|
|
86
|
-
// // Register a service
|
|
87
|
-
// const registrationParams: oRegistrationParams = {
|
|
88
|
-
// _connectionId: 'test-connection',
|
|
89
|
-
// _requestMethod: 'test-method',
|
|
90
|
-
// peerId: 'peer-embeddings',
|
|
91
|
-
// address: 'o://leader/services/embeddings',
|
|
92
|
-
// staticAddress: 'o://embeddings-text',
|
|
93
|
-
// protocols: ['/embeddings/1.0.0'],
|
|
94
|
-
// transports: ['/ip4/127.0.0.1/tcp/6001'],
|
|
95
|
-
// };
|
|
96
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
97
|
-
// method: 'commit',
|
|
98
|
-
// params: registrationParams,
|
|
99
|
-
// });
|
|
100
|
-
// // Try to use the service by static address
|
|
101
|
-
// // The resolver should find it in the registry
|
|
102
|
-
// try {
|
|
103
|
-
// const result = await leader.use(new oAddress('o://embeddings-text'), {
|
|
104
|
-
// method: 'ping', // Some method that may not exist, but routing should work
|
|
105
|
-
// params: {},
|
|
106
|
-
// });
|
|
107
|
-
// // If we get here without error, routing worked
|
|
108
|
-
// // The actual method call may fail, but that's expected
|
|
109
|
-
// } catch (error: any) {
|
|
110
|
-
// // Expected - the service doesn't actually exist, but we should have resolved the address
|
|
111
|
-
// // Check that the error is about the method, not about routing
|
|
112
|
-
// expect(error.message).to.not.include('No route');
|
|
113
|
-
// }
|
|
114
|
-
// });
|
|
115
|
-
// it('should handle multiple services with same protocol', async () => {
|
|
116
|
-
// // Register two embedding services
|
|
117
|
-
// const service1: oRegistrationParams = {
|
|
118
|
-
// _connectionId: 'test-connection',
|
|
119
|
-
// _requestMethod: 'test-method',
|
|
120
|
-
// peerId: 'peer-embeddings-1',
|
|
121
|
-
// address: 'o://leader/services/embeddings-text',
|
|
122
|
-
// staticAddress: 'o://embeddings-text',
|
|
123
|
-
// protocols: ['/embeddings/1.0.0'],
|
|
124
|
-
// transports: ['/ip4/127.0.0.1/tcp/6001'],
|
|
125
|
-
// registeredAt: 1000,
|
|
126
|
-
// };
|
|
127
|
-
// const service2: oRegistrationParams = {
|
|
128
|
-
// _connectionId: 'test-connection',
|
|
129
|
-
// _requestMethod: 'test-method',
|
|
130
|
-
// peerId: 'peer-embeddings-2',
|
|
131
|
-
// address: 'o://leader/services/embeddings-image',
|
|
132
|
-
// staticAddress: 'o://embeddings-image',
|
|
133
|
-
// protocols: ['/embeddings/1.0.0'],
|
|
134
|
-
// transports: ['/ip4/127.0.0.1/tcp/6002'],
|
|
135
|
-
// registeredAt: 2000, // More recent
|
|
136
|
-
// };
|
|
137
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
138
|
-
// method: 'commit',
|
|
139
|
-
// params: service1,
|
|
140
|
-
// });
|
|
141
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
142
|
-
// method: 'commit',
|
|
143
|
-
// params: service2,
|
|
144
|
-
// });
|
|
145
|
-
// // Search by protocol - should return both, sorted by registeredAt
|
|
146
|
-
// const searchResult = await leader.use(
|
|
147
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
148
|
-
// {
|
|
149
|
-
// method: 'search',
|
|
150
|
-
// params: { protocols: ['/embeddings/1.0.0'] },
|
|
151
|
-
// },
|
|
152
|
-
// );
|
|
153
|
-
// expect(searchResult.result.data).to.have.lengthOf(2);
|
|
154
|
-
// expect((searchResult.result.data as any[])[0].peerId).to.equal(
|
|
155
|
-
// 'peer-embeddings-2',
|
|
156
|
-
// ); // Most recent
|
|
157
|
-
// expect((searchResult.result.data as any[])[1].peerId).to.equal(
|
|
158
|
-
// 'peer-embeddings-1',
|
|
159
|
-
// );
|
|
160
|
-
// });
|
|
161
|
-
// it('should handle service removal', async () => {
|
|
162
|
-
// const registrationParams: oRegistrationParams = {
|
|
163
|
-
// _connectionId: 'test-connection',
|
|
164
|
-
// _requestMethod: 'test-method',
|
|
165
|
-
// peerId: 'peer-temporary',
|
|
166
|
-
// address: 'o://leader/services/temporary',
|
|
167
|
-
// staticAddress: 'o://temporary',
|
|
168
|
-
// protocols: ['/temp/1.0.0'],
|
|
169
|
-
// transports: ['/memory'],
|
|
170
|
-
// };
|
|
171
|
-
// // Register
|
|
172
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
173
|
-
// method: 'commit',
|
|
174
|
-
// params: registrationParams,
|
|
175
|
-
// });
|
|
176
|
-
// // Verify it exists
|
|
177
|
-
// let searchResult = await leader.use(
|
|
178
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
179
|
-
// {
|
|
180
|
-
// method: 'search',
|
|
181
|
-
// params: { staticAddress: 'o://temporary' },
|
|
182
|
-
// },
|
|
183
|
-
// );
|
|
184
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
185
|
-
// // Remove
|
|
186
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
187
|
-
// method: 'remove',
|
|
188
|
-
// params: { peerId: 'peer-temporary' },
|
|
189
|
-
// });
|
|
190
|
-
// // Verify it's gone
|
|
191
|
-
// searchResult = await leader.use(
|
|
192
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
193
|
-
// {
|
|
194
|
-
// method: 'search',
|
|
195
|
-
// params: { staticAddress: 'o://temporary' },
|
|
196
|
-
// },
|
|
197
|
-
// );
|
|
198
|
-
// expect(searchResult.result.data).to.have.lengthOf(0);
|
|
199
|
-
// });
|
|
200
|
-
// it('should list all registered nodes', async () => {
|
|
201
|
-
// // Register multiple nodes
|
|
202
|
-
// const nodes: oRegistrationParams[] = [
|
|
203
|
-
// {
|
|
204
|
-
// _connectionId: 'test-connection',
|
|
205
|
-
// _requestMethod: 'test-method',
|
|
206
|
-
// peerId: 'peer-1',
|
|
207
|
-
// address: 'o://node-1',
|
|
208
|
-
// protocols: [],
|
|
209
|
-
// transports: ['/memory'],
|
|
210
|
-
// },
|
|
211
|
-
// {
|
|
212
|
-
// _connectionId: 'test-connection',
|
|
213
|
-
// _requestMethod: 'test-method',
|
|
214
|
-
// peerId: 'peer-2',
|
|
215
|
-
// address: 'o://node-2',
|
|
216
|
-
// protocols: [],
|
|
217
|
-
// transports: ['/memory'],
|
|
218
|
-
// },
|
|
219
|
-
// {
|
|
220
|
-
// _connectionId: 'test-connection',
|
|
221
|
-
// _requestMethod: 'test-method',
|
|
222
|
-
// peerId: 'peer-3',
|
|
223
|
-
// address: 'o://node-3',
|
|
224
|
-
// protocols: [],
|
|
225
|
-
// transports: ['/memory'],
|
|
226
|
-
// },
|
|
227
|
-
// ];
|
|
228
|
-
// for (const node of nodes) {
|
|
229
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
230
|
-
// method: 'commit',
|
|
231
|
-
// params: node,
|
|
232
|
-
// });
|
|
233
|
-
// }
|
|
234
|
-
// // Get all nodes
|
|
235
|
-
// const result = await leader.use(
|
|
236
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
237
|
-
// {
|
|
238
|
-
// method: 'find_all',
|
|
239
|
-
// params: {},
|
|
240
|
-
// },
|
|
241
|
-
// );
|
|
242
|
-
// expect(result.result.data as any[]).to.be.an('array');
|
|
243
|
-
// expect((result.result.data as any[]).length).to.be.at.least(3); // At least our 3 nodes
|
|
244
|
-
// const peerIds = (result.result.data as any[]).map((n: any) => n.peerId);
|
|
245
|
-
// expect(peerIds).to.include('peer-1');
|
|
246
|
-
// expect(peerIds).to.include('peer-2');
|
|
247
|
-
// expect(peerIds).to.include('peer-3');
|
|
248
|
-
// });
|
|
249
|
-
// });
|
|
250
|
-
// describe('Multi-node scenarios', () => {
|
|
251
|
-
// let leader: oLeaderNode;
|
|
252
|
-
// let childNode: oNode;
|
|
253
|
-
// beforeEach(async () => {
|
|
254
|
-
// leader = new oLeaderNode({
|
|
255
|
-
// name: 'test-leader',
|
|
256
|
-
// parent: null,
|
|
257
|
-
// leader: null,
|
|
258
|
-
// network: {
|
|
259
|
-
// listeners: [],
|
|
260
|
-
// },
|
|
261
|
-
// });
|
|
262
|
-
// await leader.start();
|
|
263
|
-
// });
|
|
264
|
-
// afterEach(async () => {
|
|
265
|
-
// if (childNode && childNode.state === NodeState.RUNNING) {
|
|
266
|
-
// await childNode.stop();
|
|
267
|
-
// }
|
|
268
|
-
// if (leader && leader.state === NodeState.RUNNING) {
|
|
269
|
-
// await leader.stop();
|
|
270
|
-
// }
|
|
271
|
-
// });
|
|
272
|
-
// it('should handle hierarchical node registration', async () => {
|
|
273
|
-
// // Create child node
|
|
274
|
-
// childNode = new oNode({
|
|
275
|
-
// address: new oNodeAddress('o://leader/services'),
|
|
276
|
-
// parent: leader.address as any,
|
|
277
|
-
// leader: leader.address as any,
|
|
278
|
-
// network: {
|
|
279
|
-
// listeners: [],
|
|
280
|
-
// },
|
|
281
|
-
// });
|
|
282
|
-
// await childNode.start();
|
|
283
|
-
// // Register the child in the registry
|
|
284
|
-
// const registrationParams: oRegistrationParams = {
|
|
285
|
-
// _connectionId: 'test-connection',
|
|
286
|
-
// _requestMethod: 'test-method',
|
|
287
|
-
// peerId: 'peer-services',
|
|
288
|
-
// address: 'o://leader/services',
|
|
289
|
-
// protocols: ['/services/1.0.0'],
|
|
290
|
-
// transports: ['/memory'],
|
|
291
|
-
// };
|
|
292
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
293
|
-
// method: 'commit',
|
|
294
|
-
// params: registrationParams,
|
|
295
|
-
// });
|
|
296
|
-
// // Search for it
|
|
297
|
-
// const searchResult = await leader.use(
|
|
298
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
299
|
-
// {
|
|
300
|
-
// method: 'search',
|
|
301
|
-
// params: { address: 'o://leader/services' },
|
|
302
|
-
// },
|
|
303
|
-
// );
|
|
304
|
-
// expect(searchResult.result.data as any[]).to.have.lengthOf(1);
|
|
305
|
-
// expect((searchResult.result.data as any[])[0].address).to.equal(
|
|
306
|
-
// 'o://leader/services',
|
|
307
|
-
// );
|
|
308
|
-
// });
|
|
309
|
-
// it('should support service discovery by protocol', async () => {
|
|
310
|
-
// // Register services with different protocols
|
|
311
|
-
// const services: oRegistrationParams[] = [
|
|
312
|
-
// {
|
|
313
|
-
// _connectionId: 'test-connection',
|
|
314
|
-
// _requestMethod: 'test-method',
|
|
315
|
-
// peerId: 'peer-embeddings',
|
|
316
|
-
// address: 'o://leader/ai/embeddings',
|
|
317
|
-
// protocols: ['/ai/embeddings/1.0.0', '/text/1.0.0'],
|
|
318
|
-
// transports: ['/memory'],
|
|
319
|
-
// },
|
|
320
|
-
// {
|
|
321
|
-
// _connectionId: 'test-connection',
|
|
322
|
-
// _requestMethod: 'test-method',
|
|
323
|
-
// peerId: 'peer-chat',
|
|
324
|
-
// address: 'o://leader/ai/chat',
|
|
325
|
-
// protocols: ['/ai/chat/1.0.0', '/text/1.0.0'],
|
|
326
|
-
// transports: ['/memory'],
|
|
327
|
-
// },
|
|
328
|
-
// {
|
|
329
|
-
// _connectionId: 'test-connection',
|
|
330
|
-
// _requestMethod: 'test-method',
|
|
331
|
-
// peerId: 'peer-vision',
|
|
332
|
-
// address: 'o://leader/ai/vision',
|
|
333
|
-
// protocols: ['/ai/vision/1.0.0', '/image/1.0.0'],
|
|
334
|
-
// transports: ['/memory'],
|
|
335
|
-
// },
|
|
336
|
-
// ];
|
|
337
|
-
// for (const service of services) {
|
|
338
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
339
|
-
// method: 'commit',
|
|
340
|
-
// params: service,
|
|
341
|
-
// });
|
|
342
|
-
// }
|
|
343
|
-
// // Find all text-based services
|
|
344
|
-
// const textServices = await leader.use(
|
|
345
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
346
|
-
// {
|
|
347
|
-
// method: 'search',
|
|
348
|
-
// params: { protocols: ['/text/1.0.0'] },
|
|
349
|
-
// },
|
|
350
|
-
// );
|
|
351
|
-
// expect(textServices.result.data as any[]).to.have.lengthOf(2);
|
|
352
|
-
// const peerIds = (textServices.result.data as any[]).map(
|
|
353
|
-
// (s: any) => s.peerId,
|
|
354
|
-
// );
|
|
355
|
-
// expect(peerIds).to.include.members(['peer-embeddings', 'peer-chat']);
|
|
356
|
-
// // Find embeddings service specifically
|
|
357
|
-
// const embeddingsService = await leader.use(
|
|
358
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
359
|
-
// {
|
|
360
|
-
// method: 'search',
|
|
361
|
-
// params: { protocols: ['/ai/embeddings/1.0.0'] },
|
|
362
|
-
// },
|
|
363
|
-
// );
|
|
364
|
-
// expect(embeddingsService.result.data).to.have.lengthOf(1);
|
|
365
|
-
// expect((embeddingsService.result.data as any[])[0].peerId).to.equal(
|
|
366
|
-
// 'peer-embeddings',
|
|
367
|
-
// );
|
|
368
|
-
// });
|
|
369
|
-
// it('should handle service updates on re-registration', async () => {
|
|
370
|
-
// const initialRegistration: oRegistrationParams = {
|
|
371
|
-
// _connectionId: 'test-connection',
|
|
372
|
-
// _requestMethod: 'test-method',
|
|
373
|
-
// peerId: 'peer-dynamic',
|
|
374
|
-
// address: 'o://leader/services/dynamic',
|
|
375
|
-
// protocols: ['/service/1.0.0'],
|
|
376
|
-
// transports: ['/ip4/127.0.0.1/tcp/4001'],
|
|
377
|
-
// registeredAt: 1000,
|
|
378
|
-
// };
|
|
379
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
380
|
-
// method: 'commit',
|
|
381
|
-
// params: initialRegistration,
|
|
382
|
-
// });
|
|
383
|
-
// // Simulate service update (new transport)
|
|
384
|
-
// const updatedRegistration: oRegistrationParams = {
|
|
385
|
-
// _connectionId: 'test-connection',
|
|
386
|
-
// _requestMethod: 'test-method',
|
|
387
|
-
// peerId: 'peer-dynamic',
|
|
388
|
-
// address: 'o://leader/services/dynamic',
|
|
389
|
-
// protocols: ['/service/1.0.0', '/service/2.0.0'], // Added new protocol
|
|
390
|
-
// transports: ['/ip4/192.168.1.1/tcp/4001'], // New transport
|
|
391
|
-
// registeredAt: 2000,
|
|
392
|
-
// };
|
|
393
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
394
|
-
// method: 'commit',
|
|
395
|
-
// params: updatedRegistration,
|
|
396
|
-
// });
|
|
397
|
-
// // Verify update
|
|
398
|
-
// const searchResult = await leader.use(
|
|
399
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
400
|
-
// {
|
|
401
|
-
// method: 'search',
|
|
402
|
-
// params: { address: 'o://leader/services/dynamic' },
|
|
403
|
-
// },
|
|
404
|
-
// );
|
|
405
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
406
|
-
// expect((searchResult.result.data as any[])[0].protocols).to.include(
|
|
407
|
-
// '/service/2.0.0',
|
|
408
|
-
// );
|
|
409
|
-
// expect((searchResult.result.data as any[])[0].transports[0]).to.equal(
|
|
410
|
-
// '/ip4/192.168.1.1/tcp/4001',
|
|
411
|
-
// );
|
|
412
|
-
// expect((searchResult.result.data as any[])[0].registeredAt).to.equal(
|
|
413
|
-
// 2000,
|
|
414
|
-
// );
|
|
415
|
-
// });
|
|
416
|
-
// });
|
|
417
|
-
// describe('Real-world routing scenarios', () => {
|
|
418
|
-
// let leader: oLeaderNode;
|
|
419
|
-
// beforeEach(async () => {
|
|
420
|
-
// leader = new oLeaderNode({
|
|
421
|
-
// name: 'test-leader',
|
|
422
|
-
// parent: null,
|
|
423
|
-
// leader: null,
|
|
424
|
-
// network: {
|
|
425
|
-
// listeners: [],
|
|
426
|
-
// },
|
|
427
|
-
// });
|
|
428
|
-
// await leader.start();
|
|
429
|
-
// });
|
|
430
|
-
// afterEach(async () => {
|
|
431
|
-
// if (leader && leader.state === NodeState.RUNNING) {
|
|
432
|
-
// await leader.stop();
|
|
433
|
-
// }
|
|
434
|
-
// });
|
|
435
|
-
// it('should route to static address via registry lookup', async () => {
|
|
436
|
-
// // Register service with static address
|
|
437
|
-
// const registrationParams: oRegistrationParams = {
|
|
438
|
-
// _connectionId: 'test-connection',
|
|
439
|
-
// _requestMethod: 'test-method',
|
|
440
|
-
// peerId: 'peer-static-service',
|
|
441
|
-
// address: 'o://leader/services/my-service',
|
|
442
|
-
// staticAddress: 'o://my-service',
|
|
443
|
-
// protocols: ['/service/1.0.0'],
|
|
444
|
-
// transports: ['/memory'],
|
|
445
|
-
// };
|
|
446
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
447
|
-
// method: 'commit',
|
|
448
|
-
// params: registrationParams,
|
|
449
|
-
// });
|
|
450
|
-
// // Verify static address search works
|
|
451
|
-
// const searchResult = await leader.use(
|
|
452
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
453
|
-
// {
|
|
454
|
-
// method: 'search',
|
|
455
|
-
// params: { staticAddress: 'o://my-service' },
|
|
456
|
-
// },
|
|
457
|
-
// );
|
|
458
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
459
|
-
// expect((searchResult.result.data as any[])[0].address).to.equal(
|
|
460
|
-
// 'o://leader/services/my-service',
|
|
461
|
-
// );
|
|
462
|
-
// expect((searchResult.result.data as any[])[0].staticAddress).to.equal(
|
|
463
|
-
// 'o://my-service',
|
|
464
|
-
// );
|
|
465
|
-
// });
|
|
466
|
-
// it('should handle hierarchical routing through services', async () => {
|
|
467
|
-
// // Register nested services
|
|
468
|
-
// const services: oRegistrationParams[] = [
|
|
469
|
-
// {
|
|
470
|
-
// _connectionId: 'test-connection',
|
|
471
|
-
// _requestMethod: 'test-method',
|
|
472
|
-
// peerId: 'peer-services-parent',
|
|
473
|
-
// address: 'o://leader/services',
|
|
474
|
-
// protocols: ['/services/1.0.0'],
|
|
475
|
-
// transports: ['/memory'],
|
|
476
|
-
// },
|
|
477
|
-
// {
|
|
478
|
-
// _connectionId: 'test-connection',
|
|
479
|
-
// _requestMethod: 'test-method',
|
|
480
|
-
// peerId: 'peer-embeddings-child',
|
|
481
|
-
// address: 'o://leader/services/embeddings',
|
|
482
|
-
// protocols: ['/embeddings/1.0.0'],
|
|
483
|
-
// transports: ['/memory'],
|
|
484
|
-
// },
|
|
485
|
-
// {
|
|
486
|
-
// _connectionId: 'test-connection',
|
|
487
|
-
// _requestMethod: 'test-method',
|
|
488
|
-
// peerId: 'peer-embeddings-text-leaf',
|
|
489
|
-
// address: 'o://leader/services/embeddings/text',
|
|
490
|
-
// staticAddress: 'o://embeddings-text',
|
|
491
|
-
// protocols: ['/embeddings/text/1.0.0'],
|
|
492
|
-
// transports: ['/memory'],
|
|
493
|
-
// },
|
|
494
|
-
// ];
|
|
495
|
-
// for (const service of services) {
|
|
496
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
497
|
-
// method: 'commit',
|
|
498
|
-
// params: service,
|
|
499
|
-
// });
|
|
500
|
-
// }
|
|
501
|
-
// // Verify all are registered
|
|
502
|
-
// const allServices = await leader.use(
|
|
503
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
504
|
-
// {
|
|
505
|
-
// method: 'find_all',
|
|
506
|
-
// params: {},
|
|
507
|
-
// },
|
|
508
|
-
// );
|
|
509
|
-
// const peerIds = (allServices.result.data as any[]).map(
|
|
510
|
-
// (s: any) => s.peerId,
|
|
511
|
-
// );
|
|
512
|
-
// expect(peerIds).to.include.members([
|
|
513
|
-
// 'peer-services-parent',
|
|
514
|
-
// 'peer-embeddings-child',
|
|
515
|
-
// 'peer-embeddings-text-leaf',
|
|
516
|
-
// ]);
|
|
517
|
-
// // Test routing through hierarchy using oAddress.next()
|
|
518
|
-
// const currentAddress = new oAddress('o://leader');
|
|
519
|
-
// const targetAddress = new oAddress('o://leader/services/embeddings/text');
|
|
520
|
-
// // First hop: leader -> leader/services
|
|
521
|
-
// const firstHop = oAddress.next(currentAddress, targetAddress);
|
|
522
|
-
// expect(firstHop.toString()).to.equal('o://leader/services');
|
|
523
|
-
// // Second hop: leader/services -> leader/services/embeddings
|
|
524
|
-
// const secondHop = oAddress.next(firstHop, targetAddress);
|
|
525
|
-
// expect(secondHop.toString()).to.equal('o://leader/services/embeddings');
|
|
526
|
-
// // Third hop: leader/services/embeddings -> leader/services/embeddings/text
|
|
527
|
-
// const thirdHop = oAddress.next(secondHop, targetAddress);
|
|
528
|
-
// expect(thirdHop.toString()).to.equal(
|
|
529
|
-
// 'o://leader/services/embeddings/text',
|
|
530
|
-
// );
|
|
531
|
-
// // Fourth hop: at destination
|
|
532
|
-
// const fourthHop = oAddress.next(thirdHop, targetAddress);
|
|
533
|
-
// expect(fourthHop.toString()).to.equal(
|
|
534
|
-
// 'o://leader/services/embeddings/text',
|
|
535
|
-
// );
|
|
536
|
-
// });
|
|
537
|
-
// it('should support searching with combined parameters', async () => {
|
|
538
|
-
// // Register service with multiple attributes
|
|
539
|
-
// const registrationParams: oRegistrationParams = {
|
|
540
|
-
// _connectionId: 'test-connection',
|
|
541
|
-
// _requestMethod: 'test-method',
|
|
542
|
-
// peerId: 'peer-complex',
|
|
543
|
-
// address: 'o://leader/ai/embeddings',
|
|
544
|
-
// staticAddress: 'o://embeddings-text',
|
|
545
|
-
// protocols: ['/embeddings/1.0.0', '/text/1.0.0', '/ai/1.0.0'],
|
|
546
|
-
// transports: ['/ip4/127.0.0.1/tcp/6001'],
|
|
547
|
-
// };
|
|
548
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
549
|
-
// method: 'commit',
|
|
550
|
-
// params: registrationParams,
|
|
551
|
-
// });
|
|
552
|
-
// // Search by static address
|
|
553
|
-
// const byStatic = await leader.use(
|
|
554
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
555
|
-
// {
|
|
556
|
-
// method: 'search',
|
|
557
|
-
// params: { staticAddress: 'o://embeddings-text' },
|
|
558
|
-
// },
|
|
559
|
-
// );
|
|
560
|
-
// expect(byStatic.result.data).to.have.lengthOf(1);
|
|
561
|
-
// // Search by exact address
|
|
562
|
-
// const byAddress = await leader.use(
|
|
563
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
564
|
-
// {
|
|
565
|
-
// method: 'search',
|
|
566
|
-
// params: { address: 'o://leader/ai/embeddings' },
|
|
567
|
-
// },
|
|
568
|
-
// );
|
|
569
|
-
// expect(byAddress.result.data).to.have.lengthOf(1);
|
|
570
|
-
// // Search by multiple protocols (AND logic)
|
|
571
|
-
// const byProtocols = await leader.use(
|
|
572
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
573
|
-
// {
|
|
574
|
-
// method: 'search',
|
|
575
|
-
// params: { protocols: ['/embeddings/1.0.0', '/text/1.0.0'] },
|
|
576
|
-
// },
|
|
577
|
-
// );
|
|
578
|
-
// expect(byProtocols.result.data).to.have.lengthOf(1);
|
|
579
|
-
// // Search by single protocol
|
|
580
|
-
// const bySingleProtocol = await leader.use(
|
|
581
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
582
|
-
// {
|
|
583
|
-
// method: 'search',
|
|
584
|
-
// params: { protocols: ['/ai/1.0.0'] },
|
|
585
|
-
// },
|
|
586
|
-
// );
|
|
587
|
-
// expect(bySingleProtocol.result.data).to.have.lengthOf(1);
|
|
588
|
-
// });
|
|
589
|
-
// it('should handle registry preventing infinite loops', async () => {
|
|
590
|
-
// // Try to register registry itself (should work, but search should filter it)
|
|
591
|
-
// const registryRegistration: oRegistrationParams = {
|
|
592
|
-
// _connectionId: 'test-connection',
|
|
593
|
-
// _requestMethod: 'test-method',
|
|
594
|
-
// peerId: 'peer-registry',
|
|
595
|
-
// address: RestrictedAddresses.REGISTRY,
|
|
596
|
-
// staticAddress: RestrictedAddresses.REGISTRY,
|
|
597
|
-
// protocols: ['/registry/1.0.0'],
|
|
598
|
-
// transports: ['/memory'],
|
|
599
|
-
// };
|
|
600
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
601
|
-
// method: 'commit',
|
|
602
|
-
// params: registryRegistration,
|
|
603
|
-
// });
|
|
604
|
-
// // Verify it's in the registry
|
|
605
|
-
// const allNodes = await leader.use(
|
|
606
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
607
|
-
// {
|
|
608
|
-
// method: 'find_all',
|
|
609
|
-
// params: {},
|
|
610
|
-
// },
|
|
611
|
-
// );
|
|
612
|
-
// const registryNode = (allNodes.result.data as any[]).find(
|
|
613
|
-
// (n: any) => n.peerId === 'peer-registry',
|
|
614
|
-
// );
|
|
615
|
-
// expect(registryNode).to.exist;
|
|
616
|
-
// // But search resolver should filter it out to prevent loops
|
|
617
|
-
// // This is tested in the resolver unit tests
|
|
618
|
-
// });
|
|
619
|
-
// it('should handle empty registry gracefully', async () => {
|
|
620
|
-
// // Search empty registry
|
|
621
|
-
// const searchResult = await leader.use(
|
|
622
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
623
|
-
// {
|
|
624
|
-
// method: 'search',
|
|
625
|
-
// params: { staticAddress: 'o://nonexistent' },
|
|
626
|
-
// },
|
|
627
|
-
// );
|
|
628
|
-
// expect(searchResult.result.data).to.be.an('array');
|
|
629
|
-
// expect(searchResult.result.data).to.have.lengthOf(0);
|
|
630
|
-
// });
|
|
631
|
-
// it('should handle multiple transports per service', async () => {
|
|
632
|
-
// const registrationParams: oRegistrationParams = {
|
|
633
|
-
// _connectionId: 'test-connection',
|
|
634
|
-
// _requestMethod: 'test-method',
|
|
635
|
-
// peerId: 'peer-multi-transport',
|
|
636
|
-
// address: 'o://leader/services/multi',
|
|
637
|
-
// staticAddress: 'o://multi-transport',
|
|
638
|
-
// protocols: ['/multi/1.0.0'],
|
|
639
|
-
// transports: [
|
|
640
|
-
// '/ip4/127.0.0.1/tcp/4001',
|
|
641
|
-
// '/ip4/192.168.1.1/tcp/4001',
|
|
642
|
-
// '/ip6/::1/tcp/4001',
|
|
643
|
-
// ],
|
|
644
|
-
// };
|
|
645
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
646
|
-
// method: 'commit',
|
|
647
|
-
// params: registrationParams,
|
|
648
|
-
// });
|
|
649
|
-
// const searchResult = await leader.use(
|
|
650
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
651
|
-
// {
|
|
652
|
-
// method: 'search',
|
|
653
|
-
// params: { staticAddress: 'o://multi-transport' },
|
|
654
|
-
// },
|
|
655
|
-
// );
|
|
656
|
-
// expect(
|
|
657
|
-
// (searchResult.result.data as any[])[0].transports,
|
|
658
|
-
// ).to.have.lengthOf(3);
|
|
659
|
-
// expect((searchResult.result.data as any[])[0].transports).to.include(
|
|
660
|
-
// '/ip4/127.0.0.1/tcp/4001',
|
|
661
|
-
// );
|
|
662
|
-
// expect((searchResult.result.data as any[])[0].transports).to.include(
|
|
663
|
-
// '/ip4/192.168.1.1/tcp/4001',
|
|
664
|
-
// );
|
|
665
|
-
// expect((searchResult.result.data as any[])[0].transports).to.include(
|
|
666
|
-
// '/ip6/::1/tcp/4001',
|
|
667
|
-
// );
|
|
668
|
-
// });
|
|
669
|
-
// });
|
|
670
|
-
// describe('Edge cases and error handling', () => {
|
|
671
|
-
// let leader: oLeaderNode;
|
|
672
|
-
// beforeEach(async () => {
|
|
673
|
-
// leader = new oLeaderNode({
|
|
674
|
-
// name: 'test-leader',
|
|
675
|
-
// parent: null,
|
|
676
|
-
// leader: null,
|
|
677
|
-
// network: {
|
|
678
|
-
// listeners: [],
|
|
679
|
-
// },
|
|
680
|
-
// });
|
|
681
|
-
// await leader.start();
|
|
682
|
-
// });
|
|
683
|
-
// afterEach(async () => {
|
|
684
|
-
// if (leader && leader.state === NodeState.RUNNING) {
|
|
685
|
-
// await leader.stop();
|
|
686
|
-
// }
|
|
687
|
-
// });
|
|
688
|
-
// it('should handle service with long address path', async () => {
|
|
689
|
-
// const registrationParams: oRegistrationParams = {
|
|
690
|
-
// _connectionId: 'test-connection',
|
|
691
|
-
// _requestMethod: 'test-method',
|
|
692
|
-
// peerId: 'peer-deep',
|
|
693
|
-
// address: 'o://leader/a/b/c/d/e/f/g/h/i/j/service',
|
|
694
|
-
// protocols: ['/deep/1.0.0'],
|
|
695
|
-
// transports: ['/memory'],
|
|
696
|
-
// };
|
|
697
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
698
|
-
// method: 'commit',
|
|
699
|
-
// params: registrationParams,
|
|
700
|
-
// });
|
|
701
|
-
// const searchResult = await leader.use(
|
|
702
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
703
|
-
// {
|
|
704
|
-
// method: 'search',
|
|
705
|
-
// params: { address: 'o://leader/a/b/c/d/e/f/g/h/i/j/service' },
|
|
706
|
-
// },
|
|
707
|
-
// );
|
|
708
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
709
|
-
// });
|
|
710
|
-
// it('should handle service with special characters', async () => {
|
|
711
|
-
// const registrationParams: oRegistrationParams = {
|
|
712
|
-
// _connectionId: 'test-connection',
|
|
713
|
-
// _requestMethod: 'test-method',
|
|
714
|
-
// peerId: 'peer-special-chars',
|
|
715
|
-
// address: 'o://leader/my-service_v2.0',
|
|
716
|
-
// staticAddress: 'o://my-service_v2.0',
|
|
717
|
-
// protocols: ['/service/2.0.0'],
|
|
718
|
-
// transports: ['/memory'],
|
|
719
|
-
// };
|
|
720
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
721
|
-
// method: 'commit',
|
|
722
|
-
// params: registrationParams,
|
|
723
|
-
// });
|
|
724
|
-
// const searchResult = await leader.use(
|
|
725
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
726
|
-
// {
|
|
727
|
-
// method: 'search',
|
|
728
|
-
// params: { staticAddress: 'o://my-service_v2.0' },
|
|
729
|
-
// },
|
|
730
|
-
// );
|
|
731
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
732
|
-
// expect((searchResult.result.data as any[])[0].address).to.equal(
|
|
733
|
-
// 'o://leader/my-service_v2.0',
|
|
734
|
-
// );
|
|
735
|
-
// });
|
|
736
|
-
// it('should handle service with empty protocols array', async () => {
|
|
737
|
-
// const registrationParams: oRegistrationParams = {
|
|
738
|
-
// _connectionId: 'test-connection',
|
|
739
|
-
// _requestMethod: 'test-method',
|
|
740
|
-
// peerId: 'peer-no-protocols',
|
|
741
|
-
// address: 'o://leader/services/no-protocols',
|
|
742
|
-
// protocols: [],
|
|
743
|
-
// transports: ['/memory'],
|
|
744
|
-
// };
|
|
745
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
746
|
-
// method: 'commit',
|
|
747
|
-
// params: registrationParams,
|
|
748
|
-
// });
|
|
749
|
-
// const searchResult = await leader.use(
|
|
750
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
751
|
-
// {
|
|
752
|
-
// method: 'search',
|
|
753
|
-
// params: { address: 'o://leader/services/no-protocols' },
|
|
754
|
-
// },
|
|
755
|
-
// );
|
|
756
|
-
// expect(searchResult.result.data).to.have.lengthOf(1);
|
|
757
|
-
// expect((searchResult.result.data as any[])[0].protocols).to.be.an('array')
|
|
758
|
-
// .that.is.empty;
|
|
759
|
-
// });
|
|
760
|
-
// it('should handle concurrent registrations', async () => {
|
|
761
|
-
// const registrations: oRegistrationParams[] = [];
|
|
762
|
-
// for (let i = 0; i < 10; i++) {
|
|
763
|
-
// registrations.push({
|
|
764
|
-
// _connectionId: 'test-connection',
|
|
765
|
-
// _requestMethod: 'test-method',
|
|
766
|
-
// peerId: `peer-concurrent-${i}`,
|
|
767
|
-
// address: `o://leader/services/concurrent-${i}`,
|
|
768
|
-
// protocols: ['/concurrent/1.0.0'],
|
|
769
|
-
// transports: ['/memory'],
|
|
770
|
-
// registeredAt: Date.now() + i,
|
|
771
|
-
// });
|
|
772
|
-
// }
|
|
773
|
-
// // Register concurrently
|
|
774
|
-
// const promises = registrations.map((params) =>
|
|
775
|
-
// leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
776
|
-
// method: 'commit',
|
|
777
|
-
// params,
|
|
778
|
-
// }),
|
|
779
|
-
// );
|
|
780
|
-
// await Promise.all(promises);
|
|
781
|
-
// // Verify all were registered
|
|
782
|
-
// const searchResult = await leader.use(
|
|
783
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
784
|
-
// {
|
|
785
|
-
// method: 'search',
|
|
786
|
-
// params: { protocols: ['/concurrent/1.0.0'] },
|
|
787
|
-
// },
|
|
788
|
-
// );
|
|
789
|
-
// expect(searchResult.result.data).to.have.lengthOf(10);
|
|
790
|
-
// });
|
|
791
|
-
// it('should maintain sort order after multiple operations', async () => {
|
|
792
|
-
// const nodes = [
|
|
793
|
-
// { peerId: 'peer-1', registeredAt: 1000 },
|
|
794
|
-
// { peerId: 'peer-2', registeredAt: 2000 },
|
|
795
|
-
// { peerId: 'peer-3', registeredAt: 3000 },
|
|
796
|
-
// ];
|
|
797
|
-
// for (const node of nodes) {
|
|
798
|
-
// await leader.use(new oAddress(RestrictedAddresses.REGISTRY), {
|
|
799
|
-
// method: 'commit',
|
|
800
|
-
// params: {
|
|
801
|
-
// ...node,
|
|
802
|
-
// address: `o://${node.peerId}`,
|
|
803
|
-
// protocols: ['/test/1.0.0'],
|
|
804
|
-
// transports: ['/memory'],
|
|
805
|
-
// } as oRegistrationParams,
|
|
806
|
-
// });
|
|
807
|
-
// }
|
|
808
|
-
// const searchResult = await leader.use(
|
|
809
|
-
// new oAddress(RestrictedAddresses.REGISTRY),
|
|
810
|
-
// {
|
|
811
|
-
// method: 'search',
|
|
812
|
-
// params: { protocols: ['/test/1.0.0'] },
|
|
813
|
-
// },
|
|
814
|
-
// );
|
|
815
|
-
// // Should be sorted by registeredAt descending (most recent first)
|
|
816
|
-
// expect((searchResult.result.data as any[])[0].peerId).to.equal('peer-3');
|
|
817
|
-
// expect((searchResult.result.data as any[])[1].peerId).to.equal('peer-2');
|
|
818
|
-
// expect((searchResult.result.data as any[])[2].peerId).to.equal('peer-1');
|
|
819
|
-
// });
|
|
820
|
-
// });
|
|
821
|
-
// });
|