lib_test.go 8.51 KB
Newer Older
1
package lib
2
3
4

import (
	"bytes"
5
	"fmt"
6
	"io/ioutil"
7
	"net"
8
	"net/http"
9
	"testing"
10

11
	"github.com/pion/webrtc"
12
	. "github.com/smartystreets/goconvey/convey"
13
14
15
16
)

type MockDataChannel struct {
	destination bytes.Buffer
17
	done        chan bool
18
19
}

20
func (m *MockDataChannel) Send(data []byte) error {
21
	m.destination.Write(data)
22
	m.done <- true
23
	return nil
24
25
}

26
func (*MockDataChannel) Close() error { return nil }
27

28
29
30
31
32
33
type MockResponse struct{}

func (m *MockResponse) Read(p []byte) (int, error) {
	p = []byte(`{"type":"answer","sdp":"fake"}`)
	return 0, nil
}
34
func (m *MockResponse) Close() error { return nil }
35

36
37
38
39
type MockTransport struct {
	statusOverride int
	body           []byte
}
40
41
42

// Just returns a response with fake SDP answer.
func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
43
	s := ioutil.NopCloser(bytes.NewReader(m.body))
44
	r := &http.Response{
45
		StatusCode: m.statusOverride,
46
47
48
49
50
		Body:       s,
	}
	return r, nil
}

51
52
type FakeDialer struct{}

53
func (w FakeDialer) Catch() (Snowflake, error) {
54
	fmt.Println("Caught a dummy snowflake.")
55
	return &WebRTCPeer{}, nil
56
57
}

58
59
60
61
62
63
64
65
66
type FakeSocksConn struct {
	net.Conn
	rejected bool
}

func (f FakeSocksConn) Reject() error {
	f.rejected = true
	return nil
}
67
func (f FakeSocksConn) Grant(addr *net.TCPAddr) error { return nil }
68

69
type FakePeers struct{ toRelease *WebRTCPeer }
70

71
func (f FakePeers) Collect() (Snowflake, error) { return &WebRTCPeer{}, nil }
72
73
func (f FakePeers) Pop() Snowflake              { return nil }
func (f FakePeers) Melted() <-chan struct{}     { return nil }
74

75
func TestSnowflakeClient(t *testing.T) {
76

77
78
79
80
81
82
83
84
85
86
	Convey("Peers", t, func() {
		Convey("Can construct", func() {
			p := NewPeers(1)
			So(p.capacity, ShouldEqual, 1)
			So(p.snowflakeChan, ShouldNotBeNil)
			So(cap(p.snowflakeChan), ShouldEqual, 1)
		})

		Convey("Collecting a Snowflake requires a Tongue.", func() {
			p := NewPeers(1)
87
			_, err := p.Collect()
88
89
90
91
			So(err, ShouldNotBeNil)
			So(p.Count(), ShouldEqual, 0)
			// Set the dialer so that collection is possible.
			p.Tongue = FakeDialer{}
92
			_, err = p.Collect()
93
94
			So(err, ShouldBeNil)
			So(p.Count(), ShouldEqual, 1)
95
			// S
96
			_, err = p.Collect()
97
98
99
		})

		Convey("Collection continues until capacity.", func() {
100
			c := 5
101
			p := NewPeers(c)
102
103
104
105
			p.Tongue = FakeDialer{}
			// Fill up to capacity.
			for i := 0; i < c; i++ {
				fmt.Println("Adding snowflake ", i)
106
				_, err := p.Collect()
107
108
109
110
111
				So(err, ShouldBeNil)
				So(p.Count(), ShouldEqual, i+1)
			}
			// But adding another gives an error.
			So(p.Count(), ShouldEqual, c)
112
			_, err := p.Collect()
113
114
115
116
117
118
119
120
121
			So(err, ShouldNotBeNil)
			So(p.Count(), ShouldEqual, c)

			// But popping and closing allows it to continue.
			s := p.Pop()
			s.Close()
			So(s, ShouldNotBeNil)
			So(p.Count(), ShouldEqual, c-1)

122
			_, err = p.Collect()
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
			So(err, ShouldBeNil)
			So(p.Count(), ShouldEqual, c)
		})

		Convey("Count correctly purges peers marked for deletion.", func() {
			p := NewPeers(4)
			p.Tongue = FakeDialer{}
			p.Collect()
			p.Collect()
			p.Collect()
			p.Collect()
			So(p.Count(), ShouldEqual, 4)
			s := p.Pop()
			s.Close()
			So(p.Count(), ShouldEqual, 3)
			s = p.Pop()
			s.Close()
			So(p.Count(), ShouldEqual, 2)
		})

143
144
145
146
		Convey("End Closes all peers.", func() {
			cnt := 5
			p := NewPeers(cnt)
			for i := 0; i < cnt; i++ {
147
				p.activePeers.PushBack(&WebRTCPeer{})
148
149
150
			}
			So(p.Count(), ShouldEqual, cnt)
			p.End()
151
			<-p.Melted()
152
153
154
			So(p.Count(), ShouldEqual, 0)
		})

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
		Convey("Pop skips over closed peers.", func() {
			p := NewPeers(4)
			p.Tongue = FakeDialer{}
			wc1, _ := p.Collect()
			wc2, _ := p.Collect()
			wc3, _ := p.Collect()
			So(wc1, ShouldNotBeNil)
			So(wc2, ShouldNotBeNil)
			So(wc3, ShouldNotBeNil)
			wc1.Close()
			r := p.Pop()
			So(p.Count(), ShouldEqual, 2)
			So(r, ShouldEqual, wc2)
			wc4, _ := p.Collect()
			wc2.Close()
			wc3.Close()
			r = p.Pop()
			So(r, ShouldEqual, wc4)
		})

175
176
	})

177
178
179
180
	Convey("Snowflake", t, func() {

		SkipConvey("Handler Grants correctly", func() {
			socks := &FakeSocksConn{}
181
			snowflakes := &FakePeers{}
182
183
184

			So(socks.rejected, ShouldEqual, false)
			snowflakes.toRelease = nil
185
			Handler(socks, snowflakes)
186
			So(socks.rejected, ShouldEqual, true)
187
		})
188
189

		Convey("WebRTC Connection", func() {
190
			c := NewWebRTCPeer(nil, nil)
191
192
			So(c.buffer.Bytes(), ShouldEqual, nil)

193
			Convey("Can construct a WebRTCConn", func() {
194
				s := NewWebRTCPeer(nil, nil)
195
				So(s, ShouldNotBeNil)
196
197
				So(s.offerChannel, ShouldNotBeNil)
				So(s.answerChannel, ShouldNotBeNil)
198
199
200
				s.Close()
			})

201
202
			Convey("Write buffers when datachannel is nil", func() {
				c.Write([]byte("test"))
203
				c.transport = nil
204
205
206
				So(c.buffer.Bytes(), ShouldResemble, []byte("test"))
			})

207
			Convey("Write sends to datachannel when not nil", func() {
208
				mock := new(MockDataChannel)
209
				c.transport = mock
210
211
				mock.done = make(chan bool, 1)
				c.Write([]byte("test"))
212
				<-mock.done
213
214
215
				So(c.buffer.Bytes(), ShouldEqual, nil)
				So(mock.destination.Bytes(), ShouldResemble, []byte("test"))
			})
216

217
218
219
220
			Convey("Exchange SDP sets remote description", func() {
				c.offerChannel = make(chan *webrtc.SessionDescription, 1)
				c.answerChannel = make(chan *webrtc.SessionDescription, 1)

221
				c.config = &webrtc.Configuration{}
222
				c.preparePeerConnection()
Serene Han's avatar
Serene Han committed
223

224
				c.offerChannel <- nil
225
				answer := deserializeSessionDescription(
226
227
228
					`{"type":"answer","sdp":""}`)
				c.answerChannel <- answer
				c.exchangeSDP()
Serene Han's avatar
Serene Han committed
229
230
			})

231
			SkipConvey("Exchange SDP fails on nil answer", func() {
232
				c.reset = make(chan struct{})
233
234
235
				c.offerChannel = make(chan *webrtc.SessionDescription, 1)
				c.answerChannel = make(chan *webrtc.SessionDescription, 1)
				c.offerChannel <- nil
236
				c.answerChannel <- nil
237
				c.exchangeSDP()
238
239
240
				<-c.reset
			})

241
		})
242
243
	})

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
	Convey("Dialers", t, func() {
		Convey("Can construct WebRTCDialer.", func() {
			broker := &BrokerChannel{Host: "test"}
			d := NewWebRTCDialer(broker, nil)
			So(d, ShouldNotBeNil)
			So(d.BrokerChannel, ShouldNotBeNil)
			So(d.BrokerChannel.Host, ShouldEqual, "test")
		})
		Convey("WebRTCDialer cannot Catch a snowflake with nil broker.", func() {
			d := NewWebRTCDialer(nil, nil)
			conn, err := d.Catch()
			So(conn, ShouldBeNil)
			So(err, ShouldNotBeNil)
		})
		SkipConvey("WebRTCDialer can Catch a snowflake.", func() {
			broker := &BrokerChannel{Host: "test"}
			d := NewWebRTCDialer(broker, nil)
			conn, err := d.Catch()
			So(conn, ShouldBeNil)
			So(err, ShouldNotBeNil)
		})
	})

267
	Convey("Rendezvous", t, func() {
268
269
270
271
		transport := &MockTransport{
			http.StatusOK,
			[]byte(`{"type":"answer","sdp":"fake"}`),
		}
272
		fakeOffer := deserializeSessionDescription(`{"type":"offer","sdp":"test"}`)
273

274
		Convey("Construct BrokerChannel with no front domain", func() {
275
			b := NewBrokerChannel("test.broker", "", transport)
276
277
278
279
280
			So(b.url, ShouldNotBeNil)
			So(b.url.Path, ShouldResemble, "test.broker")
			So(b.transport, ShouldNotBeNil)
		})

281
		Convey("Construct BrokerChannel *with* front domain", func() {
282
			b := NewBrokerChannel("test.broker", "front", transport)
283
284
285
286
287
288
			So(b.url, ShouldNotBeNil)
			So(b.url.Path, ShouldResemble, "test.broker")
			So(b.url.Host, ShouldResemble, "front")
			So(b.transport, ShouldNotBeNil)
		})

289
		Convey("BrokerChannel.Negotiate responds with answer", func() {
290
291
			b := NewBrokerChannel("test.broker", "", transport)
			answer, err := b.Negotiate(fakeOffer)
292
293
			So(err, ShouldBeNil)
			So(answer, ShouldNotBeNil)
294
			So(answer.SDP, ShouldResemble, "fake")
295
		})
296

297
		Convey("BrokerChannel.Negotiate fails with 503", func() {
298
			b := NewBrokerChannel("test.broker", "",
299
				&MockTransport{http.StatusServiceUnavailable, []byte("\n")})
300
301
302
303
304
305
			answer, err := b.Negotiate(fakeOffer)
			So(err, ShouldNotBeNil)
			So(answer, ShouldBeNil)
			So(err.Error(), ShouldResemble, BrokerError503)
		})

306
		Convey("BrokerChannel.Negotiate fails with 400", func() {
307
			b := NewBrokerChannel("test.broker", "",
308
				&MockTransport{http.StatusBadRequest, []byte("\n")})
309
310
311
312
313
314
			answer, err := b.Negotiate(fakeOffer)
			So(err, ShouldNotBeNil)
			So(answer, ShouldBeNil)
			So(err.Error(), ShouldResemble, BrokerError400)
		})

315
316
317
318
319
320
321
322
323
		Convey("BrokerChannel.Negotiate fails with large read", func() {
			b := NewBrokerChannel("test.broker", "",
				&MockTransport{http.StatusOK, make([]byte, 100001, 100001)})
			answer, err := b.Negotiate(fakeOffer)
			So(err, ShouldNotBeNil)
			So(answer, ShouldBeNil)
			So(err.Error(), ShouldResemble, "unexpected EOF")
		})

324
		Convey("BrokerChannel.Negotiate fails with unexpected error", func() {
325
			b := NewBrokerChannel("test.broker", "",
326
				&MockTransport{123, []byte("")})
327
328
329
330
331
			answer, err := b.Negotiate(fakeOffer)
			So(err, ShouldNotBeNil)
			So(answer, ShouldBeNil)
			So(err.Error(), ShouldResemble, BrokerErrorUnexpected)
		})
332
333
	})
}