diff options
Diffstat (limited to 'pkg/snowflake/lib/lib_test.go')
-rw-r--r-- | pkg/snowflake/lib/lib_test.go | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/pkg/snowflake/lib/lib_test.go b/pkg/snowflake/lib/lib_test.go new file mode 100644 index 0000000..5537a52 --- /dev/null +++ b/pkg/snowflake/lib/lib_test.go @@ -0,0 +1,269 @@ +package lib + +import ( + "bytes" + "fmt" + "io/ioutil" + "net" + "net/http" + "testing" + + "git.torproject.org/pluggable-transports/snowflake.git/common/util" + . "github.com/smartystreets/goconvey/convey" +) + +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 { + max int +} + +func (w FakeDialer) Catch() (*WebRTCPeer, error) { + fmt.Println("Caught a dummy snowflake.") + return &WebRTCPeer{}, nil +} + +func (w FakeDialer) GetMax() int { + return w.max +} + +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() (*WebRTCPeer, error) { return &WebRTCPeer{}, nil } +func (f FakePeers) Pop() *WebRTCPeer { return nil } +func (f FakePeers) Melted() <-chan struct{} { return nil } + +func TestSnowflakeClient(t *testing.T) { + + Convey("Peers", t, func() { + Convey("Can construct", func() { + d := &FakeDialer{max: 1} + p, _ := NewPeers(d) + So(p.Tongue.GetMax(), ShouldEqual, 1) + So(p.snowflakeChan, ShouldNotBeNil) + So(cap(p.snowflakeChan), ShouldEqual, 1) + }) + + Convey("Collecting a Snowflake requires a Tongue.", func() { + p, err := NewPeers(nil) + So(err, ShouldNotBeNil) + // Set the dialer so that collection is possible. + d := &FakeDialer{max: 1} + p, err = NewPeers(d) + _, 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(FakeDialer{max: c}) + // 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(FakeDialer{max: 5}) + 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(FakeDialer{max: 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(FakeDialer{max: 4}) + 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{} + broker := &BrokerChannel{Host: "test"} + d := NewWebRTCDialer(broker, nil, 1) + + So(socks.rejected, ShouldEqual, false) + Handler(socks, d) + So(socks.rejected, ShouldEqual, true) + }) + }) + + Convey("Dialers", t, func() { + Convey("Can construct WebRTCDialer.", func() { + broker := &BrokerChannel{Host: "test"} + d := NewWebRTCDialer(broker, nil, 1) + So(d, ShouldNotBeNil) + So(d.BrokerChannel, ShouldNotBeNil) + So(d.BrokerChannel.Host, ShouldEqual, "test") + }) + SkipConvey("WebRTCDialer can Catch a snowflake.", func() { + broker := &BrokerChannel{Host: "test"} + d := NewWebRTCDialer(broker, nil, 1) + conn, err := d.Catch() + So(conn, ShouldBeNil) + So(err, ShouldNotBeNil) + }) + }) + + Convey("Rendezvous", t, func() { + transport := &MockTransport{ + http.StatusOK, + []byte(`{"type":"answer","sdp":"fake"}`), + } + fakeOffer, err := util.DeserializeSessionDescription(`{"type":"offer","sdp":"test"}`) + if err != nil { + panic(err) + } + + Convey("Construct BrokerChannel with no front domain", func() { + b, err := NewBrokerChannel("test.broker", "", transport, false) + So(b.url, ShouldNotBeNil) + So(err, ShouldBeNil) + So(b.url.Path, ShouldResemble, "test.broker") + So(b.transport, ShouldNotBeNil) + }) + + Convey("Construct BrokerChannel *with* front domain", func() { + b, err := NewBrokerChannel("test.broker", "front", transport, false) + So(b.url, ShouldNotBeNil) + So(err, ShouldBeNil) + 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, err := NewBrokerChannel("test.broker", "", transport, false) + So(err, ShouldBeNil) + answer, err := b.Negotiate(fakeOffer) + So(err, ShouldBeNil) + So(answer, ShouldNotBeNil) + So(answer.SDP, ShouldResemble, "fake") + }) + + Convey("BrokerChannel.Negotiate fails with 503", func() { + b, err := NewBrokerChannel("test.broker", "", + &MockTransport{http.StatusServiceUnavailable, []byte("\n")}, + false) + So(err, ShouldBeNil) + answer, err := b.Negotiate(fakeOffer) + So(err, ShouldNotBeNil) + So(answer, ShouldBeNil) + So(err.Error(), ShouldResemble, BrokerError503) + }) + + Convey("BrokerChannel.Negotiate fails with 400", func() { + b, err := NewBrokerChannel("test.broker", "", + &MockTransport{http.StatusBadRequest, []byte("\n")}, + false) + So(err, ShouldBeNil) + 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, err := NewBrokerChannel("test.broker", "", + &MockTransport{http.StatusOK, make([]byte, 100001, 100001)}, + false) + So(err, ShouldBeNil) + 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, err := NewBrokerChannel("test.broker", "", + &MockTransport{123, []byte("")}, false) + So(err, ShouldBeNil) + answer, err := b.Negotiate(fakeOffer) + So(err, ShouldNotBeNil) + So(answer, ShouldBeNil) + So(err.Error(), ShouldResemble, BrokerErrorUnexpected) + }) + }) + +} |