From 7d1c7924f2899a02eca7933b15fee6392ecfe553 Mon Sep 17 00:00:00 2001 From: Murat Kabilov Date: Fri, 9 Jun 2017 11:34:08 +0200 Subject: [PATCH] test http client close --- pkg/spec/postgresql_test.go | 20 +++++++------- pkg/spec/types.go | 2 -- pkg/util/teams/teams.go | 52 ++++++++++++++++++++++------------- pkg/util/teams/teams_test.go | 53 +++++++++++++++++++++++++++++++++++- pkg/util/util_test.go | 9 ------ 5 files changed, 95 insertions(+), 41 deletions(-) diff --git a/pkg/spec/postgresql_test.go b/pkg/spec/postgresql_test.go index 48314d376..fd5929d68 100644 --- a/pkg/spec/postgresql_test.go +++ b/pkg/spec/postgresql_test.go @@ -223,7 +223,7 @@ var unmarshalCluster = []struct { TeamID: "ACID", AllowedSourceRanges: []string{"127.0.0.1/32"}, NumberOfInstances: 2, - Users: map[string]UserFlags{"zalando": {"superuser", "createdb"}}, + Users: map[string]userFlags{"zalando": {"superuser", "createdb"}}, MaintenanceWindows: []MaintenanceWindow{{ Everyday: false, Weekday: time.Monday, @@ -237,7 +237,7 @@ var unmarshalCluster = []struct { }, { Everyday: true, - Weekday: time.Sunday, + Weekday: time.Sunday, StartTime: mustParseTime("05:00"), EndTime: mustParseTime("05:15"), }, @@ -263,13 +263,13 @@ var unmarshalCluster = []struct { }, []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"teapot-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"","parameters":null},"volume":{"size":"","storageClass":""},"patroni":{"initdb":null,"pg_hba":null,"ttl":0,"loop_wait":0,"retry_timeout":0,"maximum_lag_on_failover":0},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null},"status":"Invalid"}`), nil}, {[]byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1"`), - Postgresql{}, - []byte{}, - errors.New("unexpected end of JSON input")}, + Postgresql{}, + []byte{}, + errors.New("unexpected end of JSON input")}, {[]byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster","creationTimestamp":qaz},"spec":{"postgresql":{"version":"","parameters":null},"volume":{"size":"","storageClass":""},"patroni":{"initdb":null,"pg_hba":null,"ttl":0,"loop_wait":0,"retry_timeout":0,"maximum_lag_on_failover":0},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null},"status":"Invalid"}`), - Postgresql{}, - []byte{}, - errors.New("invalid character 'q' looking for beginning of value")}} + Postgresql{}, + []byte{}, + errors.New("invalid character 'q' looking for beginning of value")}} var postgresqlList = []struct { in []byte @@ -309,8 +309,8 @@ var postgresqlList = []struct { }, nil}, {[]byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace"`), - PostgresqlList{}, - errors.New("unexpected end of JSON input")}} + PostgresqlList{}, + errors.New("unexpected end of JSON input")}} func mustParseTime(s string) time.Time { v, err := time.Parse("15:04", s) diff --git a/pkg/spec/types.go b/pkg/spec/types.go index dd1636529..822395ce9 100644 --- a/pkg/spec/types.go +++ b/pkg/spec/types.go @@ -4,8 +4,6 @@ import ( "fmt" "strings" "database/sql" - "fmt" - "strings" "k8s.io/client-go/pkg/api/v1" "k8s.io/client-go/pkg/types" diff --git a/pkg/util/teams/teams.go b/pkg/util/teams/teams.go index b00e46271..b3d80349c 100644 --- a/pkg/util/teams/teams.go +++ b/pkg/util/teams/teams.go @@ -39,11 +39,14 @@ type team struct { InfrastructureAccounts []infrastructureAccount `json:"infrastructure-accounts"` } -// +type httpClient interface { + Do(req *http.Request) (*http.Response, error) +} + type API struct { - url string - httpClient *http.Client - logger *logrus.Entry + httpClient + url string + logger *logrus.Entry } // NewTeamsAPI creates an object to query the team API. @@ -58,23 +61,28 @@ func NewTeamsAPI(url string, log *logrus.Logger) *API { } // TeamInfo returns information about a given team using its ID and a token to authenticate to the API service. -func (t *API) TeamInfo(teamID, token string) (tm *team, er error) { +func (t *API) TeamInfo(teamID, token string) (tm *team, err error) { + var ( + req *http.Request + resp *http.Response + ) + url := fmt.Sprintf("%s/teams/%s", t.url, teamID) t.logger.Debugf("Request url: %s", url) - req, err := http.NewRequest("GET", url, nil) + req, err = http.NewRequest("GET", url, nil) if err != nil { - return nil, err + return } req.Header.Add("Authorization", "Bearer "+token) - resp, err := t.httpClient.Do(req) + resp, err = t.httpClient.Do(req) if err != nil { - return nil, err + return } defer func() { - if err:= resp.Body.Close(); err != nil { - er = fmt.Errorf("error when closing response; %v", err) - tm = nil + closeErr := resp.Body.Close() + if closeErr != nil { + err = fmt.Errorf("error when closing response: %v", closeErr) } }() if resp.StatusCode != 200 { @@ -82,21 +90,27 @@ func (t *API) TeamInfo(teamID, token string) (tm *team, er error) { d := json.NewDecoder(resp.Body) err = d.Decode(&raw) if err != nil { - return nil, fmt.Errorf("team API query failed with status code %d and malformed response: %v", resp.StatusCode, err) + err = fmt.Errorf("team API query failed with status code %d and malformed response: %v", resp.StatusCode, err) + return } if errMessage, ok := raw["error"]; ok { - return nil, fmt.Errorf("team API query failed with status code %d and message: '%v'", resp.StatusCode, string(errMessage)) + err = fmt.Errorf("team API query failed with status code %d and message: '%v'", resp.StatusCode, string(errMessage)) + return } + err = fmt.Errorf("team API query failed with status code %d", resp.StatusCode) - return nil, fmt.Errorf("team API query failed with status code %d", resp.StatusCode) + return } - teamInfo := &team{} + + tm = &team{} d := json.NewDecoder(resp.Body) - err = d.Decode(teamInfo) + err = d.Decode(tm) if err != nil { - return nil, fmt.Errorf("could not parse team API response: %v", err) + err = fmt.Errorf("could not parse team API response: %v", err) + tm = nil + return } - return teamInfo, nil + return } diff --git a/pkg/util/teams/teams_test.go b/pkg/util/teams/teams_test.go index eac29a5d3..ee8c8e5b4 100644 --- a/pkg/util/teams/teams_test.go +++ b/pkg/util/teams/teams_test.go @@ -2,11 +2,12 @@ package teams import ( "fmt" - "github.com/Sirupsen/logrus" "net/http" "net/http/httptest" "reflect" "testing" + + "github.com/Sirupsen/logrus" ) var ( @@ -168,6 +169,56 @@ func TestInfo(t *testing.T) { } } +type mockHttpClient struct { +} + +type mockBody struct { +} + +func (b *mockBody) Read(p []byte) (n int, err error) { + return 2, nil +} + +func (b *mockBody) Close() error { + return fmt.Errorf("close error") +} + +func (c *mockHttpClient) Do(req *http.Request) (*http.Response, error) { + fmt.Printf("do request: %v", *req) + + resp := http.Response{ + Status: "200 OK", + StatusCode: 200, + ContentLength: 2, + Close: false, + Request: req, + } + resp.Body = &mockBody{} + + return &resp, nil +} + +func TestHttpClientClose(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("Authorization") != "Bearer "+token { + t.Errorf("Authorization token is wrong or not provided") + } + w.WriteHeader(200) + if _, err := fmt.Fprint(w, "{}"); err != nil { + t.Errorf("Error writing teams api response %v", err) + } + })) + + api := NewTeamsAPI(ts.URL, logger) + api.httpClient = &mockHttpClient{} + + _, err := api.TeamInfo("acid", token) + expError := fmt.Errorf("error when closing response: close error") + if err.Error() != expError.Error() { + t.Errorf("Expected error: %v, got: %v", expError, err) + } +} + func TestRequest(t *testing.T) { for _, tc := range requestsURLtc { api := NewTeamsAPI(tc.url, logger) diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index ddf42760f..189addddb 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -1,7 +1,6 @@ package util import ( - "fmt" "reflect" "testing" @@ -86,14 +85,6 @@ func TestPGUserPassword(t *testing.T) { } } -func TestPretty(t *testing.T) { - for _, tt := range prettyTest { - if actual := Pretty(tt.in); fmt.Sprintf("%v", actual) != tt.out { - t.Errorf("Pretty expected: %s, got: %s", tt.out, actual) - } - } -} - func TestPrettyDiff(t *testing.T) { for _, tt := range prettyDiffTest { if actual := PrettyDiff(tt.inA, tt.inB); actual != tt.out {