From d8a5a8d5afe747fcbe39420b611340519e45af91 Mon Sep 17 00:00:00 2001 From: James Munnelly Date: Fri, 1 Dec 2017 17:41:58 +0000 Subject: [PATCH] dep ensure --- Gopkg.lock | 10 +- .../gopkg.in/jarcoal/httpmock.v1/.gitignore | 22 ++ .../gopkg.in/jarcoal/httpmock.v1/.travis.yml | 9 + vendor/gopkg.in/jarcoal/httpmock.v1/LICENSE | 20 + vendor/gopkg.in/jarcoal/httpmock.v1/README.md | 116 ++++++ vendor/gopkg.in/jarcoal/httpmock.v1/doc.go | 56 +++ vendor/gopkg.in/jarcoal/httpmock.v1/env.go | 11 + .../gopkg.in/jarcoal/httpmock.v1/env_test.go | 44 +++ .../gopkg.in/jarcoal/httpmock.v1/response.go | 134 +++++++ .../jarcoal/httpmock.v1/response_test.go | 204 ++++++++++ .../gopkg.in/jarcoal/httpmock.v1/transport.go | 327 ++++++++++++++++ .../jarcoal/httpmock.v1/transport_test.go | 352 ++++++++++++++++++ 12 files changed, 1303 insertions(+), 2 deletions(-) create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/.gitignore create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/.travis.yml create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/LICENSE create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/README.md create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/doc.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/env.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/env_test.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/response.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/response_test.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/transport.go create mode 100644 vendor/gopkg.in/jarcoal/httpmock.v1/transport_test.go diff --git a/Gopkg.lock b/Gopkg.lock index 3db05333a..5024af8e0 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -355,6 +355,12 @@ revision = "3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4" version = "v0.9.0" +[[projects]] + branch = "v1" + name = "gopkg.in/jarcoal/httpmock.v1" + packages = ["."] + revision = "cf52904a3cf0f78f199ecade6a6df8e245d5b25a" + [[projects]] branch = "v2" name = "gopkg.in/yaml.v2" @@ -382,7 +388,7 @@ [[projects]] branch = "release-5.0" name = "k8s.io/client-go" - packages = ["discovery","discovery/fake","informers/core/v1","informers/extensions/v1beta1","informers/internalinterfaces","kubernetes","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/apps/v1beta1","kubernetes/typed/apps/v1beta2","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1beta1","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v2beta1","kubernetes/typed/batch/v1","kubernetes/typed/batch/v1beta1","kubernetes/typed/batch/v2alpha1","kubernetes/typed/certificates/v1beta1","kubernetes/typed/core/v1","kubernetes/typed/extensions/v1beta1","kubernetes/typed/networking/v1","kubernetes/typed/policy/v1beta1","kubernetes/typed/rbac/v1","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1beta1","kubernetes/typed/scheduling/v1alpha1","kubernetes/typed/settings/v1alpha1","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1beta1","listers/core/v1","listers/extensions/v1beta1","pkg/version","plugin/pkg/client/auth","plugin/pkg/client/auth/azure","plugin/pkg/client/auth/gcp","plugin/pkg/client/auth/oidc","plugin/pkg/client/auth/openstack","rest","rest/watch","testing","third_party/forked/golang/template","tools/auth","tools/cache","tools/clientcmd","tools/clientcmd/api","tools/clientcmd/api/latest","tools/clientcmd/api/v1","tools/leaderelection","tools/leaderelection/resourcelock","tools/metrics","tools/pager","tools/record","tools/reference","transport","util/cert","util/flowcontrol","util/homedir","util/integer","util/jsonpath","util/workqueue"] + packages = ["discovery","discovery/fake","informers","informers/admissionregistration","informers/admissionregistration/v1alpha1","informers/apps","informers/apps/v1beta1","informers/apps/v1beta2","informers/autoscaling","informers/autoscaling/v1","informers/autoscaling/v2beta1","informers/batch","informers/batch/v1","informers/batch/v1beta1","informers/batch/v2alpha1","informers/certificates","informers/certificates/v1beta1","informers/core","informers/core/v1","informers/extensions","informers/extensions/v1beta1","informers/internalinterfaces","informers/networking","informers/networking/v1","informers/policy","informers/policy/v1beta1","informers/rbac","informers/rbac/v1","informers/rbac/v1alpha1","informers/rbac/v1beta1","informers/scheduling","informers/scheduling/v1alpha1","informers/settings","informers/settings/v1alpha1","informers/storage","informers/storage/v1","informers/storage/v1beta1","kubernetes","kubernetes/fake","kubernetes/scheme","kubernetes/typed/admissionregistration/v1alpha1","kubernetes/typed/admissionregistration/v1alpha1/fake","kubernetes/typed/apps/v1beta1","kubernetes/typed/apps/v1beta1/fake","kubernetes/typed/apps/v1beta2","kubernetes/typed/apps/v1beta2/fake","kubernetes/typed/authentication/v1","kubernetes/typed/authentication/v1/fake","kubernetes/typed/authentication/v1beta1","kubernetes/typed/authentication/v1beta1/fake","kubernetes/typed/authorization/v1","kubernetes/typed/authorization/v1/fake","kubernetes/typed/authorization/v1beta1","kubernetes/typed/authorization/v1beta1/fake","kubernetes/typed/autoscaling/v1","kubernetes/typed/autoscaling/v1/fake","kubernetes/typed/autoscaling/v2beta1","kubernetes/typed/autoscaling/v2beta1/fake","kubernetes/typed/batch/v1","kubernetes/typed/batch/v1/fake","kubernetes/typed/batch/v1beta1","kubernetes/typed/batch/v1beta1/fake","kubernetes/typed/batch/v2alpha1","kubernetes/typed/batch/v2alpha1/fake","kubernetes/typed/certificates/v1beta1","kubernetes/typed/certificates/v1beta1/fake","kubernetes/typed/core/v1","kubernetes/typed/core/v1/fake","kubernetes/typed/extensions/v1beta1","kubernetes/typed/extensions/v1beta1/fake","kubernetes/typed/networking/v1","kubernetes/typed/networking/v1/fake","kubernetes/typed/policy/v1beta1","kubernetes/typed/policy/v1beta1/fake","kubernetes/typed/rbac/v1","kubernetes/typed/rbac/v1/fake","kubernetes/typed/rbac/v1alpha1","kubernetes/typed/rbac/v1alpha1/fake","kubernetes/typed/rbac/v1beta1","kubernetes/typed/rbac/v1beta1/fake","kubernetes/typed/scheduling/v1alpha1","kubernetes/typed/scheduling/v1alpha1/fake","kubernetes/typed/settings/v1alpha1","kubernetes/typed/settings/v1alpha1/fake","kubernetes/typed/storage/v1","kubernetes/typed/storage/v1/fake","kubernetes/typed/storage/v1beta1","kubernetes/typed/storage/v1beta1/fake","listers/admissionregistration/v1alpha1","listers/apps/v1beta1","listers/apps/v1beta2","listers/autoscaling/v1","listers/autoscaling/v2beta1","listers/batch/v1","listers/batch/v1beta1","listers/batch/v2alpha1","listers/certificates/v1beta1","listers/core/v1","listers/extensions/v1beta1","listers/networking/v1","listers/policy/v1beta1","listers/rbac/v1","listers/rbac/v1alpha1","listers/rbac/v1beta1","listers/scheduling/v1alpha1","listers/settings/v1alpha1","listers/storage/v1","listers/storage/v1beta1","pkg/version","plugin/pkg/client/auth","plugin/pkg/client/auth/azure","plugin/pkg/client/auth/gcp","plugin/pkg/client/auth/oidc","plugin/pkg/client/auth/openstack","rest","rest/watch","testing","third_party/forked/golang/template","tools/auth","tools/cache","tools/clientcmd","tools/clientcmd/api","tools/clientcmd/api/latest","tools/clientcmd/api/v1","tools/leaderelection","tools/leaderelection/resourcelock","tools/metrics","tools/pager","tools/record","tools/reference","transport","util/cert","util/flowcontrol","util/homedir","util/integer","util/jsonpath","util/workqueue"] revision = "3c9596422809744570e7b344a5597b4ad8aaabfb" [[projects]] @@ -412,6 +418,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "38403ded6ab692c92470a9bd07fecf8ab268e0f01d7eb08c0ed9ffc4c4b70142" + inputs-digest = "6938bdecd896e86dedfbcb65e98140ac47ff29b4b68136a10f787f72b25eec97" solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/.gitignore b/vendor/gopkg.in/jarcoal/httpmock.v1/.gitignore new file mode 100644 index 000000000..00268614f --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/.travis.yml b/vendor/gopkg.in/jarcoal/httpmock.v1/.travis.yml new file mode 100644 index 000000000..e99eda4b1 --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.6 + - 1.7 + - 1.8 + +notifications: + email: false diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/LICENSE b/vendor/gopkg.in/jarcoal/httpmock.v1/LICENSE new file mode 100644 index 000000000..438fbf545 --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Jared Morse + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/README.md b/vendor/gopkg.in/jarcoal/httpmock.v1/README.md new file mode 100644 index 000000000..4b2d11dad --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/README.md @@ -0,0 +1,116 @@ +# httpmock [![Build Status](https://travis-ci.org/jarcoal/httpmock.png?branch=master)](https://travis-ci.org/jarcoal/httpmock) + +Easy mocking of http responses from external resources. + +## Install + +Uses gopkg to read from `v1` branch: + + go get gopkg.in/jarcoal/httpmock.v1 + +You can also use vendoring for the v1 branch if you feel so inclined. + +Currently supports Go 1.7 but also works with 1.6 for now. + +### Simple Example: +```go +func TestFetchArticles(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json", + httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`)) + + // get count info + httpmock.GetTotalCallCount() + + // get the amount of calls for the registered responder + info := httpmock.GetCallCountInfo() + info["GET https://api.mybiz.com/articles.json"] // number of GET calls made to https://api.mybiz.com/articles.json + + // do stuff that makes a request to articles.json +} +``` + +### Advanced Example: +```go +func TestFetchArticles(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + // our database of articles + articles := make([]map[string]interface{}, 0) + + // mock to list out the articles + httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json", + func(req *http.Request) (*http.Response, error) { + resp, err := httpmock.NewJsonResponse(200, articles) + if err != nil { + return httpmock.NewStringResponse(500, ""), nil + } + return resp, nil + }, + ) + + // mock to add a new article + httpmock.RegisterResponder("POST", "https://api.mybiz.com/articles.json", + func(req *http.Request) (*http.Response, error) { + article := make(map[string]interface{}) + if err := json.NewDecoder(req.Body).Decode(&article); err != nil { + return httpmock.NewStringResponse(400, ""), nil + } + + articles = append(articles, article) + + resp, err := httpmock.NewJsonResponse(200, article) + if err != nil { + return httpmock.NewStringResponse(500, ""), nil + } + return resp, nil + }, + ) + + // do stuff that adds and checks articles +} +``` + +### [Ginkgo](https://onsi.github.io/ginkgo/) Example: +```go +// article_suite_test.go + +import ( + // ... + "github.com/jarcoal/httpmock" +) +// ... +var _ = BeforeSuite(func() { + // block all HTTP requests + httpmock.Activate() +}) + +var _ = BeforeEach(func() { + // remove any mocks + httpmock.Reset() +}) + +var _ = AfterSuite(func() { + httpmock.DeactivateAndReset() +}) + + +// article_test.go + +import ( + // ... + "github.com/jarcoal/httpmock" +) + +var _ = Describe("Articles", func() { + It("returns a list of articles", func() { + httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json", + httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`)) + + // do stuff that makes a request to articles.json + }) +}) +``` diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/doc.go b/vendor/gopkg.in/jarcoal/httpmock.v1/doc.go new file mode 100644 index 000000000..d4545c8aa --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/doc.go @@ -0,0 +1,56 @@ +/* +HTTPmock provides tools for mocking HTTP responses. + +Simple Example: + func TestFetchArticles(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json", + httpmock.NewStringResponder(200, `[{"id": 1, "name": "My Great Article"}]`)) + + // do stuff that makes a request to articles.json + } + +Advanced Example: + func TestFetchArticles(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + // our database of articles + articles := make([]map[string]interface{}, 0) + + // mock to list out the articles + httpmock.RegisterResponder("GET", "https://api.mybiz.com/articles.json", + func(req *http.Request) (*http.Response, error) { + resp, err := httpmock.NewJsonResponse(200, articles) + if err != nil { + return httpmock.NewStringResponse(500, ""), nil + } + return resp + }, + ) + + // mock to add a new article + httpmock.RegisterResponder("POST", "https://api.mybiz.com/articles.json", + func(req *http.Request) (*http.Response, error) { + article := make(map[string]interface{}) + if err := json.NewDecoder(req.Body).Decode(&article); err != nil { + return httpmock.NewStringResponse(400, ""), nil + } + + articles = append(articles, article) + + resp, err := httpmock.NewJsonResponse(200, article) + if err != nil { + return httpmock.NewStringResponse(500, ""), nil + } + return resp, nil + }, + ) + + // do stuff that adds and checks articles + } + +*/ +package httpmock diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/env.go b/vendor/gopkg.in/jarcoal/httpmock.v1/env.go new file mode 100644 index 000000000..c6c076cc9 --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/env.go @@ -0,0 +1,11 @@ +package httpmock + +import ( + "os" +) + +var envVarName = "GONOMOCKS" + +func Disabled() bool { + return os.Getenv(envVarName) != "" +} diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/env_test.go b/vendor/gopkg.in/jarcoal/httpmock.v1/env_test.go new file mode 100644 index 000000000..5034358ae --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/env_test.go @@ -0,0 +1,44 @@ +package httpmock + +import ( + "net/http" + "os" + "testing" +) + +func TestEnv(t *testing.T) { + DeactivateAndReset() + + orig := os.Getenv(envVarName) + + // put it in an enabled state + if err := os.Setenv(envVarName, ""); err != nil { + t.Fatal(err) + } else if Disabled() { + t.Fatal("expected not to be disabled") + } + + // make sure an activation works + Activate() + if http.DefaultTransport != DefaultTransport { + t.Fatal("expected http.DefaultTransport to be our DefaultTransport") + } + Deactivate() + + if err := os.Setenv(envVarName, "1"); err != nil { + t.Fatal(err) + } else if !Disabled() { + t.Fatal("expected to be disabled") + } + + // make sure activation doesn't work + Activate() + if http.DefaultTransport == DefaultTransport { + t.Fatal("expected http.DefaultTransport to not be our DefaultTransport") + } + Deactivate() + + if err := os.Setenv(envVarName, orig); err != nil { + t.Fatalf("could not reset %s to it's original value '%s'", envVarName, orig) + } +} diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/response.go b/vendor/gopkg.in/jarcoal/httpmock.v1/response.go new file mode 100644 index 000000000..bd39d7f0c --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/response.go @@ -0,0 +1,134 @@ +package httpmock + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "io" + "net/http" + "strconv" + "strings" +) + +// ResponderFromResponse wraps an *http.Response in a Responder +func ResponderFromResponse(resp *http.Response) Responder { + return func(req *http.Request) (*http.Response, error) { + res := new(http.Response) + *res = *resp + res.Request = req + return res, nil + } +} + +// NewErrorResponder creates a Responder that returns an empty request and the +// given error. This can be used to e.g. imitate more deep http errors for the +// client. +func NewErrorResponder(err error) Responder { + return func(req *http.Request) (*http.Response, error) { + return nil, err + } +} + +// NewStringResponse creates an *http.Response with a body based on the given string. Also accepts +// an http status code. +func NewStringResponse(status int, body string) *http.Response { + return &http.Response{ + Status: strconv.Itoa(status), + StatusCode: status, + Body: NewRespBodyFromString(body), + Header: http.Header{}, + } +} + +// NewStringResponder creates a Responder from a given body (as a string) and status code. +func NewStringResponder(status int, body string) Responder { + return ResponderFromResponse(NewStringResponse(status, body)) +} + +// NewBytesResponse creates an *http.Response with a body based on the given bytes. Also accepts +// an http status code. +func NewBytesResponse(status int, body []byte) *http.Response { + return &http.Response{ + Status: strconv.Itoa(status), + StatusCode: status, + Body: NewRespBodyFromBytes(body), + Header: http.Header{}, + } +} + +// NewBytesResponder creates a Responder from a given body (as a byte slice) and status code. +func NewBytesResponder(status int, body []byte) Responder { + return ResponderFromResponse(NewBytesResponse(status, body)) +} + +// NewJsonResponse creates an *http.Response with a body that is a json encoded representation of +// the given interface{}. Also accepts an http status code. +func NewJsonResponse(status int, body interface{}) (*http.Response, error) { + encoded, err := json.Marshal(body) + if err != nil { + return nil, err + } + response := NewBytesResponse(status, encoded) + response.Header.Set("Content-Type", "application/json") + return response, nil +} + +// NewJsonResponder creates a Responder from a given body (as an interface{} that is encoded to +// json) and status code. +func NewJsonResponder(status int, body interface{}) (Responder, error) { + resp, err := NewJsonResponse(status, body) + if err != nil { + return nil, err + } + return ResponderFromResponse(resp), nil +} + +// NewXmlResponse creates an *http.Response with a body that is an xml encoded representation +// of the given interface{}. Also accepts an http status code. +func NewXmlResponse(status int, body interface{}) (*http.Response, error) { + encoded, err := xml.Marshal(body) + if err != nil { + return nil, err + } + response := NewBytesResponse(status, encoded) + response.Header.Set("Content-Type", "application/xml") + return response, nil +} + +// NewXmlResponder creates a Responder from a given body (as an interface{} that is encoded to xml) +// and status code. +func NewXmlResponder(status int, body interface{}) (Responder, error) { + resp, err := NewXmlResponse(status, body) + if err != nil { + return nil, err + } + return ResponderFromResponse(resp), nil +} + +// NewRespBodyFromString creates an io.ReadCloser from a string that is suitable for use as an +// http response body. +func NewRespBodyFromString(body string) io.ReadCloser { + return &dummyReadCloser{strings.NewReader(body)} +} + +// NewRespBodyFromBytes creates an io.ReadCloser from a byte slice that is suitable for use as an +// http response body. +func NewRespBodyFromBytes(body []byte) io.ReadCloser { + return &dummyReadCloser{bytes.NewReader(body)} +} + +type dummyReadCloser struct { + body io.ReadSeeker +} + +func (d *dummyReadCloser) Read(p []byte) (n int, err error) { + n, err = d.body.Read(p) + if err == io.EOF { + d.body.Seek(0, 0) + } + return n, err +} + +func (d *dummyReadCloser) Close() error { + return nil +} diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/response_test.go b/vendor/gopkg.in/jarcoal/httpmock.v1/response_test.go new file mode 100644 index 000000000..2775b03ac --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/response_test.go @@ -0,0 +1,204 @@ +package httpmock + +import ( + "encoding/json" + "encoding/xml" + "errors" + "io/ioutil" + "net/http" + "reflect" + "testing" +) + +func TestResponderFromResponse(t *testing.T) { + responder := ResponderFromResponse(NewStringResponse(200, "hello world")) + + req, err := http.NewRequest(http.MethodGet, testUrl, nil) + if err != nil { + t.Fatal("Error creating request") + } + response1, err := responder(req) + if err != nil { + t.Error("Error should be nil") + } + + testUrlWithQuery := testUrl + "?a=1" + req, err = http.NewRequest(http.MethodGet, testUrlWithQuery, nil) + if err != nil { + t.Fatal("Error creating request") + } + response2, err := responder(req) + if err != nil { + t.Error("Error should be nil") + } + + // Body should be the same for both responses + assertBody(t, response1, "hello world") + assertBody(t, response2, "hello world") + + // Request should be non-nil and different for each response + if response1.Request != nil && response2.Request != nil { + if response1.Request.URL.String() != testUrl { + t.Errorf("Expected request url %s, got: %s", testUrl, response1.Request.URL.String()) + } + if response2.Request.URL.String() != testUrlWithQuery { + t.Errorf("Expected request url %s, got: %s", testUrlWithQuery, response2.Request.URL.String()) + } + } else { + t.Error("response.Request should not be nil") + } +} + +func TestNewStringResponse(t *testing.T) { + body := "hello world" + status := 200 + response := NewStringResponse(status, body) + + data, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != body { + t.FailNow() + } + + if response.StatusCode != status { + t.FailNow() + } +} + +func TestNewBytesResponse(t *testing.T) { + body := []byte("hello world") + status := 200 + response := NewBytesResponse(status, body) + + data, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != string(body) { + t.FailNow() + } + + if response.StatusCode != status { + t.FailNow() + } +} + +func TestNewJsonResponse(t *testing.T) { + type schema struct { + Hello string `json:"hello"` + } + + body := &schema{"world"} + status := 200 + + response, err := NewJsonResponse(status, body) + if err != nil { + t.Fatal(err) + } + + if response.StatusCode != status { + t.FailNow() + } + + if response.Header.Get("Content-Type") != "application/json" { + t.FailNow() + } + + checkBody := &schema{} + if err := json.NewDecoder(response.Body).Decode(checkBody); err != nil { + t.Fatal(err) + } + + if checkBody.Hello != body.Hello { + t.FailNow() + } +} + +func TestNewXmlResponse(t *testing.T) { + type schema struct { + Hello string `xml:"hello"` + } + + body := &schema{"world"} + status := 200 + + response, err := NewXmlResponse(status, body) + if err != nil { + t.Fatal(err) + } + + if response.StatusCode != status { + t.FailNow() + } + + if response.Header.Get("Content-Type") != "application/xml" { + t.FailNow() + } + + checkBody := &schema{} + if err := xml.NewDecoder(response.Body).Decode(checkBody); err != nil { + t.Fatal(err) + } + + if checkBody.Hello != body.Hello { + t.FailNow() + } +} + +func TestNewErrorResponder(t *testing.T) { + responder := NewErrorResponder(errors.New("oh no")) + req, err := http.NewRequest(http.MethodGet, testUrl, nil) + if err != nil { + t.Fatal("Error creating request") + } + response, err := responder(req) + if response != nil { + t.Error("Response should be nil") + } + expected := errors.New("oh no") + if !reflect.DeepEqual(err, expected) { + t.Errorf("Expected error %#v, got: %#v", expected, err) + } +} + +func TestRewindResponse(t *testing.T) { + body := []byte("hello world") + status := 200 + responses := []*http.Response{ + NewBytesResponse(status, body), + NewStringResponse(status, string(body)), + } + + for _, response := range responses { + + data, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != string(body) { + t.FailNow() + } + + if response.StatusCode != status { + t.FailNow() + } + + data, err = ioutil.ReadAll(response.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != string(body) { + t.FailNow() + } + + if response.StatusCode != status { + t.FailNow() + } + } +} diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/transport.go b/vendor/gopkg.in/jarcoal/httpmock.v1/transport.go new file mode 100644 index 000000000..9a0e8f612 --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/transport.go @@ -0,0 +1,327 @@ +package httpmock + +import ( + "errors" + "fmt" + "net/http" + "strings" + "sync" +) + +// Responders are callbacks that receive and http request and return a mocked response. +type Responder func(*http.Request) (*http.Response, error) + +// NoResponderFound is returned when no responders are found for a given HTTP method and URL. +var NoResponderFound = errors.New("no responder found") + +// ConnectionFailure is a responder that returns a connection failure. This is the default +// responder, and is called when no other matching responder is found. +func ConnectionFailure(*http.Request) (*http.Response, error) { + return nil, NoResponderFound +} + +// NewMockTransport creates a new *MockTransport with no responders. +func NewMockTransport() *MockTransport { + return &MockTransport{ + responders: make(map[string]Responder), + callCountInfo: make(map[string]int), + } +} + +// MockTransport implements http.RoundTripper, which fulfills single http requests issued by +// an http.Client. This implementation doesn't actually make the call, instead deferring to +// the registered list of responders. +type MockTransport struct { + mu sync.RWMutex + responders map[string]Responder + noResponder Responder + callCountInfo map[string]int + totalCallCount int +} + +// RoundTrip receives HTTP requests and routes them to the appropriate responder. It is required to +// implement the http.RoundTripper interface. You will not interact with this directly, instead +// the *http.Client you are using will call it for you. +func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) { + url := req.URL.String() + + // try and get a responder that matches the method and URL + key := req.Method + " " + url + responder := m.responderForKey(key) + + // if we weren't able to find a responder and the URL contains a querystring + // then we strip off the querystring and try again. + if responder == nil && strings.Contains(url, "?") { + key = req.Method + " " + strings.Split(url, "?")[0] + responder = m.responderForKey(key) + } + m.mu.Lock() + defer m.mu.Unlock() + // if we found a responder, call it + if responder != nil { + m.callCountInfo[key]++ + m.totalCallCount++ + return runCancelable(responder, req) + } + + // we didn't find a responder, so fire the 'no responder' responder + if m.noResponder == nil { + return ConnectionFailure(req) + } + m.callCountInfo["NO_RESPONDER"]++ + m.totalCallCount++ + return runCancelable(m.noResponder, req) +} + +func runCancelable(responder Responder, req *http.Request) (*http.Response, error) { + if req.Cancel == nil { + return responder(req) + } + + // Set up a goroutine that translates a close(req.Cancel) into a + // "request canceled" error, and another one that runs the + // responder. Then race them: first to the result channel wins. + + type result struct { + response *http.Response + err error + } + resultch := make(chan result, 1) + done := make(chan struct{}, 1) + + go func() { + select { + case <-req.Cancel: + resultch <- result{ + response: nil, + err: errors.New("request canceled"), + } + case <-done: + } + }() + + go func() { + defer func() { + if err := recover(); err != nil { + resultch <- result{ + response: nil, + err: fmt.Errorf("panic in responder: got %q", err), + } + } + }() + + response, err := responder(req) + resultch <- result{ + response: response, + err: err, + } + }() + + r := <-resultch + + // if a close(req.Cancel) is never coming, + // we'll need to unblock the first goroutine. + done <- struct{}{} + + return r.response, r.err +} + +// do nothing with timeout +func (m *MockTransport) CancelRequest(req *http.Request) {} + +// responderForKey returns a responder for a given key +func (m *MockTransport) responderForKey(key string) Responder { + m.mu.RLock() + defer m.mu.RUnlock() + for k, r := range m.responders { + if k != key { + continue + } + return r + } + return nil +} + +// RegisterResponder adds a new responder, associated with a given HTTP method and URL. When a +// request comes in that matches, the responder will be called and the response returned to the client. +func (m *MockTransport) RegisterResponder(method, url string, responder Responder) { + key := method + " " + url + + m.mu.Lock() + m.responders[key] = responder + m.callCountInfo[key] = 0 + m.mu.Unlock() +} + +// RegisterNoResponder is used to register a responder that will be called if no other responder is +// found. The default is ConnectionFailure. +func (m *MockTransport) RegisterNoResponder(responder Responder) { + m.mu.Lock() + m.noResponder = responder + m.mu.Unlock() +} + +// Reset removes all registered responders (including the no responder) from the MockTransport +func (m *MockTransport) Reset() { + m.mu.Lock() + m.responders = make(map[string]Responder) + m.noResponder = nil + m.callCountInfo = make(map[string]int) + m.totalCallCount = 0 + m.mu.Unlock() +} + +// GetCallCountInfo returns callCountInfo +func (m *MockTransport) GetCallCountInfo() map[string]int { + res := map[string]int{} + m.mu.RLock() + for k, v := range m.callCountInfo { + res[k] = v + } + m.mu.RUnlock() + return res +} + +// GetTotalCallCount returns the totalCallCount +func (m *MockTransport) GetTotalCallCount() int { + m.mu.RLock() + count := m.totalCallCount + m.mu.RUnlock() + return count +} + +// DefaultTransport is the default mock transport used by Activate, Deactivate, Reset, +// DeactivateAndReset, RegisterResponder, and RegisterNoResponder. +var DefaultTransport = NewMockTransport() + +// InitialTransport is a cache of the original transport used so we can put it back +// when Deactivate is called. +var InitialTransport = http.DefaultTransport + +// Used to handle custom http clients (i.e clients other than http.DefaultClient) +var oldTransport http.RoundTripper +var oldClient *http.Client + +// Activate starts the mock environment. This should be called before your tests run. Under the +// hood this replaces the Transport on the http.DefaultClient with DefaultTransport. +// +// To enable mocks for a test, simply activate at the beginning of a test: +// func TestFetchArticles(t *testing.T) { +// httpmock.Activate() +// // all http requests will now be intercepted +// } +// +// If you want all of your tests in a package to be mocked, just call Activate from init(): +// func init() { +// httpmock.Activate() +// } +func Activate() { + if Disabled() { + return + } + + // make sure that if Activate is called multiple times it doesn't overwrite the InitialTransport + // with a mock transport. + if http.DefaultTransport != DefaultTransport { + InitialTransport = http.DefaultTransport + } + + http.DefaultTransport = DefaultTransport +} + +// ActivateNonDefault starts the mock environment with a non-default http.Client. +// This emulates the Activate function, but allows for custom clients that do not use +// http.DefaultTransport +// +// To enable mocks for a test using a custom client, activate at the beginning of a test: +// client := &http.Client{Transport: &http.Transport{TLSHandshakeTimeout: 60 * time.Second}} +// httpmock.ActivateNonDefault(client) +func ActivateNonDefault(client *http.Client) { + if Disabled() { + return + } + + // save the custom client & it's RoundTripper + oldTransport = client.Transport + oldClient = client + client.Transport = DefaultTransport +} + +// GetCallCountInfo gets the info on all the calls httpmock has taken since it was activated or +// reset. The info is returned as a map of the calling keys with the number of calls made to them +// as their value. The key is the method, a space, and the url all concatenated together. +func GetCallCountInfo() map[string]int { + return DefaultTransport.GetCallCountInfo() +} + +// GetTotalCallCount gets the total number of calls httpmock has taken since it was activated or +// reset. +func GetTotalCallCount() int { + return DefaultTransport.GetTotalCallCount() +} + +// Deactivate shuts down the mock environment. Any HTTP calls made after this will use a live +// transport. +// +// Usually you'll call it in a defer right after activating the mock environment: +// func TestFetchArticles(t *testing.T) { +// httpmock.Activate() +// defer httpmock.Deactivate() +// +// // when this test ends, the mock environment will close +// } +func Deactivate() { + if Disabled() { + return + } + http.DefaultTransport = InitialTransport + + // reset the custom client to use it's original RoundTripper + if oldClient != nil { + oldClient.Transport = oldTransport + } +} + +// Reset will remove any registered mocks and return the mock environment to it's initial state. +func Reset() { + DefaultTransport.Reset() +} + +// DeactivateAndReset is just a convenience method for calling Deactivate() and then Reset() +// Happy deferring! +func DeactivateAndReset() { + Deactivate() + Reset() +} + +// RegisterResponder adds a mock that will catch requests to the given HTTP method and URL, then +// route them to the Responder which will generate a response to be returned to the client. +// +// Example: +// func TestFetchArticles(t *testing.T) { +// httpmock.Activate() +// httpmock.DeactivateAndReset() +// +// httpmock.RegisterResponder("GET", "http://example.com/", +// httpmock.NewStringResponder("hello world", 200)) +// +// // requests to http://example.com/ will now return 'hello world' +// } +func RegisterResponder(method, url string, responder Responder) { + DefaultTransport.RegisterResponder(method, url, responder) +} + +// RegisterNoResponder adds a mock that will be called whenever a request for an unregistered URL +// is received. The default behavior is to return a connection error. +// +// In some cases you may not want all URLs to be mocked, in which case you can do this: +// func TestFetchArticles(t *testing.T) { +// httpmock.Activate() +// httpmock.DeactivateAndReset() +// httpmock.RegisterNoResponder(httpmock.InitialTransport.RoundTrip) +// +// // any requests that don't have a registered URL will be fetched normally +// } +func RegisterNoResponder(responder Responder) { + DefaultTransport.RegisterNoResponder(responder) +} diff --git a/vendor/gopkg.in/jarcoal/httpmock.v1/transport_test.go b/vendor/gopkg.in/jarcoal/httpmock.v1/transport_test.go new file mode 100644 index 000000000..5f24ec1fb --- /dev/null +++ b/vendor/gopkg.in/jarcoal/httpmock.v1/transport_test.go @@ -0,0 +1,352 @@ +package httpmock + +import ( + "bytes" + "encoding/json" + "errors" + "io/ioutil" + "net" + "net/http" + "net/url" + "reflect" + "strings" + "testing" + "time" +) + +var testUrl = "http://www.example.com/" + +func assertBody(t *testing.T, resp *http.Response, expected string) { + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + got := string(data) + + if got != expected { + t.Errorf("Expected body: %#v, got %#v", expected, got) + } +} + +func TestMockTransport(t *testing.T) { + Activate() + defer Deactivate() + + url := "https://github.com/" + body := "hello world" + + RegisterResponder("GET", url, NewStringResponder(200, body)) + + resp, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != body { + t.FailNow() + } + + // the http client wraps our NoResponderFound error, so we just try and match on text + if _, err := http.Get(testUrl); !strings.Contains(err.Error(), + NoResponderFound.Error()) { + + t.Fatal(err) + } +} + +func TestMockTransportReset(t *testing.T) { + DeactivateAndReset() + + if len(DefaultTransport.responders) > 0 { + t.Fatal("expected no responders at this point") + } + + RegisterResponder("GET", testUrl, nil) + + if len(DefaultTransport.responders) != 1 { + t.Fatal("expected one responder") + } + + Reset() + + if len(DefaultTransport.responders) > 0 { + t.Fatal("expected no responders as they were just reset") + } +} + +func TestMockTransportNoResponder(t *testing.T) { + Activate() + defer DeactivateAndReset() + + Reset() + + if DefaultTransport.noResponder != nil { + t.Fatal("expected noResponder to be nil") + } + + if _, err := http.Get(testUrl); err == nil { + t.Fatal("expected to receive a connection error due to lack of responders") + } + + RegisterNoResponder(NewStringResponder(200, "hello world")) + + resp, err := http.Get(testUrl) + if err != nil { + t.Fatal("expected request to succeed") + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != "hello world" { + t.Fatal("expected body to be 'hello world'") + } +} + +func TestMockTransportQuerystringFallback(t *testing.T) { + Activate() + defer DeactivateAndReset() + + // register the testUrl responder + RegisterResponder("GET", testUrl, NewStringResponder(200, "hello world")) + + // make a request for the testUrl with a querystring + resp, err := http.Get(testUrl + "?hello=world") + if err != nil { + t.Fatal("expected request to succeed") + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != "hello world" { + t.Fatal("expected body to be 'hello world'") + } +} + +type dummyTripper struct{} + +func (d *dummyTripper) RoundTrip(*http.Request) (*http.Response, error) { + return nil, nil +} + +func TestMockTransportInitialTransport(t *testing.T) { + DeactivateAndReset() + + tripper := &dummyTripper{} + http.DefaultTransport = tripper + + Activate() + + if http.DefaultTransport == tripper { + t.Fatal("expected http.DefaultTransport to be a mock transport") + } + + Deactivate() + + if http.DefaultTransport != tripper { + t.Fatal("expected http.DefaultTransport to be dummy") + } +} + +func TestMockTransportNonDefault(t *testing.T) { + // create a custom http client w/ custom Roundtripper + client := &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 60 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 60 * time.Second, + }, + } + + // activate mocks for the client + ActivateNonDefault(client) + defer DeactivateAndReset() + + body := "hello world!" + + RegisterResponder("GET", testUrl, NewStringResponder(200, body)) + + req, err := http.NewRequest("GET", testUrl, nil) + if err != nil { + t.Fatal(err) + } + + resp, err := client.Do(req) + if err != nil { + t.Fatal(err) + } + + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + + if string(data) != body { + t.FailNow() + } +} + +func TestMockTransportRespectsCancel(t *testing.T) { + Activate() + defer DeactivateAndReset() + + cases := []struct { + withCancel bool + cancelNow bool + withPanic bool + expectedBody string + expectedErr error + }{ + // No cancel specified at all. Falls back to normal behavior + {false, false, false, "hello world", nil}, + + // Cancel returns error + {true, true, false, "", errors.New("request canceled")}, + + // Request can be cancelled but it is not cancelled. + {true, false, false, "hello world", nil}, + + // Panic in cancelled request is handled + {true, false, true, "", errors.New(`panic in responder: got "oh no"`)}, + } + + for _, c := range cases { + Reset() + if c.withPanic { + RegisterResponder("GET", testUrl, func(r *http.Request) (*http.Response, error) { + time.Sleep(time.Millisecond) + panic("oh no") + }) + } else { + RegisterResponder("GET", testUrl, func(r *http.Request) (*http.Response, error) { + time.Sleep(time.Millisecond) + return NewStringResponse(http.StatusOK, "hello world"), nil + }) + } + + req, err := http.NewRequest("GET", testUrl, nil) + if err != nil { + t.Fatal(err) + } + if c.withCancel { + cancel := make(chan struct{}, 1) + req.Cancel = cancel + if c.cancelNow { + cancel <- struct{}{} + } + } + + resp, err := http.DefaultClient.Do(req) + + // If we expect and error but none was returned, it's fatal for this test... + if err == nil && c.expectedErr != nil { + t.Fatal("Error should not be nil") + } + + if err != nil { + got := err.(*url.Error) + if !reflect.DeepEqual(got.Err, c.expectedErr) { + t.Errorf("Expected: %#v, got: %#v", c.expectedErr, got.Err) + } + } + + if c.expectedBody != "" { + assertBody(t, resp, c.expectedBody) + } + } +} + +func TestMockTransportRespectsTimeout(t *testing.T) { + timeout := time.Millisecond + client := &http.Client{ + Timeout: timeout, + } + + ActivateNonDefault(client) + defer DeactivateAndReset() + + RegisterResponder( + "GET", testUrl, + func(r *http.Request) (*http.Response, error) { + time.Sleep(2 * timeout) + return NewStringResponse(http.StatusOK, ""), nil + }, + ) + + _, err := client.Get(testUrl) + if err == nil { + t.Fail() + } +} + +func TestMockTransportCallCount(t *testing.T) { + Reset() + Activate() + defer Deactivate() + + url := "https://github.com/" + url2 := "https://gitlab.com/" + + RegisterResponder("GET", url, NewStringResponder(200, "body")) + RegisterResponder("POST", url2, NewStringResponder(200, "body")) + + _, err := http.Get(url) + if err != nil { + t.Fatal(err) + } + + buff := new(bytes.Buffer) + json.NewEncoder(buff).Encode("{}") + _, err1 := http.Post(url2, "application/json", buff) + if err1 != nil { + t.Fatal(err1) + } + + _, err2 := http.Get(url) + if err2 != nil { + t.Fatal(err2) + } + + totalCallCount := GetTotalCallCount() + if totalCallCount != 3 { + t.Fatalf("did not track the total count of calls correctly. expected it to be 3, but it was %v", totalCallCount) + } + + info := GetCallCountInfo() + expectedInfo := map[string]int{} + urlCallkey := "GET " + url + url2Callkey := "POST " + url2 + expectedInfo[urlCallkey] = 2 + expectedInfo[url2Callkey] = 1 + + if !reflect.DeepEqual(info, expectedInfo) { + t.Fatalf("did not correctly track the call count info. expected it to be \n %+v \n but it was \n %+v \n", expectedInfo, info) + } + + Reset() + + afterResetTotalCallCount := GetTotalCallCount() + if afterResetTotalCallCount != 0 { + t.Fatalf("did not reset the total count of calls correctly. expected it to be 0 after reset, but it was %v", afterResetTotalCallCount) + } + +}