123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- package lib
- import (
- "bytes"
- "fmt"
- "io/ioutil"
- "net"
- "net/http"
- "testing"
- "github.com/pion/webrtc"
- . "github.com/smartystreets/goconvey/convey"
- )
- type MockDataChannel struct {
- destination bytes.Buffer
- done chan bool
- }
- func (m *MockDataChannel) Send(data []byte) error {
- m.destination.Write(data)
- m.done <- true
- return nil
- }
- func (*MockDataChannel) Close() error { return nil }
- type MockResponse struct{}
- func (m *MockResponse) Read(p []byte) (int, error) {
- p = []byte(`{"type":"answer","sdp":"fake"}`)
- return 0, nil
- }
- func (m *MockResponse) Close() error { return nil }
- type MockTransport struct {
- statusOverride int
- body []byte
- }
- // Just returns a response with fake SDP answer.
- func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
- s := ioutil.NopCloser(bytes.NewReader(m.body))
- r := &http.Response{
- StatusCode: m.statusOverride,
- Body: s,
- }
- return r, nil
- }
- type FakeDialer struct{}
- func (w FakeDialer) Catch() (Snowflake, error) {
- fmt.Println("Caught a dummy snowflake.")
- return &WebRTCPeer{}, nil
- }
- type FakeSocksConn struct {
- net.Conn
- rejected bool
- }
- func (f FakeSocksConn) Reject() error {
- f.rejected = true
- return nil
- }
- func (f FakeSocksConn) Grant(addr *net.TCPAddr) error { return nil }
- type FakePeers struct{ toRelease *WebRTCPeer }
- func (f FakePeers) Collect() (Snowflake, error) { return &WebRTCPeer{}, nil }
- func (f FakePeers) Pop() Snowflake { return nil }
- func (f FakePeers) Melted() <-chan struct{} { return nil }
- func TestSnowflakeClient(t *testing.T) {
- 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)
- _, err := p.Collect()
- So(err, ShouldNotBeNil)
- So(p.Count(), ShouldEqual, 0)
- // Set the dialer so that collection is possible.
- p.Tongue = FakeDialer{}
- _, err = p.Collect()
- So(err, ShouldBeNil)
- So(p.Count(), ShouldEqual, 1)
- // S
- _, err = p.Collect()
- })
- Convey("Collection continues until capacity.", func() {
- c := 5
- p := NewPeers(c)
- p.Tongue = FakeDialer{}
- // Fill up to capacity.
- for i := 0; i < c; i++ {
- fmt.Println("Adding snowflake ", i)
- _, err := p.Collect()
- So(err, ShouldBeNil)
- So(p.Count(), ShouldEqual, i+1)
- }
- // But adding another gives an error.
- So(p.Count(), ShouldEqual, c)
- _, err := p.Collect()
- 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)
- _, err = p.Collect()
- 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)
- })
- Convey("End Closes all peers.", func() {
- cnt := 5
- p := NewPeers(cnt)
- for i := 0; i < cnt; i++ {
- p.activePeers.PushBack(&WebRTCPeer{})
- }
- So(p.Count(), ShouldEqual, cnt)
- p.End()
- <-p.Melted()
- So(p.Count(), ShouldEqual, 0)
- })
- 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)
- })
- })
- Convey("Snowflake", t, func() {
- SkipConvey("Handler Grants correctly", func() {
- socks := &FakeSocksConn{}
- snowflakes := &FakePeers{}
- So(socks.rejected, ShouldEqual, false)
- snowflakes.toRelease = nil
- Handler(socks, snowflakes)
- So(socks.rejected, ShouldEqual, true)
- })
- Convey("WebRTC Connection", func() {
- c := NewWebRTCPeer(nil, nil)
- So(c.buffer.Bytes(), ShouldEqual, nil)
- Convey("Can construct a WebRTCConn", func() {
- s := NewWebRTCPeer(nil, nil)
- So(s, ShouldNotBeNil)
- So(s.offerChannel, ShouldNotBeNil)
- So(s.answerChannel, ShouldNotBeNil)
- s.Close()
- })
- Convey("Write buffers when datachannel is nil", func() {
- c.Write([]byte("test"))
- c.transport = nil
- So(c.buffer.Bytes(), ShouldResemble, []byte("test"))
- })
- Convey("Write sends to datachannel when not nil", func() {
- mock := new(MockDataChannel)
- c.transport = mock
- mock.done = make(chan bool, 1)
- c.Write([]byte("test"))
- <-mock.done
- So(c.buffer.Bytes(), ShouldEqual, nil)
- So(mock.destination.Bytes(), ShouldResemble, []byte("test"))
- })
- Convey("Exchange SDP sets remote description", func() {
- c.offerChannel = make(chan *webrtc.SessionDescription, 1)
- c.answerChannel = make(chan *webrtc.SessionDescription, 1)
- c.config = &webrtc.Configuration{}
- c.preparePeerConnection()
- c.offerChannel <- nil
- answer := deserializeSessionDescription(
- `{"type":"answer","sdp":""}`)
- c.answerChannel <- answer
- c.exchangeSDP()
- })
- SkipConvey("Exchange SDP fails on nil answer", func() {
- c.reset = make(chan struct{})
- c.offerChannel = make(chan *webrtc.SessionDescription, 1)
- c.answerChannel = make(chan *webrtc.SessionDescription, 1)
- c.offerChannel <- nil
- c.answerChannel <- nil
- c.exchangeSDP()
- <-c.reset
- })
- })
- })
- 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)
- })
- })
- Convey("Rendezvous", t, func() {
- transport := &MockTransport{
- http.StatusOK,
- []byte(`{"type":"answer","sdp":"fake"}`),
- }
- fakeOffer := deserializeSessionDescription(`{"type":"offer","sdp":"test"}`)
- Convey("Construct BrokerChannel with no front domain", func() {
- b := NewBrokerChannel("test.broker", "", transport)
- So(b.url, ShouldNotBeNil)
- So(b.url.Path, ShouldResemble, "test.broker")
- So(b.transport, ShouldNotBeNil)
- })
- Convey("Construct BrokerChannel *with* front domain", func() {
- b := NewBrokerChannel("test.broker", "front", transport)
- So(b.url, ShouldNotBeNil)
- So(b.url.Path, ShouldResemble, "test.broker")
- So(b.url.Host, ShouldResemble, "front")
- So(b.transport, ShouldNotBeNil)
- })
- Convey("BrokerChannel.Negotiate responds with answer", func() {
- b := NewBrokerChannel("test.broker", "", transport)
- answer, err := b.Negotiate(fakeOffer)
- So(err, ShouldBeNil)
- So(answer, ShouldNotBeNil)
- So(answer.SDP, ShouldResemble, "fake")
- })
- Convey("BrokerChannel.Negotiate fails with 503", func() {
- b := NewBrokerChannel("test.broker", "",
- &MockTransport{http.StatusServiceUnavailable, []byte("\n")})
- answer, err := b.Negotiate(fakeOffer)
- So(err, ShouldNotBeNil)
- So(answer, ShouldBeNil)
- So(err.Error(), ShouldResemble, BrokerError503)
- })
- Convey("BrokerChannel.Negotiate fails with 400", func() {
- b := NewBrokerChannel("test.broker", "",
- &MockTransport{http.StatusBadRequest, []byte("\n")})
- answer, err := b.Negotiate(fakeOffer)
- So(err, ShouldNotBeNil)
- So(answer, ShouldBeNil)
- So(err.Error(), ShouldResemble, BrokerError400)
- })
- 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")
- })
- Convey("BrokerChannel.Negotiate fails with unexpected error", func() {
- b := NewBrokerChannel("test.broker", "",
- &MockTransport{123, []byte("")})
- answer, err := b.Negotiate(fakeOffer)
- So(err, ShouldNotBeNil)
- So(answer, ShouldBeNil)
- So(err.Error(), ShouldResemble, BrokerErrorUnexpected)
- })
- })
- }
|