Skip to content

Commit

Permalink
Merge pull request #3 from qntfy/expected-stop-and-tests
Browse files Browse the repository at this point in the history
Add Stream.ExpectedStop() and export test utils
  • Loading branch information
JoshuaC215 authored Feb 7, 2019
2 parents e45a28a + 0e4fd64 commit b1f5777
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 32 deletions.
8 changes: 8 additions & 0 deletions twitter/streams.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type Stream struct {
done chan struct{}
group *sync.WaitGroup
body io.Closer
expected bool
}

// newStream creates a Stream and starts a goroutine to retry connecting and
Expand All @@ -175,6 +176,7 @@ func newStream(client *http.Client, req *http.Request, expBackoff, aggExpBackoff
// Stop signals retry and receiver to stop, closes the Messages channel, and
// blocks until done.
func (s *Stream) Stop() {
s.expected = true
close(s.done)
// Scanner does not have a Stop() or take a done channel, so for low volume
// streams Scan() blocks until the next keep-alive. Close the resp.Body to
Expand All @@ -186,6 +188,12 @@ func (s *Stream) Stop() {
s.group.Wait()
}

// ExpectedStop indicates whether Stream halting was due to an expected Stop()
// or some error condition.
func (s *Stream) ExpectedStop() bool {
return s.expected
}

// retry retries making the given http.Request and receiving the response
// according to the Twitter backoff policies. Callers should invoke in a
// goroutine since backoffs sleep between retries.
Expand Down
57 changes: 57 additions & 0 deletions twitter/test_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package twitter

import (
"net/http"
"net/http/httptest"
"net/url"
)

// NewTestStream creates a Stream for testing with a provided input Messages channel.
// It is safe to call Stop() once on the provided *Stream, as with a normal Stream.
func NewTestStream(messages chan interface{}) *Stream {
return &Stream{
Messages: messages,
done: make(chan struct{}),
}
}

// NewTestServer exposes testServer for test scaffolding in libraries that use go-twitter
// it takes a map of path:functions to set the ServeMux.
func NewTestServer(handlers map[string]func(w http.ResponseWriter, r *http.Request)) (*http.Client, *httptest.Server) {
client, mux, server := testServer()
for path, handler := range handlers {
mux.HandleFunc(path, handler)
}
return client, server
}

// testServer returns an http Client, ServeMux, and Server. The client proxies
// requests to the server and handlers can be registered on the mux to handle
// requests. The caller must close the test server.
func testServer() (*http.Client, *http.ServeMux, *httptest.Server) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
transport := &RewriteTransport{&http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(server.URL)
},
}}
client := &http.Client{Transport: transport}
return client, mux, server
}

// RewriteTransport rewrites https requests to http to avoid TLS cert issues
// during testing.
type RewriteTransport struct {
Transport http.RoundTripper
}

// RoundTrip rewrites the request scheme to http and calls through to the
// composed RoundTripper or if it is nil, to the http.DefaultTransport.
func (t *RewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req.URL.Scheme = "http"
if t.Transport == nil {
return http.DefaultTransport.RoundTrip(req)
}
return t.Transport.RoundTrip(req)
}
32 changes: 0 additions & 32 deletions twitter/twitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package twitter

import (
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
Expand All @@ -12,37 +11,6 @@ import (

var defaultTestTimeout = time.Second * 1

// testServer returns an http Client, ServeMux, and Server. The client proxies
// requests to the server and handlers can be registered on the mux to handle
// requests. The caller must close the test server.
func testServer() (*http.Client, *http.ServeMux, *httptest.Server) {
mux := http.NewServeMux()
server := httptest.NewServer(mux)
transport := &RewriteTransport{&http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(server.URL)
},
}}
client := &http.Client{Transport: transport}
return client, mux, server
}

// RewriteTransport rewrites https requests to http to avoid TLS cert issues
// during testing.
type RewriteTransport struct {
Transport http.RoundTripper
}

// RoundTrip rewrites the request scheme to http and calls through to the
// composed RoundTripper or if it is nil, to the http.DefaultTransport.
func (t *RewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req.URL.Scheme = "http"
if t.Transport == nil {
return http.DefaultTransport.RoundTrip(req)
}
return t.Transport.RoundTrip(req)
}

func assertMethod(t *testing.T, expectedMethod string, req *http.Request) {
assert.Equal(t, expectedMethod, req.Method)
}
Expand Down

0 comments on commit b1f5777

Please sign in to comment.