Merge pull request #736 from zgdxiaoxiao/new-dev

project api test and bugfix
This commit is contained in:
yhua123 2016-08-31 10:41:47 +08:00 committed by GitHub
commit 18015ed05a
4 changed files with 379 additions and 93 deletions

View File

@ -10,9 +10,9 @@ import (
"path/filepath"
"runtime"
"github.com/vmware/harbor/tests/apitests/apilib"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/tests/apitests/apilib"
"github.com/astaxie/beego"
"github.com/dghubble/sling"
@ -22,6 +22,11 @@ import (
_ "github.com/vmware/harbor/auth/ldap"
)
const (
jsonAcceptHeader = "application/json"
testAcceptHeader = "text/plain"
)
type api struct {
basePath string
}
@ -51,13 +56,31 @@ func init() {
beego.TestBeegoInit(apppath)
beego.Router("/api/search/", &SearchAPI{})
beego.Router("/api/projects/", &ProjectAPI{}, "get:List;post:Post")
beego.Router("/api/projects/", &ProjectAPI{}, "get:List;post:Post;head:Head")
beego.Router("/api/projects/:id/delete", &ProjectAPI{}, "delete:Delete")
beego.Router("/api/users/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword")
beego.Router("/api/projects/:id/publicity", &ProjectAPI{}, "put:ToggleProjectPublic")
beego.Router("/api/projects/:id([0-9]+)/logs/filter", &ProjectAPI{}, "post:FilterAccessLog")
_ = updateInitPassword(1, "Harbor12345")
}
func request(_sling *sling.Sling, acceptHeader string, authInfo ...usrInfo) (int, []byte, error) {
_sling = _sling.Set("Accept", acceptHeader)
req, err := _sling.Request()
if err != nil {
return 400, nil, err
}
if len(authInfo) > 0 {
req.SetBasicAuth(authInfo[0].Name, authInfo[0].Passwd)
}
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, req)
body, err := ioutil.ReadAll(w.Body)
return w.Code, body, err
}
//Search for projects and repositories
//Implementation Notes
//The Search endpoint returns information about the projects and repositories
@ -80,23 +103,7 @@ func (a api) SearchGet(q string) (apilib.Search, error) {
_sling = _sling.QueryStruct(&QueryParams{Query: q})
accepts := []string{"application/json", "text/plain"}
for key := range accepts {
_sling = _sling.Set("Accept", accepts[key])
break // only use the first Accept
}
req, err := _sling.Request()
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, req)
body, err := ioutil.ReadAll(w.Body)
if err != nil {
// handle error
}
_, body, err := request(_sling, jsonAcceptHeader)
var successPayload = new(apilib.Search)
err = json.Unmarshal(body, &successPayload)
return *successPayload, err
@ -117,24 +124,10 @@ func (a api) ProjectsPost(prjUsr usrInfo, project apilib.Project) (int, error) {
_sling = _sling.Path(path)
// accept header
accepts := []string{"application/json", "text/plain"}
for key := range accepts {
_sling = _sling.Set("Accept", accepts[key])
break // only use the first Accept
}
// body params
_sling = _sling.BodyJSON(project)
//fmt.Printf("project post req: %+v\n", _sling)
req, err := _sling.Request()
req.SetBasicAuth(prjUsr.Name, prjUsr.Passwd)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, req)
return w.Code, err
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
return httpStatusCode, err
}
//Change password
@ -154,27 +147,11 @@ func (a api) UsersUserIDPasswordPut(user usrInfo, userID int32, password apilib.
fmt.Printf("password %+v\n", password)
_sling = _sling.Path(path)
// accept header
accepts := []string{"application/json", "text/plain"}
for key := range accepts {
_sling = _sling.Set("Accept", accepts[key])
break // only use the first Accept
}
// body params
_sling = _sling.BodyJSON(password)
fmt.Printf("project post req: %+v\n", _sling)
req, err := _sling.Request()
req.SetBasicAuth(user.Name, user.Passwd)
fmt.Printf("project post req: %+v\n", req)
if err != nil {
// handle error
}
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, req)
return w.Code
httpStatusCode, _, _ := request(_sling, jsonAcceptHeader, user)
return httpStatusCode
}
@ -184,8 +161,8 @@ func (a api) UsersUserIDPasswordPut(user usrInfo, userID int32, password apilib.
////@param repoName The name of repository which will be deleted.
////@param tag Tag of a repository.
////@return void
////func (a HarborAPI) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) {
//func (a HarborAPI) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) {
////func (a api) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) {
//func (a api) RepositoriesDelete(prjUsr UsrInfo, repoName string, tag string) (int, error) {
// _sling := sling.New().Delete(a.basePath)
// // create path and map variables
@ -220,6 +197,128 @@ func (a api) UsersUserIDPasswordPut(user usrInfo, userID int32, password apilib.
// return httpResponse.StatusCode, err
//}
//Delete project by projectID
func (a api) ProjectsDelete(prjUsr usrInfo, projectID string) (int, error) {
_sling := sling.New().Delete(a.basePath)
//create api path
path := "api/projects/" + projectID + "/delete"
_sling = _sling.Path(path)
//_sling = _sling.BodyJSON(project)
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, prjUsr)
fmt.Println(string(body))
return httpStatusCode, err
}
//Check if the project name user provided already exists
func (a api) ProjectsHead(prjUsr usrInfo, projectName string) (int, error) {
_sling := sling.New().Head(a.basePath)
//create api path
path := "api/projects"
_sling = _sling.Path(path)
type QueryParams struct {
ProjectName string `url:"project_name,omitempty"`
}
_sling = _sling.QueryStruct(&QueryParams{ProjectName: projectName})
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
return httpStatusCode, err
}
//Search projects by projectName and isPublic
func (a api) ProjectsGet(projectName string, isPublic int32) (int, []apilib.Project, error) {
_sling := sling.New().Get(a.basePath)
//create api path
path := "api/projects"
_sling = _sling.Path(path)
type QueryParams struct {
ProjectName string `url:"project_name,omitempty"`
IsPubilc int32 `url:"is_public,omitempty"`
}
_sling = _sling.QueryStruct(&QueryParams{ProjectName: projectName, IsPubilc: isPublic})
var successPayload []apilib.Project
httpStatusCode, body, err := request(_sling, jsonAcceptHeader)
if err == nil && httpStatusCode == 200 {
err = json.Unmarshal(body, &successPayload)
}
return httpStatusCode, successPayload, err
}
//Update properties for a selected project.
func (a api) ToggleProjectPublicity(prjUsr usrInfo, projectID string, ispublic int32) (int, error) {
// create path and map variables
path := "/api/projects/" + projectID + "/publicity/"
_sling := sling.New().Put(a.basePath)
_sling = _sling.Path(path)
type QueryParams struct {
Public int32 `json:"public,omitempty"`
}
_sling = _sling.BodyJSON(&QueryParams{Public: ispublic})
httpStatusCode, _, err := request(_sling, jsonAcceptHeader, prjUsr)
return httpStatusCode, err
}
//Get access logs accompany with a relevant project.
func (a api) ProjectLogsFilter(prjUsr usrInfo, projectID string, accessLog apilib.AccessLogFilter) (int, []byte, error) {
//func (a api) ProjectLogsFilter(prjUsr usrInfo, projectID string, accessLog apilib.AccessLog) (int, apilib.AccessLog, error) {
_sling := sling.New().Post(a.basePath)
path := "/api/projects/" + projectID + "/logs/filter"
_sling = _sling.Path(path)
// body params
_sling = _sling.BodyJSON(accessLog)
// var successPayload []apilib.AccessLog
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, prjUsr)
/*
if err == nil && httpStatusCode == 200 {
err = json.Unmarshal(body, &successPayload)
}
*/
return httpStatusCode, body, err
// return httpStatusCode, successPayload, err
}
//Return relevant role members of projectID
func (a api) GetProjectMembersByProID(prjUsr usrInfo, projectID string) (int, []byte, error) {
_sling := sling.New().Post(a.basePath)
path := "/api/projects/" + projectID + "/members/"
_sling = _sling.Path(path)
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, prjUsr)
return httpStatusCode, body, err
}
//Add project role member accompany with projectID
func (a api) AddProjectMember(prjUsr usrInfo, projectID string, roles apilib.RoleParam) (int, []byte, error) {
_sling := sling.New().Post(a.basePath)
path := "/api/projects/" + projectID + "/members/"
_sling = _sling.Path(path)
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, prjUsr)
return httpStatusCode, body, err
}
//Return projects created by Harbor
//func (a HarborApi) ProjectsGet (projectName string, isPublic int32) ([]Project, error) {
// }
@ -229,35 +328,35 @@ func (a api) UsersUserIDPasswordPut(user usrInfo, userID int32, password apilib.
//}
//Get access logs accompany with a relevant project.
//func (a HarborApi) ProjectsProjectIdLogsFilterPost (projectId int32, accessLog AccessLog) ([]AccessLog, error) {
//func (a HarborApi) ProjectsProjectIdLogsFilterPost (projectID int32, accessLog AccessLog) ([]AccessLog, error) {
//}
//Return a project's relevant role members.
//func (a HarborApi) ProjectsProjectIdMembersGet (projectId int32) ([]Role, error) {
//func (a HarborApi) ProjectsProjectIdMembersGet (projectID int32) ([]Role, error) {
//}
//Add project role member accompany with relevant project and user.
//func (a HarborApi) ProjectsProjectIdMembersPost (projectId int32, roles RoleParam) (error) {
//func (a HarborApi) ProjectsProjectIdMembersPost (projectID int32, roles RoleParam) (error) {
//}
//Delete project role members accompany with relevant project and user.
//func (a HarborApi) ProjectsProjectIdMembersUserIdDelete (projectId int32, userId int32) (error) {
//func (a HarborApi) ProjectsProjectIdMembersUserIdDelete (projectID int32, userId int32) (error) {
//}
//Return role members accompany with relevant project and user.
//func (a HarborApi) ProjectsProjectIdMembersUserIdGet (projectId int32, userId int32) ([]Role, error) {
//func (a HarborApi) ProjectsProjectIdMembersUserIdGet (projectID int32, userId int32) ([]Role, error) {
//}
//Update project role members accompany with relevant project and user.
//func (a HarborApi) ProjectsProjectIdMembersUserIdPut (projectId int32, userId int32, roles RoleParam) (error) {
//func (a HarborApi) ProjectsProjectIdMembersUserIdPut (projectID int32, userId int32, roles RoleParam) (error) {
//}
//Update properties for a selected project.
//func (a HarborApi) ProjectsProjectIdPut (projectId int32, project Project) (error) {
//func (a HarborApi) ProjectsProjectIdPut (projectID int32, project Project) (error) {
//}
//Get repositories accompany with relevant project and repo name.
//func (a HarborApi) RepositoriesGet (projectId int32, q string) ([]Repository, error) {
//func (a HarborApi) RepositoriesGet (projectID int32, q string) ([]Repository, error) {
//}
//Get manifests of a relevant repository.

View File

@ -38,7 +38,7 @@ type ProjectAPI struct {
type projectReq struct {
ProjectName string `json:"project_name"`
Public bool `json:"public"`
Public int `json:"public"`
}
const projectNameMaxLen int = 30
@ -73,11 +73,8 @@ func (p *ProjectAPI) Post() {
p.userID = p.ValidateUser()
var req projectReq
var public int
p.DecodeJSONReq(&req)
if req.Public {
public = 1
}
public := req.Public
err := validateProjectReq(req)
if err != nil {
log.Errorf("Invalid project request, error: %v", err)
@ -305,7 +302,6 @@ func (p *ProjectAPI) List() {
func (p *ProjectAPI) ToggleProjectPublic() {
p.userID = p.ValidateUser()
var req projectReq
var public int
projectID, err := strconv.ParseInt(p.Ctx.Input.Param(":id"), 10, 64)
if err != nil {
@ -315,9 +311,7 @@ func (p *ProjectAPI) ToggleProjectPublic() {
}
p.DecodeJSONReq(&req)
if req.Public {
public = 1
}
public := req.Public
if !isProjectAdmin(p.userID, projectID) {
log.Warningf("Current user, id: %d does not have project admin role for project, id: %d", p.userID, projectID)
p.RenderError(http.StatusForbidden, "")

View File

@ -2,64 +2,257 @@ package api
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/tests/apitests/apilib"
"strconv"
"testing"
"time"
)
var admin, unknownUsr *usrInfo
var addProject apilib.Project
func Init() {
admin = &usrInfo{"admin", "Harbor12345"}
unknownUsr = &usrInfo{"unknown", "unknown"}
addProject.ProjectName = "test_project"
addProject.Public = 1
}
func TestAddProject(t *testing.T) {
fmt.Println("Testing Add Project(ProjectsPost) API")
fmt.Println("\nTesting Add Project(ProjectsPost) API")
assert := assert.New(t)
apiTest := newHarborAPI()
//prepare for test
admin := &usrInfo{"admin", "Harbor12345"}
prjUsr := &usrInfo{"unknown", "unknown"}
var project apilib.Project
project.ProjectName = "test_project"
project.Public = true
Init()
//case 1: admin not login, expect project creation fail.
result, err := apiTest.ProjectsPost(*prjUsr, project)
result, err := apiTest.ProjectsPost(*unknownUsr, addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
assert.Equal(result, int(401), "Case 1: Project creation status should be 401")
assert.Equal(int(401), result, "Case 1: Project creation status should be 401")
//t.Log(result)
}
//case 2: admin successful login, expect project creation success.
fmt.Println("case 2: admin successful login, expect project creation success.")
prjUsr = admin
unknownUsr = admin
result, err = apiTest.ProjectsPost(*prjUsr, project)
result, err = apiTest.ProjectsPost(*admin, addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
assert.Equal(result, int(201), "Case 2: Project creation status should be 201")
assert.Equal(int(201), result, "Case 2: Project creation status should be 201")
//t.Log(result)
}
//case 3: duplicate project name, create project fail
fmt.Println("case 3: duplicate project name, create project fail")
result, err = apiTest.ProjectsPost(*prjUsr, project)
result, err = apiTest.ProjectsPost(*admin, addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
assert.Equal(result, int(409), "Case 3: Project creation status should be 409")
assert.Equal(int(409), result, "Case 3: Project creation status should be 409")
//t.Log(result)
}
fmt.Printf("\n")
}
func TestProGet(t *testing.T) {
fmt.Println("\nTest for Project GET API")
assert := assert.New(t)
apiTest := newHarborAPI()
var result []apilib.Project
//----------------------------case 1 : Response Code=200----------------------------//
fmt.Println("case 1: respose code:200")
httpStatusCode, result, err := apiTest.ProjectsGet(addProject.ProjectName, 1)
if err != nil {
t.Error("Error while search project by proName and isPublic", err.Error())
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
//find add projectID
addProject.ProjectId = int32(result[0].ProjectId)
}
//----------------------------case 2 : Response Code=401:is_public=0----------------------------//
fmt.Println("case 2: respose code:401,isPublic = 0")
httpStatusCode, result, err = apiTest.ProjectsGet("library", 0)
if err != nil {
t.Error("Error while search project by proName and isPublic", err.Error())
t.Log(err)
} else {
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 200")
}
fmt.Printf("\n")
}
func TestDeleteProject(t *testing.T) {
fmt.Println("\nTesting Delete Project(ProjectsPost) API")
assert := assert.New(t)
apiTest := newHarborAPI()
projectID := strconv.Itoa(int(addProject.ProjectId))
//--------------------------case 1: Response Code=200---------------------------------//
httpStatusCode, err := apiTest.ProjectsDelete(*admin, projectID)
if err != nil {
t.Error("Error while delete project", err.Error())
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "Case 1: Project creation status should be 200")
//t.Log(result)
}
fmt.Printf("\n")
}
func TestProHead(t *testing.T) {
Init()
fmt.Println("\nTest for Project HEAD API")
assert := assert.New(t)
apiTest := newHarborAPI()
//----------------------------case 1 : Response Code=200----------------------------//
fmt.Println("case 1: respose code:200")
httpStatusCode, err := apiTest.ProjectsHead(*admin, "library")
if err != nil {
t.Error("Error while search project by proName", err.Error())
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
}
//----------------------------case 2 : Response Code=404:Project name does not exist.----------------------------//
fmt.Println("case 2: respose code:404,Project name does not exist.")
httpStatusCode, err = apiTest.ProjectsHead(*admin, "libra")
if err != nil {
t.Error("Error while search project by proName", err.Error())
t.Log(err)
} else {
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
}
//----------------------------case 3 : Response Code=401:User need to log in first..----------------------------//
fmt.Println("case 3: respose code:401,User need to log in first..")
httpStatusCode, err = apiTest.ProjectsHead(*unknownUsr, "libra")
if err != nil {
t.Error("Error while search project by proName", err.Error())
t.Log(err)
} else {
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
}
fmt.Printf("\n")
}
func TestToggleProjectPublicity(t *testing.T) {
fmt.Println("\nTest for Project PUT API: Update properties for a selected project")
assert := assert.New(t)
apiTest := newHarborAPI()
//-------------------case1: Response Code=200------------------------------//
fmt.Println("case 1: respose code:200")
httpStatusCode, err := apiTest.ToggleProjectPublicity(*admin, "1", 1)
if err != nil {
t.Error("Error while search project by proId", err.Error())
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
}
//-------------------case2: Response Code=401 User need to log in first. ------------------------------//
fmt.Println("case 2: respose code:401, User need to log in first.")
httpStatusCode, err = apiTest.ToggleProjectPublicity(*unknownUsr, "1", 1)
if err != nil {
t.Error("Error while search project by proId", err.Error())
t.Log(err)
} else {
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
}
//-------------------case3: Response Code=400 Invalid project id------------------------------//
fmt.Println("case 3: respose code:400, Invalid project id")
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "cc", 1)
if err != nil {
t.Error("Error while search project by proId", err.Error())
t.Log(err)
} else {
assert.Equal(int(400), httpStatusCode, "httpStatusCode should be 400")
}
//-------------------case4: Response Code=404 Not found the project------------------------------//
fmt.Println("case 4: respose code:404, Not found the project")
httpStatusCode, err = apiTest.ToggleProjectPublicity(*admin, "0", 1)
if err != nil {
t.Error("Error while search project by proId", err.Error())
t.Log(err)
} else {
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
}
fmt.Printf("\n")
}
func TestProjectLogsFilter(t *testing.T) {
fmt.Println("\nTest for search access logs filtered by operations and date time ranges..")
assert := assert.New(t)
apiTest := newHarborAPI()
endTimestamp := time.Now().Unix()
startTimestamp := endTimestamp - 3600
accessLog := &apilib.AccessLogFilter{
Username: "admin",
Keywords: "",
BeginTimestamp: startTimestamp,
EndTimestamp: endTimestamp,
}
//-------------------case1: Response Code=200------------------------------//
fmt.Println("case 1: respose code:200")
projectID := "1"
httpStatusCode, _, err := apiTest.ProjectLogsFilter(*admin, projectID, *accessLog)
if err != nil {
t.Error("Error while search access logs")
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
}
//-------------------case2: Response Code=401:User need to log in first.------------------------------//
fmt.Println("case 2: respose code:401:User need to log in first.")
projectID = "1"
httpStatusCode, _, err = apiTest.ProjectLogsFilter(*unknownUsr, projectID, *accessLog)
if err != nil {
t.Error("Error while search access logs")
t.Log(err)
} else {
assert.Equal(int(401), httpStatusCode, "httpStatusCode should be 401")
}
//-------------------case3: Response Code=404:Project does not exist.-------------------------//
fmt.Println("case 3: respose code:404:Illegal format of provided ID value.")
projectID = "11111"
httpStatusCode, _, err = apiTest.ProjectLogsFilter(*admin, projectID, *accessLog)
if err != nil {
t.Error("Error while search access logs")
t.Log(err)
} else {
assert.Equal(int(404), httpStatusCode, "httpStatusCode should be 404")
}
fmt.Printf("\n")
}

View File

@ -49,7 +49,7 @@ type Project struct {
OwnerName string `json:"owner_name,omitempty"`
// The public status of the project.
Public bool `json:"public,omitempty"`
Public int32 `json:"public,omitempty"`
// Correspond to the UI about whether the project's publicity is updatable (for UI)
Togglable bool `json:"togglable,omitempty"`