harbor/src/core/api/project_test.go

486 lines
15 KiB
Go

// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package api
import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"testing"
"time"
"github.com/goharbor/harbor/src/chartserver"
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/tests/apitests/apilib"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var addProject *apilib.ProjectReq
var addPID int
func InitAddPro() {
addProject = &apilib.ProjectReq{"add_project", map[string]string{models.ProMetaPublic: "true"}}
}
func TestAddProject(t *testing.T) {
fmt.Println("\nTesting Add Project(ProjectsPost) API")
assert := assert.New(t)
apiTest := newHarborAPI()
// prepare for test
InitAddPro()
// case 1: admin not login, expect project creation fail.
result, err := apiTest.ProjectsPost(*unknownUsr, *addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
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.")
result, err = apiTest.ProjectsPost(*admin, *addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
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(*admin, *addProject)
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
assert.Equal(int(409), result, "Case 3: Project creation status should be 409")
// t.Log(result)
}
// case 4: response code = 400 : Project name is illegal in length
fmt.Println("case 4 : response code = 400 : Project name is illegal in length ")
result, err = apiTest.ProjectsPost(*admin, apilib.ProjectReq{"t", map[string]string{models.ProMetaPublic: "true"}})
if err != nil {
t.Error("Error while creat project", err.Error())
t.Log(err)
} else {
assert.Equal(int(400), result, "case 4 : response code = 400 : Project name is illegal in length ")
}
fmt.Printf("\n")
}
func TestListProjects(t *testing.T) {
fmt.Println("\nTest for Project GET API by project name")
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(
&apilib.ProjectQuery{
Name: addProject.ProjectName,
Owner: admin.Name,
Public: true,
})
assert.Nil(err)
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
// find add projectID
addPID = int(result[0].ProjectId)
// -------------------case 3 : check admin project role------------------------//
httpStatusCode, result, err = apiTest.ProjectsGet(
&apilib.ProjectQuery{
Name: addProject.ProjectName,
Owner: admin.Name,
Public: true,
}, *admin)
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")
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
assert.Equal(int32(1), result[0].CurrentUserRoleId, "User project role is wrong")
}
// -------------------case 4 : add project member and check his role ------------------------//
CommonAddUser()
member := &models.MemberReq{
Role: 2,
MemberUser: models.User{
Username: TestUserName,
},
}
projectID := strconv.Itoa(addPID)
httpStatusCode, err = apiTest.AddProjectMember(*admin, projectID, member)
if err != nil {
t.Error("Error whihle add project role member", err.Error())
t.Log(err)
} else {
assert.Equal(int(201), httpStatusCode, "httpStatusCode should be 201")
}
httpStatusCode, result, err = apiTest.ProjectsGet(
&apilib.ProjectQuery{
Name: addProject.ProjectName,
}, *testUser)
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")
assert.Equal(addProject.ProjectName, result[0].ProjectName, "Project name is wrong")
assert.Equal("true", result[0].Metadata[models.ProMetaPublic], "Public is wrong")
assert.Equal(int32(2), result[0].CurrentUserRoleId, "User project role is wrong")
}
id := strconv.Itoa(CommonGetUserID())
httpStatusCode, err = apiTest.DeleteProjectMember(*admin, projectID, id)
if err != nil {
t.Error("Error whihle add project role member", err.Error())
t.Log(err)
} else {
assert.Equal(int(200), httpStatusCode, "httpStatusCode should be 200")
}
CommonDelUser()
}
// Get project by proID
func TestProGetByID(t *testing.T) {
fmt.Println("\nTest for Project GET API by project id")
assert := assert.New(t)
apiTest := newHarborAPI()
var result apilib.Project
projectID := strconv.Itoa(addPID)
// ----------------------------case 1 : Response Code=200----------------------------//
fmt.Println("case 1: respose code:200")
httpStatusCode, result, err := apiTest.ProjectsGetByPID(projectID)
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")
assert.Equal(addProject.ProjectName, result.ProjectName, "ProjectName is wrong")
assert.Equal("true", result.Metadata[models.ProMetaPublic], "Public is wrong")
}
fmt.Printf("\n")
}
func TestDeleteProject(t *testing.T) {
fmt.Println("\nTesting Delete Project(ProjectsPost) API")
assert := assert.New(t)
apiTest := newHarborAPI()
projectID := strconv.Itoa(addPID)
// --------------------------case 1: Response Code=401,User need to log in first.-----------------------//
fmt.Println("case 1: Response Code=401,User need to log in first.")
httpStatusCode, err := apiTest.ProjectsDelete(*unknownUsr, projectID)
if err != nil {
t.Error("Error while delete project", err.Error())
t.Log(err)
} else {
assert.Equal(int(401), httpStatusCode, "Case 1: Project creation status should be 401")
}
// --------------------------case 2: Response Code=200---------------------------------//
fmt.Println("case2: respose 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 2: Project creation status should be 200")
}
// --------------------------case 3: Response Code=404,Project does not exist---------------------------------//
fmt.Println("case 3: Response Code=404,Project does not exist")
projectID = "11"
httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID)
if err != nil {
t.Error("Error while delete project", err.Error())
t.Log(err)
} else {
assert.Equal(int(404), httpStatusCode, "Case 3: Project creation status should be 404")
}
// --------------------------case 4: Response Code=400,Invalid project id.---------------------------------//
fmt.Println("case 4: Response Code=400,Invalid project id.")
projectID = "cc"
httpStatusCode, err = apiTest.ProjectsDelete(*admin, projectID)
if err != nil {
t.Error("Error while delete project", err.Error())
t.Log(err)
} else {
assert.Equal(int(400), httpStatusCode, "Case 4: Project creation status should be 400")
}
fmt.Printf("\n")
}
func TestProHead(t *testing.T) {
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")
}
fmt.Printf("\n")
}
func TestPut(t *testing.T) {
fmt.Println("\nTest for Project PUT API: Update properties for a selected project")
assert := assert.New(t)
apiTest := newHarborAPI()
project := &models.Project{
Metadata: map[string]string{
models.ProMetaPublic: "true",
},
}
fmt.Println("case 1: respose code:200")
code, err := apiTest.ProjectsPut(*admin, "1", project)
require.Nil(t, err)
assert.Equal(int(200), code)
fmt.Println("case 2: respose code:401, User need to log in first.")
code, err = apiTest.ProjectsPut(*unknownUsr, "1", project)
require.Nil(t, err)
assert.Equal(int(401), code)
fmt.Println("case 3: respose code:400, Invalid project id")
code, err = apiTest.ProjectsPut(*admin, "cc", project)
require.Nil(t, err)
assert.Equal(int(400), code)
fmt.Println("case 4: respose code:404, Not found the project")
code, err = apiTest.ProjectsPut(*admin, "1234", project)
require.Nil(t, err)
assert.Equal(int(404), code)
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()
query := &apilib.LogQuery{
Username: "admin",
Repository: "",
Tag: "",
Operation: []string{""},
BeginTimestamp: 0,
EndTimestamp: time.Now().Unix(),
}
// -------------------case1: Response Code=200------------------------------//
fmt.Println("case 1: respose code:200")
projectID := "1"
httpStatusCode, _, err := apiTest.ProjectLogs(*admin, projectID, query)
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.ProjectLogs(*unknownUsr, projectID, query)
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.ProjectLogs(*admin, projectID, query)
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")
}
func TestDeletable(t *testing.T) {
apiTest := newHarborAPI()
chServer, oldController, err := mockChartController()
require.Nil(t, err)
require.NotNil(t, chServer)
defer chServer.Close()
defer func() {
chartController = oldController
}()
project := models.Project{
Name: "project_for_test_deletable",
OwnerID: 1,
}
id, err := dao.AddProject(project)
require.Nil(t, err)
// non-exist project
code, del, err := apiTest.ProjectDeletable(*admin, 1000)
assert.Nil(t, err)
assert.Equal(t, http.StatusNotFound, code)
// unauthorized
code, del, err = apiTest.ProjectDeletable(*unknownUsr, id)
assert.Nil(t, err)
assert.Equal(t, http.StatusUnauthorized, code)
// can be deleted
code, del, err = apiTest.ProjectDeletable(*admin, id)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, code)
assert.True(t, del)
err = dao.AddRepository(models.RepoRecord{
Name: project.Name + "/golang",
ProjectID: id,
})
require.Nil(t, err)
// can not be deleted as contains repository
code, del, err = apiTest.ProjectDeletable(*admin, id)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, code)
assert.False(t, del)
}
// Provides a mock chart controller for deletable test cases
func mockChartController() (*httptest.Server, *chartserver.Controller, error) {
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case "/api/project_for_test_deletable/charts":
if r.Method == http.MethodGet {
w.Write([]byte("{}"))
return
}
case "/api/library/charts/harbor/0.2.0":
if r.Method == http.MethodGet {
w.Write([]byte(chartVersionOfHarbor020))
return
}
}
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte("not supported"))
}))
var oldController, newController *chartserver.Controller
url, err := url.Parse(mockServer.URL)
if err == nil {
newController, err = chartserver.NewController(url)
}
if err != nil {
mockServer.Close()
return nil, nil, err
}
// Override current controller and keep the old one for restoring
oldController = chartController
chartController = newController
return mockServer, oldController, nil
}
var chartVersionOfHarbor020 = `
{
"name": "harbor",
"home": "https://github.com/vmware/harbor",
"sources": [
"https://github.com/vmware/harbor/tree/master/contrib/helm/harbor"
],
"version": "0.2.0",
"description": "An Enterprise-class Docker Registry by VMware",
"keywords": [
"vmware",
"docker",
"registry",
"harbor"
],
"maintainers": [
{
"name": "Jesse Hu",
"email": "huh@vmware.com"
},
{
"name": "paulczar",
"email": "username.taken@gmail.com"
}
],
"engine": "gotpl",
"icon": "https://raw.githubusercontent.com/vmware/harbor/master/docs/img/harbor_logo.png",
"appVersion": "1.5.0",
"urls": [
"charts/harbor-0.2.0.tgz"
],
"created": "2018-08-29T10:26:21.141611102Z",
"digest": "fc8aae8dade9f0dfca12e9f1085081c49843d30a063a3fa7eb42497e3ceb277c"
}
`