p2p/net/swarm: extensive dial tests
Juan Batiz-Benet committed
Jan 13, 2015 at 08:15 UTC
baf254123786b7b91a1f5aa65f460bcbaf88bdd0
2 files changed
+427
-43
p2p/net/swarm/dial_test.go
new
+427
@@ -0,0 +1,427 @@
1
+package swarm
2
+
3
+import (
4
+ "net"
5
+ "sync"
6
+ "testing"
7
+ "time"
8
+
9
+ addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
10
+ peer "github.com/jbenet/go-ipfs/p2p/peer"
11
+ testutil "github.com/jbenet/go-ipfs/util/testutil"
12
+
13
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
14
+ ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
15
+ manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
16
+)
17
+
18
+func acceptAndHang(l net.Listener) {
19
+ conns := make([]net.Conn, 0, 10)
20
+ for {
21
+ c, err := l.Accept()
22
+ if err != nil {
23
+ break
24
+ }
25
+ if c != nil {
26
+ conns = append(conns, c)
27
+ }
28
+ }
29
+ for _, c := range conns {
30
+ c.Close()
31
+ }
32
+}
33
+
34
+func TestSimultDials(t *testing.T) {
35
+ // t.Skip("skipping for another test")
36
+ t.Parallel()
37
+
38
+ ctx := context.Background()
39
+ swarms := makeSwarms(ctx, t, 2)
40
+
41
+ // connect everyone
42
+ {
43
+ var wg sync.WaitGroup
44
+ connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
45
+ // copy for other peer
46
+ log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr)
47
+ s.peers.AddAddress(dst, addr)
48
+ if _, err := s.Dial(ctx, dst); err != nil {
49
+ t.Fatal("error swarm dialing to peer", err)
50
+ }
51
+ wg.Done()
52
+ }
53
+
54
+ ifaceAddrs0, err := swarms[0].InterfaceListenAddresses()
55
+ if err != nil {
56
+ t.Fatal(err)
57
+ }
58
+ ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
59
+ if err != nil {
60
+ t.Fatal(err)
61
+ }
62
+
63
+ log.Info("Connecting swarms simultaneously.")
64
+ for i := 0; i < 10; i++ { // connect 10x for each.
65
+ wg.Add(2)
66
+ go connect(swarms[0], swarms[1].local, ifaceAddrs1[0])
67
+ go connect(swarms[1], swarms[0].local, ifaceAddrs0[0])
68
+ }
69
+ wg.Wait()
70
+ }
71
+
72
+ // should still just have 1, at most 2 connections :)
73
+ c01l := len(swarms[0].ConnectionsToPeer(swarms[1].local))
74
+ if c01l > 2 {
75
+ t.Error("0->1 has", c01l)
76
+ }
77
+ c10l := len(swarms[1].ConnectionsToPeer(swarms[0].local))
78
+ if c10l > 2 {
79
+ t.Error("1->0 has", c10l)
80
+ }
81
+
82
+ for _, s := range swarms {
83
+ s.Close()
84
+ }
85
+}
86
+
87
+func newSilentPeer(t *testing.T) (peer.ID, ma.Multiaddr, net.Listener) {
88
+ dst := testutil.RandPeerIDFatal(t)
89
+ lst, err := net.Listen("tcp", ":0")
90
+ if err != nil {
91
+ t.Fatal(err)
92
+ }
93
+ addr, err := manet.FromNetAddr(lst.Addr())
94
+ if err != nil {
95
+ t.Fatal(err)
96
+ }
97
+ addrs := []ma.Multiaddr{addr}
98
+ addrs, err = addrutil.ResolveUnspecifiedAddresses(addrs, nil)
99
+ if err != nil {
100
+ t.Fatal(err)
101
+ }
102
+ t.Log("new silent peer:", dst, addrs[0])
103
+ return dst, addrs[0], lst
104
+}
105
+
106
+func TestDialWait(t *testing.T) {
107
+ // t.Skip("skipping for another test")
108
+ t.Parallel()
109
+
110
+ ctx := context.Background()
111
+ swarms := makeSwarms(ctx, t, 1)
112
+ s1 := swarms[0]
113
+ defer s1.Close()
114
+
115
+ s1.dialT = time.Millisecond * 300 // lower timeout for tests.
116
+
117
+ // dial to a non-existent peer.
118
+ s2p, s2addr, s2l := newSilentPeer(t)
119
+ go acceptAndHang(s2l)
120
+ defer s2l.Close()
121
+ s1.peers.AddAddress(s2p, s2addr)
122
+
123
+ before := time.Now()
124
+ if c, err := s1.Dial(ctx, s2p); err == nil {
125
+ defer c.Close()
126
+ t.Fatal("error swarm dialing to unknown peer worked...", err)
127
+ } else {
128
+ t.Log("correctly got error:", err)
129
+ }
130
+ duration := time.Now().Sub(before)
131
+
132
+ dt := s1.dialT
133
+ if duration < dt*dialAttempts {
134
+ t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts)
135
+ }
136
+ if duration > 2*dt*dialAttempts {
137
+ t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts)
138
+ }
139
+
140
+ if !s1.backf.Backoff(s2p) {
141
+ t.Error("s2 should now be on backoff")
142
+ }
143
+}
144
+
145
+func TestDialBackoff(t *testing.T) {
146
+ // t.Skip("skipping for another test")
147
+ t.Parallel()
148
+
149
+ ctx := context.Background()
150
+ swarms := makeSwarms(ctx, t, 2)
151
+ s1 := swarms[0]
152
+ s2 := swarms[1]
153
+ defer s1.Close()
154
+ defer s2.Close()
155
+
156
+ s1.dialT = time.Millisecond * 500 // lower timeout for tests.
157
+ s2.dialT = time.Millisecond * 500 // lower timeout for tests.
158
+
159
+ s2addrs, err := s2.InterfaceListenAddresses()
160
+ if err != nil {
161
+ t.Fatal(err)
162
+ }
163
+ s1.peers.AddAddresses(s2.local, s2addrs)
164
+
165
+ // dial to a non-existent peer.
166
+ s3p, s3addr, s3l := newSilentPeer(t)
167
+ go acceptAndHang(s3l)
168
+ defer s3l.Close()
169
+ s1.peers.AddAddress(s3p, s3addr)
170
+
171
+ // in this test we will:
172
+ // 1) dial 10x to each node.
173
+ // 2) all dials should hang
174
+ // 3) s1->s2 should succeed.
175
+ // 4) s1->s3 should not (and should place s3 on backoff)
176
+ // 5) disconnect entirely
177
+ // 6) dial 10x to each node again
178
+ // 7) s3 dials should all return immediately (except 1)
179
+ // 8) s2 dials should all hang, and succeed
180
+ // 9) last s3 dial ends, unsuccessful
181
+
182
+ dialOnlineNode := func(dst peer.ID, times int) <-chan bool {
183
+ ch := make(chan bool)
184
+ for i := 0; i < times; i++ {
185
+ go func() {
186
+ if _, err := s1.Dial(ctx, dst); err != nil {
187
+ t.Error("error dialing", dst, err)
188
+ ch <- false
189
+ } else {
190
+ ch <- true
191
+ }
192
+ }()
193
+ }
194
+ return ch
195
+ }
196
+
197
+ dialOfflineNode := func(dst peer.ID, times int) <-chan bool {
198
+ ch := make(chan bool)
199
+ for i := 0; i < times; i++ {
200
+ go func() {
201
+ if c, err := s1.Dial(ctx, dst); err != nil {
202
+ ch <- false
203
+ } else {
204
+ t.Error("succeeded in dialing", dst)
205
+ ch <- true
206
+ c.Close()
207
+ }
208
+ }()
209
+ }
210
+ return ch
211
+ }
212
+
213
+ {
214
+ // 1) dial 10x to each node.
215
+ N := 10
216
+ s2done := dialOnlineNode(s2.local, N)
217
+ s3done := dialOfflineNode(s3p, N)
218
+
219
+ // when all dials should be done by:
220
+ dialTimeout1x := time.After(s1.dialT)
221
+ dialTimeout1Ax := time.After(s1.dialT * dialAttempts)
222
+ dialTimeout10Ax := time.After(s1.dialT * dialAttempts * 10)
223
+
224
+ // 2) all dials should hang
225
+ select {
226
+ case <-s2done:
227
+ t.Error("s2 should not happen immediately")
228
+ case <-s3done:
229
+ t.Error("s3 should not happen yet")
230
+ case <-time.After(time.Millisecond):
231
+ // s2 may finish very quickly, so let's get out.
232
+ }
233
+
234
+ // 3) s1->s2 should succeed.
235
+ for i := 0; i < N; i++ {
236
+ select {
237
+ case r := <-s2done:
238
+ if !r {
239
+ t.Error("s2 should not fail")
240
+ }
241
+ case <-s3done:
242
+ t.Error("s3 should not happen yet")
243
+ case <-dialTimeout1x:
244
+ t.Error("s2 took too long")
245
+ }
246
+ }
247
+
248
+ select {
249
+ case <-s2done:
250
+ t.Error("s2 should have no more")
251
+ case <-s3done:
252
+ t.Error("s3 should not happen yet")
253
+ case <-dialTimeout1x: // let it pass
254
+ }
255
+
256
+ // 4) s1->s3 should not (and should place s3 on backoff)
257
+ // N-1 should finish before dialTimeout1Ax
258
+ for i := 0; i < N; i++ {
259
+ select {
260
+ case <-s2done:
261
+ t.Error("s2 should have no more")
262
+ case r := <-s3done:
263
+ if r {
264
+ t.Error("s3 should not succeed")
265
+ }
266
+ case <-dialTimeout1Ax:
267
+ if i < (N - 1) {
268
+ t.Fatal("s3 took too long")
269
+ }
270
+ t.Log("dialTimeout1Ax hit for last peer")
271
+ case <-dialTimeout10Ax:
272
+ t.Fatal("s3 took too long")
273
+ }
274
+ }
275
+
276
+ // check backoff state
277
+ if s1.backf.Backoff(s2.local) {
278
+ t.Error("s2 should not be on backoff")
279
+ }
280
+ if !s1.backf.Backoff(s3p) {
281
+ t.Error("s3 should be on backoff")
282
+ }
283
+
284
+ // 5) disconnect entirely
285
+
286
+ for _, c := range s1.Connections() {
287
+ c.Close()
288
+ }
289
+ for i := 0; i < 100 && len(s1.Connections()) > 0; i++ {
290
+ <-time.After(time.Millisecond)
291
+ }
292
+ if len(s1.Connections()) > 0 {
293
+ t.Fatal("s1 conns must exit")
294
+ }
295
+ }
296
+
297
+ {
298
+ // 6) dial 10x to each node again
299
+ N := 10
300
+ s2done := dialOnlineNode(s2.local, N)
301
+ s3done := dialOfflineNode(s3p, N)
302
+
303
+ // when all dials should be done by:
304
+ dialTimeout1x := time.After(s1.dialT)
305
+ dialTimeout1Ax := time.After(s1.dialT * dialAttempts)
306
+ dialTimeout10Ax := time.After(s1.dialT * dialAttempts * 10)
307
+
308
+ // 7) s3 dials should all return immediately (except 1)
309
+ for i := 0; i < N-1; i++ {
310
+ select {
311
+ case <-s2done:
312
+ t.Error("s2 should not succeed yet")
313
+ case r := <-s3done:
314
+ if r {
315
+ t.Error("s3 should not succeed")
316
+ }
317
+ case <-dialTimeout1x:
318
+ t.Fatal("s3 took too long")
319
+ }
320
+ }
321
+
322
+ // 8) s2 dials should all hang, and succeed
323
+ for i := 0; i < N; i++ {
324
+ select {
325
+ case r := <-s2done:
326
+ if !r {
327
+ t.Error("s2 should succeed")
328
+ }
329
+ // case <-s3done:
330
+ case <-dialTimeout1Ax:
331
+ t.Fatal("s3 took too long")
332
+ }
333
+ }
334
+
335
+ // 9) the last s3 should return, failed.
336
+ select {
337
+ case <-s2done:
338
+ t.Error("s2 should have no more")
339
+ case r := <-s3done:
340
+ if r {
341
+ t.Error("s3 should not succeed")
342
+ }
343
+ case <-dialTimeout10Ax:
344
+ t.Fatal("s3 took too long")
345
+ }
346
+
347
+ // check backoff state (the same)
348
+ if s1.backf.Backoff(s2.local) {
349
+ t.Error("s2 should not be on backoff")
350
+ }
351
+ if !s1.backf.Backoff(s3p) {
352
+ t.Error("s3 should be on backoff")
353
+ }
354
+
355
+ }
356
+}
357
+
358
+func TestDialBackoffClears(t *testing.T) {
359
+ // t.Skip("skipping for another test")
360
+ t.Parallel()
361
+
362
+ ctx := context.Background()
363
+ swarms := makeSwarms(ctx, t, 2)
364
+ s1 := swarms[0]
365
+ s2 := swarms[1]
366
+ defer s1.Close()
367
+ defer s2.Close()
368
+ s1.dialT = time.Millisecond * 300 // lower timeout for tests.
369
+ s2.dialT = time.Millisecond * 300 // lower timeout for tests.
370
+
371
+ // use another address first, that accept and hang on conns
372
+ _, s2bad, s2l := newSilentPeer(t)
373
+ go acceptAndHang(s2l)
374
+ defer s2l.Close()
375
+
376
+ // phase 1 -- dial to non-operational addresses
377
+ s1.peers.AddAddress(s2.local, s2bad)
378
+
379
+ before := time.Now()
380
+ if c, err := s1.Dial(ctx, s2.local); err == nil {
381
+ t.Fatal("dialing to broken addr worked...", err)
382
+ defer c.Close()
383
+ } else {
384
+ t.Log("correctly got error:", err)
385
+ }
386
+ duration := time.Now().Sub(before)
387
+
388
+ dt := s1.dialT
389
+ if duration < dt*dialAttempts {
390
+ t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts)
391
+ }
392
+ if duration > 2*dt*dialAttempts {
393
+ t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts)
394
+ }
395
+
396
+ if !s1.backf.Backoff(s2.local) {
397
+ t.Error("s2 should now be on backoff")
398
+ } else {
399
+ t.Log("correctly added to backoff")
400
+ }
401
+
402
+ // phase 2 -- add the working address. dial should succeed.
403
+ ifaceAddrs1, err := swarms[1].InterfaceListenAddresses()
404
+ if err != nil {
405
+ t.Fatal(err)
406
+ }
407
+ s1.peers.AddAddresses(s2.local, ifaceAddrs1)
408
+
409
+ before = time.Now()
410
+ if c, err := s1.Dial(ctx, s2.local); err != nil {
411
+ t.Fatal(err)
412
+ } else {
413
+ c.Close()
414
+ t.Log("correctly connected")
415
+ }
416
+ duration = time.Now().Sub(before)
417
+
418
+ if duration >= dt {
419
+ // t.Error("took too long", duration, dt)
420
+ }
421
+
422
+ if s1.backf.Backoff(s2.local) {
423
+ t.Error("s2 should no longer be on backoff")
424
+ } else {
425
+ t.Log("correctly cleared backoff")
426
+ }
427
+}
p2p/net/swarm/simul_test.go
-43
@@ -11,49 +11,6 @@ import (
11
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12
)
13
14
-func TestSimultDials(t *testing.T) {
15
- // t.Skip("skipping for another test")
16
-
17
- ctx := context.Background()
18
- swarms := makeSwarms(ctx, t, 2)
19
-
20
- // connect everyone
21
- {
22
- var wg sync.WaitGroup
23
- connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
24
- // copy for other peer
25
- log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr)
26
- s.peers.AddAddress(dst, addr)
27
- if _, err := s.Dial(ctx, dst); err != nil {
28
- t.Fatal("error swarm dialing to peer", err)
29
- }
30
- wg.Done()
31
- }
32
-
33
- log.Info("Connecting swarms simultaneously.")
34
- for i := 0; i < 10; i++ { // connect 10x for each.
35
- wg.Add(2)
36
- go connect(swarms[0], swarms[1].local, swarms[1].ListenAddresses()[0])
37
- go connect(swarms[1], swarms[0].local, swarms[0].ListenAddresses()[0])
38
- }
39
- wg.Wait()
40
- }
41
-
42
- // should still just have 1, at most 2 connections :)
43
- c01l := len(swarms[0].ConnectionsToPeer(swarms[1].local))
44
- if c01l > 2 {
45
- t.Error("0->1 has", c01l)
46
- }
47
- c10l := len(swarms[1].ConnectionsToPeer(swarms[0].local))
48
- if c10l > 2 {
49
- t.Error("1->0 has", c10l)
50
- }
51
-
52
- for _, s := range swarms {
53
- s.Close()
54
- }
55
-}
56
-
14
func TestSimultOpen(t *testing.T) {
15
// t.Skip("skipping for another test")
16