add test team member (#1842)
* return err if teams API fails with StatusCode other than 404 * add unit test for 404 at team members Co-authored-by: Jociele Padilha <jociele.padilha@zalando.de> Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
		
							parent
							
								
									9bcb25ac7e
								
							
						
					
					
						commit
						483bf624ee
					
				|  | @ -194,8 +194,8 @@ type mockTeamsAPIClient struct { | |||
| 	members []string | ||||
| } | ||||
| 
 | ||||
| func (m *mockTeamsAPIClient) TeamInfo(teamID, token string) (tm *teams.Team, err error) { | ||||
| 	return &teams.Team{Members: m.members}, nil | ||||
| func (m *mockTeamsAPIClient) TeamInfo(teamID, token string) (tm *teams.Team, statusCode int, err error) { | ||||
| 	return &teams.Team{Members: m.members}, statusCode, nil | ||||
| } | ||||
| 
 | ||||
| func (m *mockTeamsAPIClient) setMembers(members []string) { | ||||
|  | @ -260,15 +260,15 @@ type mockTeamsAPIClientMultipleTeams struct { | |||
| 	teams []mockTeam | ||||
| } | ||||
| 
 | ||||
| func (m *mockTeamsAPIClientMultipleTeams) TeamInfo(teamID, token string) (tm *teams.Team, err error) { | ||||
| func (m *mockTeamsAPIClientMultipleTeams) TeamInfo(teamID, token string) (tm *teams.Team, statusCode int, err error) { | ||||
| 	for _, team := range m.teams { | ||||
| 		if team.teamID == teamID { | ||||
| 			return &teams.Team{Members: team.members}, nil | ||||
| 			return &teams.Team{Members: team.members}, statusCode, nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// should not be reached if a slice with teams is populated correctly
 | ||||
| 	return nil, nil | ||||
| 	return nil, statusCode, nil | ||||
| } | ||||
| 
 | ||||
| // Test adding members of maintenance teams that get superuser rights for all PG databases
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ import ( | |||
| 	"encoding/gob" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
|  | @ -272,9 +273,14 @@ func (c *Cluster) getTeamMembers(teamID string) ([]string, error) { | |||
| 		return nil, fmt.Errorf("could not get oauth token to authenticate to team service API: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	teamInfo, err := c.teamsAPIClient.TeamInfo(teamID, token) | ||||
| 	teamInfo, statusCode, err := c.teamsAPIClient.TeamInfo(teamID, token) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		c.logger.Warningf("could not get team info for team %q: %v", teamID, err) | ||||
| 		if statusCode == http.StatusNotFound { | ||||
| 			c.logger.Warningf("could not get team info for team %q: %v", teamID, err) | ||||
| 		} else { | ||||
| 			return nil, fmt.Errorf("could not get team info for team %q: %v", teamID, err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		for _, member := range teamInfo.Members { | ||||
| 			if !(util.SliceContains(members, member)) { | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ type httpClient interface { | |||
| 
 | ||||
| // Interface to the TeamsAPIClient
 | ||||
| type Interface interface { | ||||
| 	TeamInfo(teamID, token string) (tm *Team, err error) | ||||
| 	TeamInfo(teamID, token string) (tm *Team, statusCode int, err error) | ||||
| } | ||||
| 
 | ||||
| // API describes teams API
 | ||||
|  | @ -67,7 +67,7 @@ func NewTeamsAPI(url string, log *logrus.Entry) *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, err error) { | ||||
| func (t *API) TeamInfo(teamID, token string) (tm *Team, statusCode int, err error) { | ||||
| 	var ( | ||||
| 		req  *http.Request | ||||
| 		resp *http.Response | ||||
|  | @ -77,37 +77,38 @@ func (t *API) TeamInfo(teamID, token string) (tm *Team, err error) { | |||
| 	t.logger.Debugf("request url: %s", url) | ||||
| 	req, err = http.NewRequest("GET", url, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return nil, http.StatusBadRequest, err | ||||
| 	} | ||||
| 
 | ||||
| 	req.Header.Add("Authorization", "Bearer "+token) | ||||
| 	if resp, err = t.httpClient.Do(req); err != nil { | ||||
| 		return nil, err | ||||
| 		return nil, http.StatusUnauthorized, err | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		if closeErr := resp.Body.Close(); closeErr != nil { | ||||
| 			err = fmt.Errorf("error when closing response: %v", closeErr) | ||||
| 		} | ||||
| 	}() | ||||
| 	if resp.StatusCode != 200 { | ||||
| 	statusCode = resp.StatusCode | ||||
| 	if statusCode != http.StatusOK { | ||||
| 		var raw map[string]json.RawMessage | ||||
| 		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) | ||||
| 			return nil, statusCode, fmt.Errorf("team API query failed with status code %d and malformed response: %v", statusCode, err) | ||||
| 		} | ||||
| 
 | ||||
| 		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)) | ||||
| 			return nil, statusCode, fmt.Errorf("team API query failed with status code %d and message: '%v'", statusCode, string(errMessage)) | ||||
| 		} | ||||
| 		return nil, fmt.Errorf("team API query failed with status code %d", resp.StatusCode) | ||||
| 		return nil, statusCode, fmt.Errorf("team API query failed with status code %d", statusCode) | ||||
| 	} | ||||
| 
 | ||||
| 	tm = &Team{} | ||||
| 	d := json.NewDecoder(resp.Body) | ||||
| 	if err = d.Decode(tm); err != nil { | ||||
| 		return nil, fmt.Errorf("could not parse team API response: %v", err) | ||||
| 		return nil, statusCode, fmt.Errorf("could not parse team API response: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return tm, nil | ||||
| 	return tm, statusCode, nil | ||||
| } | ||||
|  |  | |||
|  | @ -13,60 +13,63 @@ import ( | |||
| var ( | ||||
| 	logger = logrus.New().WithField("pkg", "teamsapi") | ||||
| 	token  = "ec45b1cfbe7100c6315d183a3eb6cec0M2U1LWJkMzEtZDgzNzNmZGQyNGM3IiwiYXV0aF90aW1lIjoxNDkzNzMwNzQ1LCJpc3MiOiJodHRwcz" | ||||
| 	input  = `{ | ||||
| 	"dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
| 	"id": "acid", | ||||
| 	"id_name": "acid", | ||||
| 	"team_id": "111222", | ||||
| 	"type": "official", | ||||
| 	"name": "Acid team name", | ||||
| 	"mail": [ | ||||
| 	"email1@example.com", | ||||
| 	"email2@example.com" | ||||
| 	], | ||||
| 	"alias": [ | ||||
| 	"acid" | ||||
| 	], | ||||
| 	"member": [ | ||||
| 	  "member1", | ||||
| 	  "member2", | ||||
| 	  "member3" | ||||
| 	], | ||||
| 	"infrastructure-accounts": [ | ||||
| 	{ | ||||
| 	  "id": "1234512345", | ||||
| 	  "name": "acid", | ||||
| 	  "provider": "aws", | ||||
| 	  "type": "aws", | ||||
| 	  "description": "", | ||||
| 	  "owner": "acid", | ||||
| 	  "owner_dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
| 	  "disabled": false | ||||
| 	}, | ||||
| 	{ | ||||
| 	  "id": "5432154321", | ||||
| 	  "name": "db", | ||||
| 	  "provider": "aws", | ||||
| 	  "type": "aws", | ||||
| 	  "description": "", | ||||
| 	  "owner": "acid", | ||||
| 	  "owner_dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
| 	  "disabled": false | ||||
| 	} | ||||
| 	], | ||||
| 	"cost_center": "00099999", | ||||
| 	"delivery_lead": "member4", | ||||
| 	"parent_team_id": "111221" | ||||
| 	}` | ||||
| ) | ||||
| 
 | ||||
| var teamsAPItc = []struct { | ||||
| 	in     string | ||||
| 	inCode int | ||||
| 	inTeam string | ||||
| 	out    *Team | ||||
| 	err    error | ||||
| }{ | ||||
| 	{`{ | ||||
| "dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
| "id": "acid", | ||||
| "id_name": "acid", | ||||
| "team_id": "111222", | ||||
| "type": "official", | ||||
| "name": "Acid team name", | ||||
| "mail": [ | ||||
| "email1@example.com", | ||||
| "email2@example.com" | ||||
| ], | ||||
| "alias": [ | ||||
| "acid" | ||||
| ], | ||||
| "member": [ | ||||
|   "member1", | ||||
|   "member2", | ||||
|   "member3" | ||||
| ], | ||||
| "infrastructure-accounts": [ | ||||
| { | ||||
|   "id": "1234512345", | ||||
|   "name": "acid", | ||||
|   "provider": "aws", | ||||
|   "type": "aws", | ||||
|   "description": "", | ||||
|   "owner": "acid", | ||||
|   "owner_dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
|   "disabled": false | ||||
| }, | ||||
| { | ||||
|   "id": "5432154321", | ||||
|   "name": "db", | ||||
|   "provider": "aws", | ||||
|   "type": "aws", | ||||
|   "description": "", | ||||
|   "owner": "acid", | ||||
|   "owner_dn": "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
|   "disabled": false | ||||
| } | ||||
| ], | ||||
| "cost_center": "00099999", | ||||
| "delivery_lead": "member4", | ||||
| "parent_team_id": "111221" | ||||
| }`, | ||||
| 	{ | ||||
| 		input, | ||||
| 		200, | ||||
| 		"acid", | ||||
| 		&Team{ | ||||
| 			Dn:           "cn=100100,ou=official,ou=foobar,dc=zalando,dc=net", | ||||
| 			ID:           "acid", | ||||
|  | @ -104,27 +107,38 @@ var teamsAPItc = []struct { | |||
| 		nil}, { | ||||
| 		`{"error": "Access Token not valid"}`, | ||||
| 		401, | ||||
| 		"acid", | ||||
| 		nil, | ||||
| 		fmt.Errorf(`team API query failed with status code 401 and message: '"Access Token not valid"'`), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{"status": "I'm a teapot'"}`, | ||||
| 		418, | ||||
| 		"acid", | ||||
| 		nil, | ||||
| 		fmt.Errorf(`team API query failed with status code 418`), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{"status": "I'm a teapot`, | ||||
| 		418, | ||||
| 		"acid", | ||||
| 		nil, | ||||
| 		fmt.Errorf(`team API query failed with status code 418 and malformed response: unexpected EOF`), | ||||
| 	}, | ||||
| 	{ | ||||
| 		`{"status": "I'm a teapot`, | ||||
| 		200, | ||||
| 		"acid", | ||||
| 		nil, | ||||
| 		fmt.Errorf(`could not parse team API response: unexpected EOF`), | ||||
| 	}, | ||||
| 	{ | ||||
| 		input, | ||||
| 		404, | ||||
| 		"banana", | ||||
| 		nil, | ||||
| 		fmt.Errorf(`team API query failed with status code 404`), | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var requestsURLtc = []struct { | ||||
|  | @ -156,7 +170,7 @@ func TestInfo(t *testing.T) { | |||
| 			defer ts.Close() | ||||
| 			api := NewTeamsAPI(ts.URL, logger) | ||||
| 
 | ||||
| 			actual, err := api.TeamInfo("acid", token) | ||||
| 			actual, statusCode, err := api.TeamInfo(tc.inTeam, token) | ||||
| 			if err != nil && err.Error() != tc.err.Error() { | ||||
| 				t.Errorf("expected error: %v, got: %v", tc.err, err) | ||||
| 				return | ||||
|  | @ -165,6 +179,10 @@ func TestInfo(t *testing.T) { | |||
| 			if !reflect.DeepEqual(actual, tc.out) { | ||||
| 				t.Errorf("expected %#v, got: %#v", tc.out, actual) | ||||
| 			} | ||||
| 
 | ||||
| 			if statusCode != tc.inCode { | ||||
| 				t.Errorf("expected %d, got: %d", tc.inCode, statusCode) | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| } | ||||
|  | @ -202,7 +220,7 @@ func TestHttpClientClose(t *testing.T) { | |||
| 	api := NewTeamsAPI(ts.URL, logger) | ||||
| 	api.httpClient = &mockHTTPClient{} | ||||
| 
 | ||||
| 	_, err := api.TeamInfo("acid", token) | ||||
| 	_, _, 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) | ||||
|  | @ -212,7 +230,7 @@ func TestHttpClientClose(t *testing.T) { | |||
| func TestRequest(t *testing.T) { | ||||
| 	for _, tc := range requestsURLtc { | ||||
| 		api := NewTeamsAPI(tc.url, logger) | ||||
| 		resp, err := api.TeamInfo("acid", token) | ||||
| 		resp, _, err := api.TeamInfo("acid", token) | ||||
| 		if resp != nil { | ||||
| 			t.Errorf("response expected to be nil") | ||||
| 			continue | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue