diff --git a/tests/apitests/api-testing/client/harbor_api_client.go b/tests/apitests/api-testing/client/harbor_api_client.go index bc87576ba..7f392be24 100644 --- a/tests/apitests/api-testing/client/harbor_api_client.go +++ b/tests/apitests/api-testing/client/harbor_api_client.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "errors" + "fmt" "io/ioutil" "net/http" "net/url" @@ -135,6 +136,10 @@ func (ac *APIClient) Post(url string, data []byte) error { if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK { + if err := getErrorMessage(resp); err != nil { + return fmt.Errorf("%s:%s", resp.Status, err.Error()) + } + return errors.New(resp.Status) } @@ -161,6 +166,10 @@ func (ac *APIClient) Delete(url string) error { } if resp.StatusCode != http.StatusOK { + if err := getErrorMessage(resp); err != nil { + return fmt.Errorf("%s:%s", resp.Status, err.Error()) + } + return errors.New(resp.Status) } @@ -177,3 +186,25 @@ func (ac *APIClient) SwitchAccount(username, password string) { ac.config.Username = username ac.config.Password = password } + +//Read error message from response body +func getErrorMessage(resp *http.Response) error { + if resp == nil { + return errors.New("nil response") + } + + if resp.Body == nil || resp.ContentLength == 0 { + //nothing to read + return nil + } + + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + //abandon to read deatiled error message + return nil + } + + return fmt.Errorf("%s", data) +} diff --git a/tests/apitests/api-testing/lib/project.go b/tests/apitests/api-testing/lib/project.go index c00d3e836..e9cdbb9a1 100644 --- a/tests/apitests/api-testing/lib/project.go +++ b/tests/apitests/api-testing/lib/project.go @@ -88,11 +88,8 @@ func (pu *ProjectUtil) CreateProject(projectName string, accessLevel bool) error } url := pu.rootURI + "/api/projects" - if err = pu.testingClient.Post(url, body); err != nil { - return err - } - return nil + return pu.testingClient.Post(url, body) } //DeleteProject : Delete project @@ -108,11 +105,7 @@ func (pu *ProjectUtil) DeleteProject(projectName string) error { url := fmt.Sprintf("%s%s%d", pu.rootURI, "/api/projects/", pid) - if err := pu.testingClient.Delete(url); err != nil { - return err - } - - return nil + return pu.testingClient.Delete(url) } //AssignRole : Assign role to user @@ -128,8 +121,10 @@ func (pu *ProjectUtil) AssignRole(projectName, username string) error { } m := models.Member{ - UserName: username, - Roles: []int{2}, + RoleID: 2, + Member: &models.MemberUser{ + Username: username, + }, } body, err := json.Marshal(&m) @@ -138,20 +133,17 @@ func (pu *ProjectUtil) AssignRole(projectName, username string) error { } url := fmt.Sprintf("%s%s%d%s", pu.rootURI, "/api/projects/", pid, "/members") - if err := pu.testingClient.Post(url, body); err != nil { - return err - } - return nil + return pu.testingClient.Post(url, body) } //RevokeRole : RevokeRole role from user -func (pu *ProjectUtil) RevokeRole(projectName string, uid int) error { +func (pu *ProjectUtil) RevokeRole(projectName string, username string) error { if len(strings.TrimSpace(projectName)) == 0 { return errors.New("Project name is required for revoking role") } - if uid == 0 { + if len(strings.TrimSpace(username)) == 0 { return errors.New("User ID is required for revoking role") } @@ -160,10 +152,42 @@ func (pu *ProjectUtil) RevokeRole(projectName string, uid int) error { return fmt.Errorf("Failed to get project ID with name %s", projectName) } - url := fmt.Sprintf("%s%s%d%s%d", pu.rootURI, "/api/projects/", pid, "/members/", uid) - if err := pu.testingClient.Delete(url); err != nil { + m, err := pu.GetProjectMember(pid, username) + if err != nil { return err } - return nil + url := fmt.Sprintf("%s%s%d%s%d", pu.rootURI, "/api/projects/", pid, "/members/", m.MID) + + return pu.testingClient.Delete(url) +} + +//GetProjectMember : Get the project member by name +func (pu *ProjectUtil) GetProjectMember(pid int, member string) (*models.ExistingMember, error) { + if pid == 0 { + return nil, errors.New("invalid project ID") + } + + if len(strings.TrimSpace(member)) == 0 { + return nil, errors.New("empty member name") + } + + url := fmt.Sprintf("%s/api/projects/%d/members", pu.rootURI, pid) + data, err := pu.testingClient.Get(url) + if err != nil { + return nil, err + } + + members := []*models.ExistingMember{} + if err := json.Unmarshal(data, &members); err != nil { + return nil, err + } + + for _, m := range members { + if m.Name == member { + return m, nil + } + } + + return nil, fmt.Errorf("no member found by the name '%s'", member) } diff --git a/tests/apitests/api-testing/lib/report.go b/tests/apitests/api-testing/lib/report.go index abda88a5f..6b39a552c 100644 --- a/tests/apitests/api-testing/lib/report.go +++ b/tests/apitests/api-testing/lib/report.go @@ -16,7 +16,11 @@ func (r *Report) Passed(caseName string) { //Failed case func (r *Report) Failed(caseName string, err error) { - r.failed = append(r.failed, fmt.Sprintf("%s: [%s] %s", caseName, "FAILED", err.Error())) + errMsg := "" + if err != nil { + errMsg = err.Error() + } + r.failed = append(r.failed, fmt.Sprintf("%s: [%s] %s", caseName, "FAILED", errMsg)) } //Print report diff --git a/tests/apitests/api-testing/models/member.go b/tests/apitests/api-testing/models/member.go index 3d7983afe..e39d3731a 100644 --- a/tests/apitests/api-testing/models/member.go +++ b/tests/apitests/api-testing/models/member.go @@ -2,6 +2,18 @@ package models //Member : For /api/projects/:pid/members type Member struct { - UserName string `json:"username"` - Roles []int `json:"roles"` + RoleID int `json:"role_id"` + Member *MemberUser `json:"member_user"` +} + +//MemberUser ... +type MemberUser struct { + Username string `json:"username"` +} + +//ExistingMember : For GET /api/projects/20/members +type ExistingMember struct { + MID int `json:"id"` + Name string `json:"entity_name"` + RoleID int `json:"role_id"` } diff --git a/tests/apitests/api-testing/models/project.go b/tests/apitests/api-testing/models/project.go index 690d9adf9..05a9ab9fe 100644 --- a/tests/apitests/api-testing/models/project.go +++ b/tests/apitests/api-testing/models/project.go @@ -3,7 +3,7 @@ package models //Project : For /api/projects type Project struct { Name string `json:"project_name"` - Metadata *Metadata `json:"metadata, omitempty"` + Metadata *Metadata `json:"metadata,omitempty"` } //Metadata : Metadata for project diff --git a/tests/apitests/api-testing/tests/suites/suite01/suite.go b/tests/apitests/api-testing/tests/suites/suite01/suite.go index d5b2f317f..8f5ce1f0a 100644 --- a/tests/apitests/api-testing/tests/suites/suite01/suite.go +++ b/tests/apitests/api-testing/tests/suites/suite01/suite.go @@ -86,8 +86,7 @@ func (ccs *ConcourseCiSuite01) Run(onEnvironment *envs.Environment) *lib.Report } //s7 - uid := usr.GetUserID(onEnvironment.Account) - if err := pro.RevokeRole(onEnvironment.TestingProject, uid); err != nil { + if err := pro.RevokeRole(onEnvironment.TestingProject, onEnvironment.Account); err != nil { report.Failed("RevokeRole", err) } else { report.Passed("RevokeRole") diff --git a/tests/apitests/api-testing/tests/suites/suite02/suite.go b/tests/apitests/api-testing/tests/suites/suite02/suite.go index 3a2839c3d..454ea9de9 100644 --- a/tests/apitests/api-testing/tests/suites/suite02/suite.go +++ b/tests/apitests/api-testing/tests/suites/suite02/suite.go @@ -76,9 +76,7 @@ func (ccs *ConcourseCiSuite02) Run(onEnvironment *envs.Environment) *lib.Report } //s6 - usr := lib.NewUserUtil(onEnvironment.RootURI(), onEnvironment.HTTPClient) - uid := usr.GetUserID(onEnvironment.Account) - if err := pro.RevokeRole(onEnvironment.TestingProject, uid); err != nil { + if err := pro.RevokeRole(onEnvironment.TestingProject, onEnvironment.Account); err != nil { report.Failed("RevokeRole", err) } else { report.Passed("RevokeRole")