lib_test.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. package lib
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "net/http"
  8. "testing"
  9. "github.com/pion/webrtc"
  10. . "github.com/smartystreets/goconvey/convey"
  11. )
  12. type MockDataChannel struct {
  13. destination bytes.Buffer
  14. done chan bool
  15. }
  16. func (m *MockDataChannel) Send(data []byte) error {
  17. m.destination.Write(data)
  18. m.done <- true
  19. return nil
  20. }
  21. func (*MockDataChannel) Close() error { return nil }
  22. type MockResponse struct{}
  23. func (m *MockResponse) Read(p []byte) (int, error) {
  24. p = []byte(`{"type":"answer","sdp":"fake"}`)
  25. return 0, nil
  26. }
  27. func (m *MockResponse) Close() error { return nil }
  28. type MockTransport struct {
  29. statusOverride int
  30. body []byte
  31. }
  32. // Just returns a response with fake SDP answer.
  33. func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  34. s := ioutil.NopCloser(bytes.NewReader(m.body))
  35. r := &http.Response{
  36. StatusCode: m.statusOverride,
  37. Body: s,
  38. }
  39. return r, nil
  40. }
  41. type FakeDialer struct{}
  42. func (w FakeDialer) Catch() (Snowflake, error) {
  43. fmt.Println("Caught a dummy snowflake.")
  44. return &WebRTCPeer{}, nil
  45. }
  46. type FakeSocksConn struct {
  47. net.Conn
  48. rejected bool
  49. }
  50. func (f FakeSocksConn) Reject() error {
  51. f.rejected = true
  52. return nil
  53. }
  54. func (f FakeSocksConn) Grant(addr *net.TCPAddr) error { return nil }
  55. type FakePeers struct{ toRelease *WebRTCPeer }
  56. func (f FakePeers) Collect() (Snowflake, error) { return &WebRTCPeer{}, nil }
  57. func (f FakePeers) Pop() Snowflake { return nil }
  58. func (f FakePeers) Melted() <-chan struct{} { return nil }
  59. func TestSnowflakeClient(t *testing.T) {
  60. Convey("Peers", t, func() {
  61. Convey("Can construct", func() {
  62. p := NewPeers(1)
  63. So(p.capacity, ShouldEqual, 1)
  64. So(p.snowflakeChan, ShouldNotBeNil)
  65. So(cap(p.snowflakeChan), ShouldEqual, 1)
  66. })
  67. Convey("Collecting a Snowflake requires a Tongue.", func() {
  68. p := NewPeers(1)
  69. _, err := p.Collect()
  70. So(err, ShouldNotBeNil)
  71. So(p.Count(), ShouldEqual, 0)
  72. // Set the dialer so that collection is possible.
  73. p.Tongue = FakeDialer{}
  74. _, err = p.Collect()
  75. So(err, ShouldBeNil)
  76. So(p.Count(), ShouldEqual, 1)
  77. // S
  78. _, err = p.Collect()
  79. })
  80. Convey("Collection continues until capacity.", func() {
  81. c := 5
  82. p := NewPeers(c)
  83. p.Tongue = FakeDialer{}
  84. // Fill up to capacity.
  85. for i := 0; i < c; i++ {
  86. fmt.Println("Adding snowflake ", i)
  87. _, err := p.Collect()
  88. So(err, ShouldBeNil)
  89. So(p.Count(), ShouldEqual, i+1)
  90. }
  91. // But adding another gives an error.
  92. So(p.Count(), ShouldEqual, c)
  93. _, err := p.Collect()
  94. So(err, ShouldNotBeNil)
  95. So(p.Count(), ShouldEqual, c)
  96. // But popping and closing allows it to continue.
  97. s := p.Pop()
  98. s.Close()
  99. So(s, ShouldNotBeNil)
  100. So(p.Count(), ShouldEqual, c-1)
  101. _, err = p.Collect()
  102. So(err, ShouldBeNil)
  103. So(p.Count(), ShouldEqual, c)
  104. })
  105. Convey("Count correctly purges peers marked for deletion.", func() {
  106. p := NewPeers(4)
  107. p.Tongue = FakeDialer{}
  108. p.Collect()
  109. p.Collect()
  110. p.Collect()
  111. p.Collect()
  112. So(p.Count(), ShouldEqual, 4)
  113. s := p.Pop()
  114. s.Close()
  115. So(p.Count(), ShouldEqual, 3)
  116. s = p.Pop()
  117. s.Close()
  118. So(p.Count(), ShouldEqual, 2)
  119. })
  120. Convey("End Closes all peers.", func() {
  121. cnt := 5
  122. p := NewPeers(cnt)
  123. for i := 0; i < cnt; i++ {
  124. p.activePeers.PushBack(&WebRTCPeer{})
  125. }
  126. So(p.Count(), ShouldEqual, cnt)
  127. p.End()
  128. <-p.Melted()
  129. So(p.Count(), ShouldEqual, 0)
  130. })
  131. Convey("Pop skips over closed peers.", func() {
  132. p := NewPeers(4)
  133. p.Tongue = FakeDialer{}
  134. wc1, _ := p.Collect()
  135. wc2, _ := p.Collect()
  136. wc3, _ := p.Collect()
  137. So(wc1, ShouldNotBeNil)
  138. So(wc2, ShouldNotBeNil)
  139. So(wc3, ShouldNotBeNil)
  140. wc1.Close()
  141. r := p.Pop()
  142. So(p.Count(), ShouldEqual, 2)
  143. So(r, ShouldEqual, wc2)
  144. wc4, _ := p.Collect()
  145. wc2.Close()
  146. wc3.Close()
  147. r = p.Pop()
  148. So(r, ShouldEqual, wc4)
  149. })
  150. })
  151. Convey("Snowflake", t, func() {
  152. SkipConvey("Handler Grants correctly", func() {
  153. socks := &FakeSocksConn{}
  154. snowflakes := &FakePeers{}
  155. So(socks.rejected, ShouldEqual, false)
  156. snowflakes.toRelease = nil
  157. Handler(socks, snowflakes)
  158. So(socks.rejected, ShouldEqual, true)
  159. })
  160. Convey("WebRTC Connection", func() {
  161. c := NewWebRTCPeer(nil, nil)
  162. So(c.buffer.Bytes(), ShouldEqual, nil)
  163. Convey("Can construct a WebRTCConn", func() {
  164. s := NewWebRTCPeer(nil, nil)
  165. So(s, ShouldNotBeNil)
  166. So(s.offerChannel, ShouldNotBeNil)
  167. So(s.answerChannel, ShouldNotBeNil)
  168. s.Close()
  169. })
  170. Convey("Write buffers when datachannel is nil", func() {
  171. c.Write([]byte("test"))
  172. c.transport = nil
  173. So(c.buffer.Bytes(), ShouldResemble, []byte("test"))
  174. })
  175. Convey("Write sends to datachannel when not nil", func() {
  176. mock := new(MockDataChannel)
  177. c.transport = mock
  178. mock.done = make(chan bool, 1)
  179. c.Write([]byte("test"))
  180. <-mock.done
  181. So(c.buffer.Bytes(), ShouldEqual, nil)
  182. So(mock.destination.Bytes(), ShouldResemble, []byte("test"))
  183. })
  184. Convey("Exchange SDP sets remote description", func() {
  185. c.offerChannel = make(chan *webrtc.SessionDescription, 1)
  186. c.answerChannel = make(chan *webrtc.SessionDescription, 1)
  187. c.config = &webrtc.Configuration{}
  188. c.preparePeerConnection()
  189. c.offerChannel <- nil
  190. answer := deserializeSessionDescription(
  191. `{"type":"answer","sdp":""}`)
  192. c.answerChannel <- answer
  193. c.exchangeSDP()
  194. })
  195. SkipConvey("Exchange SDP fails on nil answer", func() {
  196. c.reset = make(chan struct{})
  197. c.offerChannel = make(chan *webrtc.SessionDescription, 1)
  198. c.answerChannel = make(chan *webrtc.SessionDescription, 1)
  199. c.offerChannel <- nil
  200. c.answerChannel <- nil
  201. c.exchangeSDP()
  202. <-c.reset
  203. })
  204. })
  205. })
  206. Convey("Dialers", t, func() {
  207. Convey("Can construct WebRTCDialer.", func() {
  208. broker := &BrokerChannel{Host: "test"}
  209. d := NewWebRTCDialer(broker, nil)
  210. So(d, ShouldNotBeNil)
  211. So(d.BrokerChannel, ShouldNotBeNil)
  212. So(d.BrokerChannel.Host, ShouldEqual, "test")
  213. })
  214. Convey("WebRTCDialer cannot Catch a snowflake with nil broker.", func() {
  215. d := NewWebRTCDialer(nil, nil)
  216. conn, err := d.Catch()
  217. So(conn, ShouldBeNil)
  218. So(err, ShouldNotBeNil)
  219. })
  220. SkipConvey("WebRTCDialer can Catch a snowflake.", func() {
  221. broker := &BrokerChannel{Host: "test"}
  222. d := NewWebRTCDialer(broker, nil)
  223. conn, err := d.Catch()
  224. So(conn, ShouldBeNil)
  225. So(err, ShouldNotBeNil)
  226. })
  227. })
  228. Convey("Rendezvous", t, func() {
  229. transport := &MockTransport{
  230. http.StatusOK,
  231. []byte(`{"type":"answer","sdp":"fake"}`),
  232. }
  233. fakeOffer := deserializeSessionDescription(`{"type":"offer","sdp":"test"}`)
  234. Convey("Construct BrokerChannel with no front domain", func() {
  235. b := NewBrokerChannel("test.broker", "", transport)
  236. So(b.url, ShouldNotBeNil)
  237. So(b.url.Path, ShouldResemble, "test.broker")
  238. So(b.transport, ShouldNotBeNil)
  239. })
  240. Convey("Construct BrokerChannel *with* front domain", func() {
  241. b := NewBrokerChannel("test.broker", "front", transport)
  242. So(b.url, ShouldNotBeNil)
  243. So(b.url.Path, ShouldResemble, "test.broker")
  244. So(b.url.Host, ShouldResemble, "front")
  245. So(b.transport, ShouldNotBeNil)
  246. })
  247. Convey("BrokerChannel.Negotiate responds with answer", func() {
  248. b := NewBrokerChannel("test.broker", "", transport)
  249. answer, err := b.Negotiate(fakeOffer)
  250. So(err, ShouldBeNil)
  251. So(answer, ShouldNotBeNil)
  252. So(answer.SDP, ShouldResemble, "fake")
  253. })
  254. Convey("BrokerChannel.Negotiate fails with 503", func() {
  255. b := NewBrokerChannel("test.broker", "",
  256. &MockTransport{http.StatusServiceUnavailable, []byte("\n")})
  257. answer, err := b.Negotiate(fakeOffer)
  258. So(err, ShouldNotBeNil)
  259. So(answer, ShouldBeNil)
  260. So(err.Error(), ShouldResemble, BrokerError503)
  261. })
  262. Convey("BrokerChannel.Negotiate fails with 400", func() {
  263. b := NewBrokerChannel("test.broker", "",
  264. &MockTransport{http.StatusBadRequest, []byte("\n")})
  265. answer, err := b.Negotiate(fakeOffer)
  266. So(err, ShouldNotBeNil)
  267. So(answer, ShouldBeNil)
  268. So(err.Error(), ShouldResemble, BrokerError400)
  269. })
  270. Convey("BrokerChannel.Negotiate fails with large read", func() {
  271. b := NewBrokerChannel("test.broker", "",
  272. &MockTransport{http.StatusOK, make([]byte, 100001, 100001)})
  273. answer, err := b.Negotiate(fakeOffer)
  274. So(err, ShouldNotBeNil)
  275. So(answer, ShouldBeNil)
  276. So(err.Error(), ShouldResemble, "unexpected EOF")
  277. })
  278. Convey("BrokerChannel.Negotiate fails with unexpected error", func() {
  279. b := NewBrokerChannel("test.broker", "",
  280. &MockTransport{123, []byte("")})
  281. answer, err := b.Negotiate(fakeOffer)
  282. So(err, ShouldNotBeNil)
  283. So(answer, ShouldBeNil)
  284. So(err.Error(), ShouldResemble, BrokerErrorUnexpected)
  285. })
  286. })
  287. }