Skip to content

Commit

Permalink
test: increase Client test coverage (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
eshanholtz authored Sep 9, 2021
1 parent 742212b commit ac8119c
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 1,072 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ docker-push:
docker push twilio/twilio-go:apidefs-${API_DEFINITIONS_SHA}
docker push twilio/twilio-go:latest

GO_DIRS = $(shell go list ./... | grep -v /rest/)
GO_DIRS = $(shell go list ./... | grep -v /rest/ | grep -v /form )
cover:
go test ${GO_DIRS} -coverprofile coverage.out
go test ${GO_DIRS} -json > test-report.out
3 changes: 2 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"

"github.com/pkg/errors"
"github.com/twilio/twilio-go/client/form"
)

// Credentials store user authentication credentials.
Expand Down Expand Up @@ -98,7 +99,7 @@ func (c *Client) SendRequest(method string, rawURL string, data url.Values,

if method == http.MethodGet {
if data != nil {
v, _ := EncodeToStringWith(data, delimiter, escapee, keepZeros)
v, _ := form.EncodeToStringWith(data, delimiter, escapee, keepZeros)
regex := regexp.MustCompile(`\.\d+`)
s := regex.ReplaceAllString(v, "")

Expand Down
165 changes: 127 additions & 38 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"time"

"github.com/stretchr/testify/assert"
twilio "github.com/twilio/twilio-go/client"
)

var mockServer *httptest.Server
var testClient *twilio.Client

func NewClient(accountSid string, authToken string) *twilio.Client {
c := &twilio.Client{
Credentials: twilio.NewCredentials(accountSid, authToken),
Expand All @@ -21,22 +26,36 @@ func NewClient(accountSid string, authToken string) *twilio.Client {
return c
}

func TestMain(m *testing.M) {
mockServer = httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
d := map[string]interface{}{
"response": "ok",
}
encoder := json.NewEncoder(writer)
_ = encoder.Encode(&d)
}))
defer mockServer.Close()

testClient = NewClient("user", "pass")
os.Exit(m.Run())
}

func TestClient_SendRequestError(t *testing.T) {
errorResponse := `{
"status": 400,
"code":20001,
"message":"Bad request",
"more_info":"https://www.twilio.com/docs/errors/20001"
}`
mockServer := httptest.NewServer(http.HandlerFunc(
errorServer := httptest.NewServer(http.HandlerFunc(
func(resp http.ResponseWriter, req *http.Request) {
resp.WriteHeader(400)
_, _ = resp.Write([]byte(errorResponse))
}))
defer mockServer.Close()
defer errorServer.Close()

client := NewClient("user", "pass")
resp, err := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
resp, err := testClient.SendRequest("GET", errorServer.URL, nil, nil) //nolint:bodyclose
twilioError := err.(*twilio.TwilioRestError)
assert.Nil(t, resp)
assert.Equal(t, 400, twilioError.Status)
Expand All @@ -46,6 +65,26 @@ func TestClient_SendRequestError(t *testing.T) {
assert.Nil(t, twilioError.Details)
}

func TestClient_SendRequestDecodeError(t *testing.T) {
errorResponse := `{
"status": 400,
"code":20001,
"message":"Bad request",
"more_info":"https://www.twilio.com/docs/errors/20001",
}`
errorServer := httptest.NewServer(http.HandlerFunc(
func(resp http.ResponseWriter, req *http.Request) {
resp.WriteHeader(400)
_, _ = resp.Write([]byte(errorResponse))
}))
defer errorServer.Close()

resp, err := testClient.SendRequest("GET", errorServer.URL, nil, nil) //nolint:bodyclose
assert.Error(t, err)
assert.Contains(t, err.Error(), "error decoding the response for an HTTP error code: 400")
assert.Nil(t, resp)
}

func TestClient_SendRequestErrorWithDetails(t *testing.T) {
errorResponse := []byte(`{
"status": 400,
Expand All @@ -56,15 +95,14 @@ func TestClient_SendRequestErrorWithDetails(t *testing.T) {
"foo": "bar"
}
}`)
mockServer := httptest.NewServer(http.HandlerFunc(
errorServer := httptest.NewServer(http.HandlerFunc(
func(resp http.ResponseWriter, req *http.Request) {
resp.WriteHeader(400)
_, _ = resp.Write(errorResponse)
}))
defer mockServer.Close()
defer errorServer.Close()

client := NewClient("user", "pass")
resp, err := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
resp, err := testClient.SendRequest("GET", errorServer.URL, nil, nil) //nolint:bodyclose
twilioError := err.(*twilio.TwilioRestError)
details := make(map[string]interface{})
details["foo"] = "bar"
Expand All @@ -77,64 +115,79 @@ func TestClient_SendRequestErrorWithDetails(t *testing.T) {
}

func TestClient_SendRequestWithRedirect(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(
redirectServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(307)
_, _ = writer.Write([]byte(`{"redirect_to": "some_place"}`))
}))
defer mockServer.Close()
defer redirectServer.Close()

client := NewClient("user", "pass")
resp, _ := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
resp, _ := testClient.SendRequest("GET", redirectServer.URL, nil, nil) //nolint:bodyclose
assert.Equal(t, 307, resp.StatusCode)
}

func TestClient_SetTimeoutTimesOut(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(
func TestClient_SendRequestCreatesClient(t *testing.T) {
c := &twilio.Client{
Credentials: twilio.NewCredentials("user", "pass"),
}
resp, err := c.SendRequest("GET", mockServer.URL, nil, nil) //nolint:bodyclose
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
}

func TestClient_SendRequestWithData(t *testing.T) {
dataServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
_ = request.ParseForm()
assert.Equal(t, "bar", request.FormValue("foo"))
d := map[string]interface{}{
"response": "ok",
}
time.Sleep(100 * time.Microsecond)
encoder := json.NewEncoder(writer)
err := encoder.Encode(&d)
if err != nil {
t.Error(err)
}
writer.WriteHeader(http.StatusOK)
}))
defer mockServer.Close()
defer dataServer.Close()

client := NewClient("user", "pass")
client.SetTimeout(10 * time.Microsecond)
_, err := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
assert.Error(t, err)
tests := []string{http.MethodGet, http.MethodPost}
for _, tc := range tests {
t.Run(tc, func(t *testing.T) {
data := url.Values{}
data.Set("foo", "bar")
resp, err := testClient.SendRequest(tc, dataServer.URL, data, nil) //nolint:bodyclose
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
})
}
}

func TestClient_SetTimeoutSucceeds(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(
func TestClient_SendRequestWithHeaders(t *testing.T) {
headerServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
assert.Equal(t, "bar", request.Header.Get("foo"))
d := map[string]interface{}{
"response": "ok",
}
time.Sleep(100 * time.Microsecond)
encoder := json.NewEncoder(writer)
err := encoder.Encode(&d)
if err != nil {
t.Error(err)
}
}))
defer mockServer.Close()
defer headerServer.Close()

client := NewClient("user", "pass")
client.SetTimeout(10 * time.Second)
resp, err := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
headers := map[string]interface{}{
"foo": "bar",
}
resp, err := testClient.SendRequest("GET", headerServer.URL, nil, headers) //nolint:bodyclose
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
}

func TestClient_SetTimeoutCreatesClient(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(
func TestClient_SetTimeoutTimesOut(t *testing.T) {
timeoutServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
d := map[string]interface{}{
"response": "ok",
Expand All @@ -145,20 +198,50 @@ func TestClient_SetTimeoutCreatesClient(t *testing.T) {
if err != nil {
t.Error(err)
}
writer.WriteHeader(http.StatusOK)
}))
defer mockServer.Close()
defer timeoutServer.Close()

c := NewClient("user", "pass")
c.SetTimeout(10 * time.Microsecond)
_, err := c.SendRequest("GET", timeoutServer.URL, nil, nil) //nolint:bodyclose
assert.Error(t, err)
}

func TestClient_SetTimeoutSucceeds(t *testing.T) {
timeoutServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
d := map[string]interface{}{
"response": "ok",
}
time.Sleep(100 * time.Microsecond)
encoder := json.NewEncoder(writer)
err := encoder.Encode(&d)
if err != nil {
t.Error(err)
}
}))
defer timeoutServer.Close()

c := NewClient("user", "pass")
c.SetTimeout(10 * time.Second)
resp, err := c.SendRequest("GET", timeoutServer.URL, nil, nil) //nolint:bodyclose
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
}

client := &twilio.Client{
func TestClient_SetTimeoutCreatesClient(t *testing.T) {
c := &twilio.Client{
Credentials: twilio.NewCredentials("user", "pass"),
}
client.SetTimeout(20 * time.Second)
resp, err := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
c.SetTimeout(20 * time.Second)
resp, err := c.SendRequest("GET", mockServer.URL, nil, nil) //nolint:bodyclose
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
}

func TestClient_UnicodeResponse(t *testing.T) {
mockServer := httptest.NewServer(http.HandlerFunc(
unicodeServer := httptest.NewServer(http.HandlerFunc(
func(writer http.ResponseWriter, request *http.Request) {
d := map[string]interface{}{
"testing-unicode": "Ω≈ç√, 💩",
Expand All @@ -169,11 +252,17 @@ func TestClient_UnicodeResponse(t *testing.T) {
t.Error(err)
}
}))
defer mockServer.Close()
defer unicodeServer.Close()

client := NewClient("user", "pass")
resp, _ := client.SendRequest("get", mockServer.URL, nil, nil) //nolint:bodyclose
c := NewClient("user", "pass")
resp, _ := c.SendRequest("GET", unicodeServer.URL, nil, nil) //nolint:bodyclose
assert.Equal(t, 200, resp.StatusCode)
body, _ := ioutil.ReadAll(resp.Body)
assert.Equal(t, "{\"testing-unicode\":\"Ω≈ç√, 💩\"}\n", string(body))
}

func TestClient_SetAccountSid(t *testing.T) {
client := NewClient("user", "pass")
client.SetAccountSid("account_sid")
assert.Equal(t, "account_sid", client.AccountSid())
}
2 changes: 1 addition & 1 deletion client/encode.go → client/form/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//nolint
package client
package form

import (
"encoding"
Expand Down
2 changes: 1 addition & 1 deletion client/form.go → client/form/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// license that can be found in the LICENSE file.

// Package form implements encoding and decoding of application/x-www-form-urlencoded data.
package client
package form

const (
implicitKey = "_"
Expand Down
2 changes: 1 addition & 1 deletion client/node.go → client/form/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//nolint
package client
package form

import (
"net/url"
Expand Down
16 changes: 0 additions & 16 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,10 @@ go 1.16

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-lintpack/lintpack v0.5.2 // indirect
github.com/golang/mock v1.6.0
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 // indirect
github.com/golangci/go-tools v0.0.0-20190318055746-e32c54105b7c // indirect
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3 // indirect
github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee // indirect
github.com/golangci/golangci-lint v1.39.0 // indirect
github.com/golangci/gosec v0.0.0-20190211064107-66fb7fc33547 // indirect
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc // indirect
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21 // indirect
github.com/klauspost/cpuid v1.2.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pkg/errors v0.9.1
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7 // indirect
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect
github.com/stretchr/testify v1.7.0
golang.org/x/tools v0.1.5 // indirect
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 // indirect
)
Loading

0 comments on commit ac8119c

Please sign in to comment.