test http client close
This commit is contained in:
parent
80038239f7
commit
7d1c7924f2
|
|
@ -223,7 +223,7 @@ var unmarshalCluster = []struct {
|
||||||
TeamID: "ACID",
|
TeamID: "ACID",
|
||||||
AllowedSourceRanges: []string{"127.0.0.1/32"},
|
AllowedSourceRanges: []string{"127.0.0.1/32"},
|
||||||
NumberOfInstances: 2,
|
NumberOfInstances: 2,
|
||||||
Users: map[string]UserFlags{"zalando": {"superuser", "createdb"}},
|
Users: map[string]userFlags{"zalando": {"superuser", "createdb"}},
|
||||||
MaintenanceWindows: []MaintenanceWindow{{
|
MaintenanceWindows: []MaintenanceWindow{{
|
||||||
Everyday: false,
|
Everyday: false,
|
||||||
Weekday: time.Monday,
|
Weekday: time.Monday,
|
||||||
|
|
@ -237,7 +237,7 @@ var unmarshalCluster = []struct {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Everyday: true,
|
Everyday: true,
|
||||||
Weekday: time.Sunday,
|
Weekday: time.Sunday,
|
||||||
StartTime: mustParseTime("05:00"),
|
StartTime: mustParseTime("05:00"),
|
||||||
EndTime: mustParseTime("05:15"),
|
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","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"`),
|
{[]byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1"`),
|
||||||
Postgresql{},
|
Postgresql{},
|
||||||
[]byte{},
|
[]byte{},
|
||||||
errors.New("unexpected end of JSON input")},
|
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"}`),
|
{[]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{},
|
Postgresql{},
|
||||||
[]byte{},
|
[]byte{},
|
||||||
errors.New("invalid character 'q' looking for beginning of value")}}
|
errors.New("invalid character 'q' looking for beginning of value")}}
|
||||||
|
|
||||||
var postgresqlList = []struct {
|
var postgresqlList = []struct {
|
||||||
in []byte
|
in []byte
|
||||||
|
|
@ -309,8 +309,8 @@ var postgresqlList = []struct {
|
||||||
},
|
},
|
||||||
nil},
|
nil},
|
||||||
{[]byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace"`),
|
{[]byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace"`),
|
||||||
PostgresqlList{},
|
PostgresqlList{},
|
||||||
errors.New("unexpected end of JSON input")}}
|
errors.New("unexpected end of JSON input")}}
|
||||||
|
|
||||||
func mustParseTime(s string) time.Time {
|
func mustParseTime(s string) time.Time {
|
||||||
v, err := time.Parse("15:04", s)
|
v, err := time.Parse("15:04", s)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
"k8s.io/client-go/pkg/types"
|
"k8s.io/client-go/pkg/types"
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,14 @@ type team struct {
|
||||||
InfrastructureAccounts []infrastructureAccount `json:"infrastructure-accounts"`
|
InfrastructureAccounts []infrastructureAccount `json:"infrastructure-accounts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
type httpClient interface {
|
||||||
|
Do(req *http.Request) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
url string
|
httpClient
|
||||||
httpClient *http.Client
|
url string
|
||||||
logger *logrus.Entry
|
logger *logrus.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTeamsAPI creates an object to query the team API.
|
// 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.
|
// 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)
|
url := fmt.Sprintf("%s/teams/%s", t.url, teamID)
|
||||||
t.logger.Debugf("Request url: %s", url)
|
t.logger.Debugf("Request url: %s", url)
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
req, err = http.NewRequest("GET", url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("Authorization", "Bearer "+token)
|
req.Header.Add("Authorization", "Bearer "+token)
|
||||||
resp, err := t.httpClient.Do(req)
|
resp, err = t.httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err:= resp.Body.Close(); err != nil {
|
closeErr := resp.Body.Close()
|
||||||
er = fmt.Errorf("error when closing response; %v", err)
|
if closeErr != nil {
|
||||||
tm = nil
|
err = fmt.Errorf("error when closing response: %v", closeErr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
|
|
@ -82,21 +90,27 @@ func (t *API) TeamInfo(teamID, token string) (tm *team, er error) {
|
||||||
d := json.NewDecoder(resp.Body)
|
d := json.NewDecoder(resp.Body)
|
||||||
err = d.Decode(&raw)
|
err = d.Decode(&raw)
|
||||||
if err != nil {
|
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 {
|
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)
|
d := json.NewDecoder(resp.Body)
|
||||||
err = d.Decode(teamInfo)
|
err = d.Decode(tm)
|
||||||
if err != nil {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ package teams
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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) {
|
func TestRequest(t *testing.T) {
|
||||||
for _, tc := range requestsURLtc {
|
for _, tc := range requestsURLtc {
|
||||||
api := NewTeamsAPI(tc.url, logger)
|
api := NewTeamsAPI(tc.url, logger)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"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) {
|
func TestPrettyDiff(t *testing.T) {
|
||||||
for _, tt := range prettyDiffTest {
|
for _, tt := range prettyDiffTest {
|
||||||
if actual := PrettyDiff(tt.inA, tt.inB); actual != tt.out {
|
if actual := PrettyDiff(tt.inA, tt.inB); actual != tt.out {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue