@dxos/network-manager 0.1.16 → 0.1.18
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/lib/browser/index.mjs +144 -276
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +153 -342
- package/dist/lib/node/index.cjs +145 -281
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +153 -345
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/network-manager.d.ts +1 -5
- package/dist/types/src/network-manager.d.ts.map +1 -1
- package/dist/types/src/swarm/connection.d.ts +4 -0
- package/dist/types/src/swarm/connection.d.ts.map +1 -1
- package/dist/types/src/swarm/peer.d.ts.map +1 -1
- package/dist/types/src/swarm/swarm-mapper.d.ts +1 -3
- package/dist/types/src/swarm/swarm-mapper.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +0 -1
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-builder.d.ts +2 -2
- package/dist/types/src/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-wire-protocol.d.ts +14 -0
- package/dist/types/src/testing/test-wire-protocol.d.ts.map +1 -0
- package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
- package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
- package/dist/types/src/tests/utils.d.ts.map +1 -1
- package/dist/types/src/transport/memory-transport.d.ts +3 -3
- package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
- package/dist/types/src/wire-protocol.d.ts +0 -10
- package/dist/types/src/wire-protocol.d.ts.map +1 -1
- package/package.json +16 -18
- package/src/connection-log.ts +26 -26
- package/src/index.ts +0 -1
- package/src/network-manager.ts +1 -8
- package/src/swarm/connection.ts +12 -1
- package/src/swarm/peer.ts +1 -3
- package/src/swarm/swarm-mapper.ts +29 -31
- package/src/swarm/swarm.test.ts +12 -34
- package/src/testing/index.ts +0 -1
- package/src/testing/test-builder.ts +4 -7
- package/src/testing/test-wire-protocol.ts +44 -0
- package/src/tests/basic-test-suite.ts +13 -53
- package/src/tests/property-test-suite.ts +13 -15
- package/src/tests/utils.ts +10 -37
- package/src/transport/memory-transport.test.ts +13 -52
- package/src/transport/memory-transport.ts +37 -29
- package/src/transport/webrtc-transport-proxy.test.ts +13 -73
- package/src/transport/webrtc-transport.test.ts +7 -38
- package/src/wire-protocol.ts +0 -24
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/testing/index.cjs.map +0 -7
- package/dist/types/src/protocol-factory.d.ts +0 -36
- package/dist/types/src/protocol-factory.d.ts.map +0 -1
- package/dist/types/src/testing/test-protocol.d.ts +0 -52
- package/dist/types/src/testing/test-protocol.d.ts.map +0 -1
- package/dist/types/src/tests/presence.test.d.ts +0 -2
- package/dist/types/src/tests/presence.test.d.ts.map +0 -1
- package/src/protocol-factory.ts +0 -88
- package/src/testing/test-protocol.ts +0 -166
- package/src/tests/presence.test.ts +0 -80
package/src/swarm/swarm.test.ts
CHANGED
|
@@ -5,18 +5,16 @@
|
|
|
5
5
|
// @dxos/test platform=nodejs
|
|
6
6
|
|
|
7
7
|
import { expect } from 'earljs';
|
|
8
|
-
import waitForExpect from 'wait-for-expect';
|
|
9
8
|
|
|
10
|
-
import {
|
|
9
|
+
import { asyncTimeout, sleep } from '@dxos/async';
|
|
11
10
|
import { PublicKey } from '@dxos/keys';
|
|
12
11
|
import { log } from '@dxos/log';
|
|
13
12
|
import { MemorySignalManager, MemorySignalManagerContext, Messenger } from '@dxos/messaging';
|
|
14
|
-
import { beforeEach, describe, test
|
|
13
|
+
import { afterTest, beforeEach, describe, test } from '@dxos/test';
|
|
15
14
|
|
|
16
|
-
import {
|
|
15
|
+
import { TestWireProtocol } from '../testing/test-wire-protocol';
|
|
17
16
|
import { FullyConnectedTopology } from '../topology';
|
|
18
17
|
import { createWebRTCTransportFactory } from '../transport';
|
|
19
|
-
import { adaptProtocolProvider } from '../wire-protocol';
|
|
20
18
|
import { Swarm } from './swarm';
|
|
21
19
|
|
|
22
20
|
describe('Swarm', () => {
|
|
@@ -29,12 +27,12 @@ describe('Swarm', () => {
|
|
|
29
27
|
});
|
|
30
28
|
|
|
31
29
|
const setupSwarm = ({ topic, peerId }: { topic: PublicKey; peerId: PublicKey }) => {
|
|
32
|
-
const
|
|
30
|
+
const protocol = new TestWireProtocol(peerId);
|
|
33
31
|
const swarm = new Swarm(
|
|
34
32
|
topic,
|
|
35
33
|
peerId,
|
|
36
34
|
new FullyConnectedTopology(),
|
|
37
|
-
|
|
35
|
+
protocol.factory,
|
|
38
36
|
new Messenger({ signalManager }),
|
|
39
37
|
createWebRTCTransportFactory(),
|
|
40
38
|
undefined
|
|
@@ -44,25 +42,17 @@ describe('Swarm', () => {
|
|
|
44
42
|
await swarm.destroy();
|
|
45
43
|
});
|
|
46
44
|
|
|
47
|
-
return { swarm,
|
|
45
|
+
return { swarm, protocol };
|
|
48
46
|
};
|
|
49
47
|
|
|
50
48
|
test('connects two peers in a swarm', async () => {
|
|
51
49
|
const topic = PublicKey.random();
|
|
52
50
|
const peerId1 = PublicKey.random();
|
|
53
51
|
const peerId2 = PublicKey.random();
|
|
54
|
-
const data = 'Hello';
|
|
55
52
|
|
|
56
|
-
const { swarm: swarm1,
|
|
57
|
-
let receivedData: string;
|
|
58
|
-
plugin1.on('receive', async (_, payload) => {
|
|
59
|
-
receivedData = payload;
|
|
60
|
-
});
|
|
53
|
+
const { swarm: swarm1, protocol: protocol1 } = setupSwarm({ topic, peerId: peerId1 });
|
|
61
54
|
|
|
62
|
-
const { swarm: swarm2
|
|
63
|
-
plugin2.on('connect', async () => {
|
|
64
|
-
await plugin2.send(peerId1.asBuffer(), data);
|
|
65
|
-
});
|
|
55
|
+
const { swarm: swarm2 } = setupSwarm({ topic, peerId: peerId2 });
|
|
66
56
|
|
|
67
57
|
expect(swarm1.connections.length).toEqual(0);
|
|
68
58
|
expect(swarm2.connections.length).toEqual(0);
|
|
@@ -91,9 +81,7 @@ describe('Swarm', () => {
|
|
|
91
81
|
await promise;
|
|
92
82
|
log('Swarms connected');
|
|
93
83
|
|
|
94
|
-
await
|
|
95
|
-
expect(receivedData).toEqual(data);
|
|
96
|
-
});
|
|
84
|
+
await protocol1.testConnection(peerId2);
|
|
97
85
|
}).timeout(5_000);
|
|
98
86
|
|
|
99
87
|
test('two peers try to originate connections to each other simultaneously', async () => {
|
|
@@ -130,18 +118,10 @@ describe('Swarm', () => {
|
|
|
130
118
|
const topic = PublicKey.random();
|
|
131
119
|
const peerId1 = PublicKey.random();
|
|
132
120
|
const peerId2 = PublicKey.random();
|
|
133
|
-
const data = 'Hello';
|
|
134
121
|
|
|
135
|
-
const { swarm: swarm1,
|
|
136
|
-
let receivedData: string;
|
|
137
|
-
plugin1.on('receive', async (_, payload) => {
|
|
138
|
-
receivedData = payload;
|
|
139
|
-
});
|
|
122
|
+
const { swarm: swarm1, protocol: protocol1 } = setupSwarm({ topic, peerId: peerId1 });
|
|
140
123
|
|
|
141
|
-
const { swarm: swarm2
|
|
142
|
-
plugin2.on('connect', async () => {
|
|
143
|
-
await plugin2.send(peerId1.asBuffer(), data);
|
|
144
|
-
});
|
|
124
|
+
const { swarm: swarm2 } = setupSwarm({ topic, peerId: peerId2 });
|
|
145
125
|
|
|
146
126
|
expect(swarm1.connections.length).toEqual(0);
|
|
147
127
|
expect(swarm2.connections.length).toEqual(0);
|
|
@@ -164,8 +144,6 @@ describe('Swarm', () => {
|
|
|
164
144
|
|
|
165
145
|
await connectPromises;
|
|
166
146
|
|
|
167
|
-
await
|
|
168
|
-
expect(receivedData).toEqual(data);
|
|
169
|
-
});
|
|
147
|
+
await protocol1.testConnection(peerId2);
|
|
170
148
|
}).timeout(10_000);
|
|
171
149
|
});
|
package/src/testing/index.ts
CHANGED
|
@@ -17,8 +17,7 @@ import {
|
|
|
17
17
|
WebRTCTransportProxyFactory,
|
|
18
18
|
WebRTCTransportService
|
|
19
19
|
} from '../transport';
|
|
20
|
-
import {
|
|
21
|
-
import { TestProtocolPlugin, testProtocolProvider } from './test-protocol';
|
|
20
|
+
import { TestWireProtocol } from './test-wire-protocol';
|
|
22
21
|
|
|
23
22
|
// Signal server will be started by the setup script.
|
|
24
23
|
export const TEST_SIGNAL_URL = 'ws://localhost:4000/.well-known/dx/signal';
|
|
@@ -152,12 +151,12 @@ export class TestPeer {
|
|
|
152
151
|
|
|
153
152
|
// TODO(burdon): Reconcile with new Swarm concept.
|
|
154
153
|
export class TestSwarmConnection {
|
|
155
|
-
|
|
154
|
+
protocol: TestWireProtocol;
|
|
156
155
|
|
|
157
156
|
constructor(readonly peer: TestPeer, readonly topic: PublicKey) {
|
|
158
157
|
// TODO(burdon): Configure plugins.
|
|
159
158
|
// TODO(burdon): Prevent reuse?
|
|
160
|
-
this.
|
|
159
|
+
this.protocol = new TestWireProtocol(this.peer.peerId);
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
// TODO(burdon): Need to create new plugin instance per swarm?
|
|
@@ -166,9 +165,7 @@ export class TestSwarmConnection {
|
|
|
166
165
|
await this.peer._networkManager.joinSwarm({
|
|
167
166
|
topic: this.topic,
|
|
168
167
|
peerId: this.peer.peerId,
|
|
169
|
-
protocolProvider:
|
|
170
|
-
testProtocolProvider(this.topic.asBuffer(), this.peer.peerId, this.plugin)
|
|
171
|
-
),
|
|
168
|
+
protocolProvider: this.protocol.factory,
|
|
172
169
|
topology
|
|
173
170
|
});
|
|
174
171
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { PublicKey } from '@dxos/keys';
|
|
7
|
+
import { log } from '@dxos/log';
|
|
8
|
+
import { TestExtension } from '@dxos/teleport';
|
|
9
|
+
import { ComplexMap } from '@dxos/util';
|
|
10
|
+
|
|
11
|
+
import { createTeleportProtocolFactory } from '../wire-protocol';
|
|
12
|
+
|
|
13
|
+
export class TestWireProtocol {
|
|
14
|
+
public readonly connections = new ComplexMap<PublicKey, TestExtension>(PublicKey.hash);
|
|
15
|
+
public readonly connected = new Event<PublicKey>();
|
|
16
|
+
|
|
17
|
+
constructor(public readonly peerId: PublicKey) {}
|
|
18
|
+
|
|
19
|
+
readonly factory = createTeleportProtocolFactory(async (teleport) => {
|
|
20
|
+
log('create', { remotePeerId: teleport.remotePeerId });
|
|
21
|
+
const extension = new TestExtension({
|
|
22
|
+
onClose: async () => {
|
|
23
|
+
this.connections.delete(teleport.remotePeerId);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
this.connections.set(teleport.remotePeerId, extension);
|
|
27
|
+
teleport.addExtension('test', extension);
|
|
28
|
+
this.connected.emit(teleport.remotePeerId);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
async waitForConnection(peerId: PublicKey) {
|
|
32
|
+
if (this.connections.has(peerId)) {
|
|
33
|
+
return this.connections.get(peerId)!;
|
|
34
|
+
}
|
|
35
|
+
log('waitForConnection', { peerId });
|
|
36
|
+
await this.connected.waitFor((connectedId) => connectedId.equals(peerId));
|
|
37
|
+
return this.connections.get(peerId)!;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async testConnection(peerId: PublicKey) {
|
|
41
|
+
const connection = await this.waitForConnection(peerId);
|
|
42
|
+
await connection.test();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -3,12 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { expect } from 'chai';
|
|
6
|
-
import waitForExpect from 'wait-for-expect';
|
|
7
6
|
|
|
8
|
-
import { latch } from '@dxos/async';
|
|
9
7
|
import { PublicKey } from '@dxos/keys';
|
|
10
8
|
import { log } from '@dxos/log';
|
|
11
|
-
import { Protocol } from '@dxos/mesh-protocol';
|
|
12
9
|
import { test } from '@dxos/test';
|
|
13
10
|
import { range } from '@dxos/util';
|
|
14
11
|
|
|
@@ -88,11 +85,8 @@ export const basicTestSuite = (testBuilder: TestBuilder, runTests = true) => {
|
|
|
88
85
|
expect(topics).to.have.length(numSwarms);
|
|
89
86
|
});
|
|
90
87
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Generalize for n swarms and factor into other tests; configure message activity.
|
|
94
|
-
test.skip('joins multiple swarms concurrently', async () => {
|
|
95
|
-
const createSwarm = async (messages: any[], label: string) => {
|
|
88
|
+
test('joins multiple swarms concurrently', async () => {
|
|
89
|
+
const createSwarm = async () => {
|
|
96
90
|
const topicA = PublicKey.random();
|
|
97
91
|
const peer1a = testBuilder.createPeer();
|
|
98
92
|
const peer2a = testBuilder.createPeer();
|
|
@@ -100,33 +94,19 @@ export const basicTestSuite = (testBuilder: TestBuilder, runTests = true) => {
|
|
|
100
94
|
const swarm1a = await peer1a.createSwarm(topicA).join();
|
|
101
95
|
const swarm2a = await peer2a.createSwarm(topicA).join();
|
|
102
96
|
|
|
103
|
-
swarm1a
|
|
104
|
-
messages.push(msg);
|
|
105
|
-
});
|
|
106
|
-
swarm2a.plugin.on('connect', async () => {
|
|
107
|
-
await swarm2a.plugin.send(peer1a.peerId.asBuffer(), label);
|
|
108
|
-
});
|
|
97
|
+
return { swarm1a, swarm2a, peer1a, peer2a };
|
|
109
98
|
};
|
|
110
99
|
|
|
111
|
-
const
|
|
112
|
-
const
|
|
100
|
+
const test1 = await createSwarm();
|
|
101
|
+
const test2 = await createSwarm();
|
|
113
102
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
await waitForExpect(() => {
|
|
119
|
-
expect(receivedA).to.have.length(1);
|
|
120
|
-
expect(receivedB).to.have.length(1);
|
|
121
|
-
|
|
122
|
-
expect(receivedA[0]).to.eq('Swarm A');
|
|
123
|
-
expect(receivedB[0]).to.eq('Swarm B');
|
|
124
|
-
});
|
|
103
|
+
await Promise.all([
|
|
104
|
+
test1.swarm1a.protocol.testConnection(test1.peer2a.peerId),
|
|
105
|
+
test2.swarm1a.protocol.testConnection(test1.peer2a.peerId)
|
|
106
|
+
]);
|
|
125
107
|
});
|
|
126
108
|
|
|
127
|
-
|
|
128
|
-
// TODO(burdon): Factor out components of test.
|
|
129
|
-
test.skip('many peers and connections', async () => {
|
|
109
|
+
test('many peers and connections', async () => {
|
|
130
110
|
const numTopics = 5;
|
|
131
111
|
const peersPerTopic = 5;
|
|
132
112
|
|
|
@@ -138,29 +118,9 @@ export const basicTestSuite = (testBuilder: TestBuilder, runTests = true) => {
|
|
|
138
118
|
range(peersPerTopic).map(async () => {
|
|
139
119
|
const peer = testBuilder.createPeer();
|
|
140
120
|
const swarm = await peer.createSwarm(topic).join();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
swarm.plugin.on('connect', async (protocol: Protocol) => {
|
|
145
|
-
const { peerId } = protocol.getSession() ?? {};
|
|
146
|
-
const remoteId = PublicKey.from(peerId);
|
|
147
|
-
await swarm.plugin.send(remoteId.asBuffer(), 'ping');
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
swarm.plugin.on('receive', async (protocol: Protocol, data: any) => {
|
|
151
|
-
const { peerId } = protocol.getSession() ?? {};
|
|
152
|
-
const remoteId = PublicKey.from(peerId);
|
|
153
|
-
|
|
154
|
-
if (data === 'ping') {
|
|
155
|
-
await swarm.plugin.send(remoteId.asBuffer(), 'pong');
|
|
156
|
-
} else if (data === 'pong') {
|
|
157
|
-
pongReceived();
|
|
158
|
-
} else {
|
|
159
|
-
throw new Error(`Invalid message: ${data}`);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
await done();
|
|
121
|
+
await swarm.protocol.connected.waitForCondition(
|
|
122
|
+
() => swarm.protocol.connections.size === peersPerTopic - 1
|
|
123
|
+
);
|
|
164
124
|
})
|
|
165
125
|
);
|
|
166
126
|
})
|
|
@@ -6,15 +6,13 @@ import * as fc from 'fast-check';
|
|
|
6
6
|
import { ModelRunSetup } from 'fast-check';
|
|
7
7
|
import waitForExpect from 'wait-for-expect';
|
|
8
8
|
|
|
9
|
+
import { todo } from '@dxos/debug';
|
|
9
10
|
import { PublicKey } from '@dxos/keys';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { range, ComplexMap, ComplexSet } from '@dxos/util';
|
|
11
|
+
import { test } from '@dxos/test';
|
|
12
|
+
import { ComplexMap, ComplexSet, range } from '@dxos/util';
|
|
13
13
|
|
|
14
14
|
import { NetworkManager } from '../network-manager';
|
|
15
|
-
import { createProtocolFactory } from '../protocol-factory';
|
|
16
15
|
import { FullyConnectedTopology } from '../topology';
|
|
17
|
-
import { adaptProtocolProvider } from '../wire-protocol';
|
|
18
16
|
|
|
19
17
|
/**
|
|
20
18
|
* Performs random actions in the real system and compares its state with a simplified model.
|
|
@@ -35,7 +33,7 @@ export const propertyTestSuite = () => {
|
|
|
35
33
|
* The real system being tested.
|
|
36
34
|
*/
|
|
37
35
|
interface Real {
|
|
38
|
-
peers: ComplexMap<PublicKey, { networkManager: NetworkManager; presence?:
|
|
36
|
+
peers: ComplexMap<PublicKey, { networkManager: NetworkManager; presence?: any }>;
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
const assertState = async (model: Model, real: Real) => {
|
|
@@ -48,12 +46,12 @@ export const propertyTestSuite = () => {
|
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
const actuallyConnectedPeers = peer.presence!.peers;
|
|
51
|
-
if (!actuallyConnectedPeers.some((peer) => PublicKey.equals(expectedPeerId, peer))) {
|
|
49
|
+
if (!actuallyConnectedPeers.some((peer: any) => PublicKey.equals(expectedPeerId, peer))) {
|
|
52
50
|
// TODO(burdon): More concise error.
|
|
53
51
|
const context = {
|
|
54
52
|
peerId: peer.presence.peerId,
|
|
55
53
|
expectedPeerId: expectedPeerId.truncate(),
|
|
56
|
-
connectedPeerIds: actuallyConnectedPeers.map((key) => key.toString('hex'))
|
|
54
|
+
connectedPeerIds: actuallyConnectedPeers.map((key: any) => key.toString('hex'))
|
|
57
55
|
};
|
|
58
56
|
|
|
59
57
|
throw new Error(`Expected peer to be in the list of joined peers: ${context}`);
|
|
@@ -118,19 +116,19 @@ export const propertyTestSuite = () => {
|
|
|
118
116
|
|
|
119
117
|
const peer = real.peers.get(this.peerId)!;
|
|
120
118
|
|
|
121
|
-
const presence = new PresencePlugin(this.peerId.asBuffer());
|
|
122
|
-
afterTest(() => presence.stop());
|
|
123
|
-
const protocol = createProtocolFactory(model.topic, this.peerId, [presence]);
|
|
119
|
+
// const presence = new PresencePlugin(this.peerId.asBuffer());
|
|
120
|
+
// afterTest(() => presence.stop());
|
|
121
|
+
// const protocol = createProtocolFactory(model.topic, this.peerId, [presence]);
|
|
124
122
|
|
|
125
123
|
await peer.networkManager.joinSwarm({
|
|
126
124
|
peerId: this.peerId, // TODO(burdon): `this`?
|
|
127
125
|
topic: model.topic,
|
|
128
|
-
protocolProvider:
|
|
129
|
-
topology: new FullyConnectedTopology()
|
|
130
|
-
presence
|
|
126
|
+
protocolProvider: todo(),
|
|
127
|
+
topology: new FullyConnectedTopology()
|
|
128
|
+
// presence
|
|
131
129
|
});
|
|
132
130
|
|
|
133
|
-
peer.presence = presence;
|
|
131
|
+
// peer.presence = presence;
|
|
134
132
|
|
|
135
133
|
await assertState(model, real);
|
|
136
134
|
}
|
package/src/tests/utils.ts
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { expect } from 'chai';
|
|
6
|
-
|
|
7
|
-
import { latch, Trigger } from '@dxos/async';
|
|
8
5
|
import { PublicKey } from '@dxos/keys';
|
|
9
6
|
import { afterTest } from '@dxos/test';
|
|
10
7
|
import { Provider } from '@dxos/util';
|
|
@@ -30,15 +27,11 @@ export const openAndCloseAfterTest = async (peers: TestPeer[]) => {
|
|
|
30
27
|
* Join and cleanly leave swarm.
|
|
31
28
|
*/
|
|
32
29
|
export const joinSwarm = async (peers: TestPeer[], topic: PublicKey, topology?: Provider<Topology>) => {
|
|
33
|
-
const
|
|
34
|
-
const swarms = peers.map((peer) => {
|
|
35
|
-
const swarm = peer.createSwarm(topic);
|
|
36
|
-
swarm.plugin.once('connect', connect);
|
|
37
|
-
return swarm;
|
|
38
|
-
});
|
|
39
|
-
|
|
30
|
+
const swarms = peers.map((peer) => peer.createSwarm(topic));
|
|
40
31
|
await Promise.all(swarms.map((swarm) => swarm.join(topology?.())));
|
|
41
|
-
await
|
|
32
|
+
await Promise.all(
|
|
33
|
+
swarms.map((swarm) => swarm.protocol.connected.waitForCondition(() => swarm.protocol.connections.size >= 0))
|
|
34
|
+
);
|
|
42
35
|
return swarms;
|
|
43
36
|
};
|
|
44
37
|
|
|
@@ -46,15 +39,11 @@ export const joinSwarm = async (peers: TestPeer[], topic: PublicKey, topology?:
|
|
|
46
39
|
* Cleanly leave swarm.
|
|
47
40
|
*/
|
|
48
41
|
export const leaveSwarm = async (peers: TestPeer[], topic: PublicKey) => {
|
|
49
|
-
const
|
|
50
|
-
const swarms = peers.map((peer) => {
|
|
51
|
-
const swarm = peer.getSwarm(topic);
|
|
52
|
-
swarm.plugin.once('disconnect', disconnect);
|
|
53
|
-
return swarm;
|
|
54
|
-
});
|
|
55
|
-
|
|
42
|
+
const swarms = peers.map((peer) => peer.getSwarm(topic));
|
|
56
43
|
await Promise.all(swarms.map((swarm) => swarm.leave()));
|
|
57
|
-
await
|
|
44
|
+
await Promise.all(
|
|
45
|
+
swarms.map((swarm) => swarm.protocol.connected.waitForCondition(() => swarm.protocol.connections.size === 0))
|
|
46
|
+
);
|
|
58
47
|
return swarms;
|
|
59
48
|
};
|
|
60
49
|
|
|
@@ -64,22 +53,6 @@ export const leaveSwarm = async (peers: TestPeer[], topic: PublicKey) => {
|
|
|
64
53
|
// TODO(burdon): Based on plugin instance.
|
|
65
54
|
// TODO(burdon): Configure to send more messages.
|
|
66
55
|
export const exchangeMessages = async (swarm1: TestSwarmConnection, swarm2: TestSwarmConnection) => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
swarm2.plugin.on('receive', (peer, message) => peer2Received.wake(message));
|
|
70
|
-
|
|
71
|
-
// TODO(burdon): Message encoding?
|
|
72
|
-
await swarm1.plugin.send(swarm2.peer.peerId.asBuffer(), JSON.stringify({ message: 'ping' }));
|
|
73
|
-
const { message } = JSON.parse(await peer2Received.wait());
|
|
74
|
-
expect(message).to.eq('ping');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
{
|
|
78
|
-
const peer1Received = new Trigger<any>();
|
|
79
|
-
swarm1.plugin.on('receive', (peer, message) => peer1Received.wake(message));
|
|
80
|
-
|
|
81
|
-
await swarm2.plugin.send(swarm1.peer.peerId.asBuffer(), JSON.stringify({ message: 'pong' }));
|
|
82
|
-
const { message } = JSON.parse(await peer1Received.wait());
|
|
83
|
-
expect(message).to.eq('pong');
|
|
84
|
-
}
|
|
56
|
+
await swarm1.protocol.testConnection(swarm2.peer.peerId);
|
|
57
|
+
await swarm2.protocol.testConnection(swarm1.peer.peerId);
|
|
85
58
|
};
|
|
@@ -2,16 +2,11 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import waitForExpect from 'wait-for-expect';
|
|
7
|
-
|
|
8
|
-
import { discoveryKey } from '@dxos/crypto';
|
|
5
|
+
import { TestStream } from '@dxos/async';
|
|
9
6
|
import { PublicKey } from '@dxos/keys';
|
|
10
|
-
import {
|
|
11
|
-
import { describe, test, afterTest } from '@dxos/test';
|
|
7
|
+
import { afterTest, describe, test } from '@dxos/test';
|
|
12
8
|
import { range } from '@dxos/util';
|
|
13
9
|
|
|
14
|
-
import { TestProtocolPlugin, testProtocolProvider } from '../testing';
|
|
15
10
|
import { MemoryTransport } from './memory-transport';
|
|
16
11
|
|
|
17
12
|
// TODO(burdon): Flaky test.
|
|
@@ -24,10 +19,9 @@ const createPair = () => {
|
|
|
24
19
|
const peer1Id = PublicKey.random();
|
|
25
20
|
const peer2Id = PublicKey.random();
|
|
26
21
|
|
|
27
|
-
const
|
|
28
|
-
const protocolProvider1 = testProtocolProvider(topic.asBuffer(), peer1Id, plugin1);
|
|
22
|
+
const stream1 = new TestStream();
|
|
29
23
|
const connection1 = new MemoryTransport({
|
|
30
|
-
stream:
|
|
24
|
+
stream: stream1,
|
|
31
25
|
sendSignal: async (signal) => {
|
|
32
26
|
await connection2.signal(signal);
|
|
33
27
|
},
|
|
@@ -37,10 +31,9 @@ const createPair = () => {
|
|
|
37
31
|
afterTest(() => connection1.destroy());
|
|
38
32
|
afterTest(() => connection1.errors.assertNoUnhandledErrors());
|
|
39
33
|
|
|
40
|
-
const
|
|
41
|
-
const protocolProvider2 = testProtocolProvider(topic.asBuffer(), peer2Id, plugin2);
|
|
34
|
+
const stream2 = new TestStream();
|
|
42
35
|
const connection2 = new MemoryTransport({
|
|
43
|
-
stream:
|
|
36
|
+
stream: stream2,
|
|
44
37
|
sendSignal: async (signal) => {
|
|
45
38
|
await connection1.signal(signal);
|
|
46
39
|
},
|
|
@@ -53,8 +46,8 @@ const createPair = () => {
|
|
|
53
46
|
return {
|
|
54
47
|
connection1,
|
|
55
48
|
connection2,
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
stream1,
|
|
50
|
+
stream2,
|
|
58
51
|
peer1Id,
|
|
59
52
|
peer2Id,
|
|
60
53
|
topic
|
|
@@ -63,47 +56,15 @@ const createPair = () => {
|
|
|
63
56
|
|
|
64
57
|
describe('MemoryTransport', () => {
|
|
65
58
|
test('establish connection and send data through with protocol', async () => {
|
|
66
|
-
const {
|
|
67
|
-
|
|
68
|
-
const received: any[] = [];
|
|
69
|
-
const mockReceive = (p: Protocol, s: string) => {
|
|
70
|
-
received.push(p, s);
|
|
71
|
-
return undefined;
|
|
72
|
-
};
|
|
73
|
-
plugin1.on('receive', mockReceive);
|
|
74
|
-
|
|
75
|
-
plugin2.on('connect', async (protocol) => {
|
|
76
|
-
await plugin2.send(peer1Id.asBuffer(), '{"message": "Hello"}');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
await waitForExpect(() => {
|
|
80
|
-
expect(received.length).toBe(2);
|
|
81
|
-
expect(received[0]).toBeInstanceOf(Protocol);
|
|
82
|
-
expect(received[1]).toBe('{"message": "Hello"}');
|
|
83
|
-
});
|
|
59
|
+
const { stream1, stream2 } = createPair();
|
|
60
|
+
await TestStream.assertConnectivity(stream1, stream2);
|
|
84
61
|
});
|
|
85
62
|
|
|
86
|
-
test
|
|
63
|
+
test('10 pairs of peers connecting at the same time', async () => {
|
|
87
64
|
await Promise.all(
|
|
88
65
|
range(10).map(async () => {
|
|
89
|
-
const {
|
|
90
|
-
|
|
91
|
-
const received: any[] = [];
|
|
92
|
-
const mockReceive = (p: Protocol, s: string) => {
|
|
93
|
-
received.push(p, s);
|
|
94
|
-
return undefined;
|
|
95
|
-
};
|
|
96
|
-
plugin1.on('receive', mockReceive);
|
|
97
|
-
|
|
98
|
-
plugin2.on('connect', async (protocol) => {
|
|
99
|
-
await plugin2.send(peer1Id.asBuffer(), '{"message": "Hello"}');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
await waitForExpect(() => {
|
|
103
|
-
expect(received.length).toBe(2);
|
|
104
|
-
expect(received[0]).toBeInstanceOf(Protocol);
|
|
105
|
-
expect(received[1]).toBe('{"message": "Hello"}');
|
|
106
|
-
});
|
|
66
|
+
const { stream1, stream2 } = createPair();
|
|
67
|
+
await TestStream.assertConnectivity(stream1, stream2);
|
|
107
68
|
})
|
|
108
69
|
);
|
|
109
70
|
});
|