swarm_test.go 7.69 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1
2
3
4
package swarm

import (
	"bytes"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5
	"fmt"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6
	"io"
7
	"net"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8
9
10
11
	"sync"
	"testing"
	"time"

12
13
14
	metrics "github.com/libp2p/go-libp2p/p2p/metrics"
	inet "github.com/libp2p/go-libp2p/p2p/net"
	testutil "github.com/libp2p/go-libp2p/testutil"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
15

16
	"context"
Jeromy's avatar
Jeromy committed
17
18
	peer "github.com/ipfs/go-libp2p-peer"
	pstore "github.com/ipfs/go-libp2p-peerstore"
Jeromy's avatar
Jeromy committed
19
	ma "github.com/jbenet/go-multiaddr"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20
21
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
22
func EchoStreamHandler(stream inet.Stream) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
23
24
25
26
	go func() {
		defer stream.Close()

		// pull out the ipfs conn
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27
		c := stream.Conn()
28
		log.Infof("%s ponging to %s", c.LocalPeer(), c.RemotePeer())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29
30
31
32
33
34

		buf := make([]byte, 4)

		for {
			if _, err := stream.Read(buf); err != nil {
				if err != io.EOF {
Jeromy's avatar
Jeromy committed
35
					log.Error("ping receive error:", err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36
37
38
39
40
				}
				return
			}

			if !bytes.Equal(buf, []byte("ping")) {
Jeromy's avatar
Jeromy committed
41
				log.Errorf("ping receive error: ping != %s %v", buf, buf)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42
43
44
45
				return
			}

			if _, err := stream.Write([]byte("pong")); err != nil {
Jeromy's avatar
Jeromy committed
46
				log.Error("pond send error:", err)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47
48
49
50
51
52
				return
			}
		}
	}()
}

Jeromy's avatar
Jeromy committed
53
54
55
func makeDialOnlySwarm(ctx context.Context, t *testing.T) *Swarm {
	id := testutil.RandIdentityOrFatal(t)

Jeromy's avatar
Jeromy committed
56
	peerstore := pstore.NewPeerstore()
Jeromy's avatar
Jeromy committed
57
58
59
60
61
62
63
64
65
66
67
68
69
	peerstore.AddPubKey(id.ID(), id.PublicKey())
	peerstore.AddPrivKey(id.ID(), id.PrivateKey())

	swarm, err := NewSwarm(ctx, nil, id.ID(), peerstore, metrics.NewBandwidthCounter())
	if err != nil {
		t.Fatal(err)
	}

	swarm.SetStreamHandler(EchoStreamHandler)

	return swarm
}

70
func makeSwarms(ctx context.Context, t *testing.T, num int) []*Swarm {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
71
72
73
74
75
	swarms := make([]*Swarm, 0, num)

	for i := 0; i < num; i++ {
		localnp := testutil.RandPeerNetParamsOrFatal(t)

Jeromy's avatar
Jeromy committed
76
		peerstore := pstore.NewPeerstore()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77
78
79
		peerstore.AddPubKey(localnp.ID, localnp.PubKey)
		peerstore.AddPrivKey(localnp.ID, localnp.PrivKey)

80
		addrs := []ma.Multiaddr{localnp.Addr}
Jeromy's avatar
Jeromy committed
81
		swarm, err := NewSwarm(ctx, addrs, localnp.ID, peerstore, metrics.NewBandwidthCounter())
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82
83
84
85
86
87
88
89
		if err != nil {
			t.Fatal(err)
		}

		swarm.SetStreamHandler(EchoStreamHandler)
		swarms = append(swarms, swarm)
	}

90
	return swarms
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91
92
}

93
func connectSwarms(t *testing.T, ctx context.Context, swarms []*Swarm) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
94
95
96
97

	var wg sync.WaitGroup
	connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) {
		// TODO: make a DialAddr func.
Jeromy's avatar
Jeromy committed
98
		s.peers.AddAddr(dst, addr, pstore.PermanentAddrTTL)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
99
100
101
102
103
104
105
		if _, err := s.Dial(ctx, dst); err != nil {
			t.Fatal("error swarm dialing to peer", err)
		}
		wg.Done()
	}

	log.Info("Connecting swarms simultaneously.")
106
107
108
	for _, s1 := range swarms {
		for _, s2 := range swarms {
			if s2.local != s1.local { // don't connect to self.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
109
				wg.Add(1)
110
				connect(s1, s2.LocalPeer(), s2.ListenAddresses()[0]) // try the first.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
			}
		}
	}
	wg.Wait()

	for _, s := range swarms {
		log.Infof("%s swarm routing table: %s", s.local, s.Peers())
	}
}

func SubtestSwarm(t *testing.T, SwarmNum int, MsgNum int) {
	// t.Skip("skipping for another test")

	ctx := context.Background()
125
	swarms := makeSwarms(ctx, t, SwarmNum)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
126
127

	// connect everyone
128
	connectSwarms(t, ctx, swarms)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
129
130
131
132
133
134
135
136
137

	// ping/pong
	for _, s1 := range swarms {
		log.Debugf("-------------------------------------------------------")
		log.Debugf("%s ping pong round", s1.local)
		log.Debugf("-------------------------------------------------------")

		_, cancel := context.WithCancel(ctx)
		got := map[peer.ID]int{}
138
		errChan := make(chan error, MsgNum*len(swarms))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
139
140
141
142
143
144
145
146
147
148
149
		streamChan := make(chan *Stream, MsgNum)

		// send out "ping" x MsgNum to every peer
		go func() {
			defer close(streamChan)

			var wg sync.WaitGroup
			send := func(p peer.ID) {
				defer wg.Done()

				// first, one stream per peer (nice)
150
				stream, err := s1.NewStreamWithPeer(ctx, p)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
151
				if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
152
					errChan <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
					return
				}

				// send out ping!
				for k := 0; k < MsgNum; k++ { // with k messages
					msg := "ping"
					log.Debugf("%s %s %s (%d)", s1.local, msg, p, k)
					if _, err := stream.Write([]byte(msg)); err != nil {
						errChan <- err
						continue
					}
				}

				// read it later
				streamChan <- stream
			}

170
171
			for _, s2 := range swarms {
				if s2.local == s1.local {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
172
173
174
175
					continue // dont send to self...
				}

				wg.Add(1)
176
				go send(s2.local)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
177
178
179
180
181
182
183
184
			}
			wg.Wait()
		}()

		// receive "pong" x MsgNum from every peer
		go func() {
			defer close(errChan)
			count := 0
185
			countShouldBe := MsgNum * (len(swarms) - 1)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
186
187
188
189
190
191
192
193
194
195
196
197
198
			for stream := range streamChan { // one per peer
				defer stream.Close()

				// get peer on the other side
				p := stream.Conn().RemotePeer()

				// receive pings
				msgCount := 0
				msg := make([]byte, 4)
				for k := 0; k < MsgNum; k++ { // with k messages

					// read from the stream
					if _, err := stream.Read(msg); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
199
						errChan <- err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
200
201
202
203
						continue
					}

					if string(msg) != "pong" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
204
						errChan <- fmt.Errorf("unexpected message: %s", msg)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
205
206
207
208
209
210
211
212
213
214
215
216
						continue
					}

					log.Debugf("%s %s %s (%d)", s1.local, msg, p, k)
					msgCount++
				}

				got[p] = msgCount
				count += msgCount
			}

			if count != countShouldBe {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
217
				errChan <- fmt.Errorf("count mismatch: %d != %d", count, countShouldBe)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
218
219
220
221
222
223
224
225
226
227
228
			}
		}()

		// check any errors (blocks till consumer is done)
		for err := range errChan {
			if err != nil {
				t.Error(err.Error())
			}
		}

		log.Debugf("%s got pongs", s1.local)
229
230
		if (len(swarms) - 1) != len(got) {
			t.Errorf("got (%d) less messages than sent (%d).", len(got), len(swarms))
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
		}

		for p, n := range got {
			if n != MsgNum {
				t.Error("peer did not get all msgs", p, n, "/", MsgNum)
			}
		}

		cancel()
		<-time.After(10 * time.Millisecond)
	}

	for _, s := range swarms {
		s.Close()
	}
}

func TestSwarm(t *testing.T) {
	// t.Skip("skipping for another test")
250
	t.Parallel()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
251
252
253
254
255

	// msgs := 1000
	msgs := 100
	swarms := 5
	SubtestSwarm(t, swarms, msgs)
Jeromy's avatar
Jeromy committed
256
257
258
259
260
261
262
263
264
}

func TestBasicSwarm(t *testing.T) {
	// t.Skip("skipping for another test")
	t.Parallel()

	msgs := 1
	swarms := 2
	SubtestSwarm(t, swarms, msgs)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
265
266
267
268
}

func TestConnHandler(t *testing.T) {
	// t.Skip("skipping for another test")
269
	t.Parallel()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
270
271

	ctx := context.Background()
272
	swarms := makeSwarms(ctx, t, 5)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
273
274
275
276
277
278

	gotconn := make(chan struct{}, 10)
	swarms[0].SetConnHandler(func(conn *Conn) {
		gotconn <- struct{}{}
	})

279
	connectSwarms(t, ctx, swarms)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296

	<-time.After(time.Millisecond)
	// should've gotten 5 by now.

	swarms[0].SetConnHandler(nil)

	expect := 4
	for i := 0; i < expect; i++ {
		select {
		case <-time.After(time.Second):
			t.Fatal("failed to get connections")
		case <-gotconn:
		}
	}

	select {
	case <-gotconn:
Jeromy's avatar
Jeromy committed
297
		t.Fatalf("should have connected to %d swarms, got an extra.", expect)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
298
299
300
	default:
	}
}
301
302
303
304
305
306

func TestAddrBlocking(t *testing.T) {
	ctx := context.Background()
	swarms := makeSwarms(ctx, t, 2)

	swarms[0].SetConnHandler(func(conn *Conn) {
Jeromy's avatar
Jeromy committed
307
		t.Errorf("no connections should happen! -- %s", conn)
308
309
310
311
312
313
314
315
316
	})

	_, block, err := net.ParseCIDR("127.0.0.1/8")
	if err != nil {
		t.Fatal(err)
	}

	swarms[1].Filters.AddDialFilter(block)

Jeromy's avatar
Jeromy committed
317
	swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], pstore.PermanentAddrTTL)
318
	_, err = swarms[1].Dial(ctx, swarms[0].LocalPeer())
319
320
321
322
	if err == nil {
		t.Fatal("dial should have failed")
	}

Jeromy's avatar
Jeromy committed
323
	swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], pstore.PermanentAddrTTL)
324
	_, err = swarms[0].Dial(ctx, swarms[1].LocalPeer())
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
	if err == nil {
		t.Fatal("dial should have failed")
	}
}

func TestFilterBounds(t *testing.T) {
	ctx := context.Background()
	swarms := makeSwarms(ctx, t, 2)

	conns := make(chan struct{}, 8)
	swarms[0].SetConnHandler(func(conn *Conn) {
		conns <- struct{}{}
	})

	// Address that we wont be dialing from
	_, block, err := net.ParseCIDR("192.0.0.1/8")
	if err != nil {
		t.Fatal(err)
	}

	// set filter on both sides, shouldnt matter
	swarms[1].Filters.AddDialFilter(block)
	swarms[0].Filters.AddDialFilter(block)

	connectSwarms(t, ctx, swarms)

	select {
	case <-time.After(time.Second):
		t.Fatal("should have gotten connection")
	case <-conns:
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
355
		t.Log("got connect")
356
357
	}
}