Merge pull request #3761 from vmware/add_api_testing

[Skip CI]add api testing for harbor including image pull and push
This commit is contained in:
Daniel Jiang 2017-12-08 17:11:59 +08:00 committed by GitHub
commit 9193161f25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1226 additions and 0 deletions

View File

@ -0,0 +1,97 @@
package client
import "os/exec"
import "strings"
import "errors"
import "bufio"
import "fmt"
//DockerClient : Run docker commands
type DockerClient struct{}
//Status : Check if docker daemon is there
func (dc *DockerClient) Status() error {
cmdName := "docker"
args := []string{"info"}
return dc.runCommand(cmdName, args)
}
//Pull : Pull image
func (dc *DockerClient) Pull(image string) error {
if len(strings.TrimSpace(image)) == 0 {
return errors.New("Empty image")
}
cmdName := "docker"
args := []string{"pull", image}
return dc.runCommandWithOutput(cmdName, args)
}
//Tag :Tag image
func (dc *DockerClient) Tag(source, target string) error {
if len(strings.TrimSpace(source)) == 0 ||
len(strings.TrimSpace(target)) == 0 {
return errors.New("Empty images")
}
cmdName := "docker"
args := []string{"tag", source, target}
return dc.runCommandWithOutput(cmdName, args)
}
//Push : push image
func (dc *DockerClient) Push(image string) error {
if len(strings.TrimSpace(image)) == 0 {
return errors.New("Empty image")
}
cmdName := "docker"
args := []string{"push", image}
return dc.runCommandWithOutput(cmdName, args)
}
//Login : Login docker
func (dc *DockerClient) Login(userName, password string, uri string) error {
if len(strings.TrimSpace(userName)) == 0 ||
len(strings.TrimSpace(password)) == 0 {
return errors.New("Invlaid credential")
}
cmdName := "docker"
args := []string{"login", "-u", userName, "-p", password, uri}
return dc.runCommandWithOutput(cmdName, args)
}
func (dc *DockerClient) runCommand(cmdName string, args []string) error {
return exec.Command(cmdName, args...).Run()
}
func (dc *DockerClient) runCommandWithOutput(cmdName string, args []string) error {
cmd := exec.Command(cmdName, args...)
cmdReader, err := cmd.StdoutPipe()
if err != nil {
return err
}
scanner := bufio.NewScanner(cmdReader)
go func() {
for scanner.Scan() {
fmt.Printf("%s out | %s\n", cmdName, scanner.Text())
}
}()
if err = cmd.Start(); err != nil {
return err
}
if err = cmd.Wait(); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,170 @@
package client
import (
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"net/http"
"strings"
)
const (
httpHeaderJSON = "application/json"
httpHeaderContentType = "Content-Type"
httpHeaderAccept = "Accept"
)
//APIClientConfig : Keep config options for APIClient
type APIClientConfig struct {
Username string
Password string
CaFile string
CertFile string
KeyFile string
}
//APIClient provided the http client for trigger http requests
type APIClient struct {
//http client
client *http.Client
//Configuration
config APIClientConfig
}
//NewAPIClient is constructor of APIClient
func NewAPIClient(config APIClientConfig) (*APIClient, error) {
//Load client cert
cert, err := tls.LoadX509KeyPair(config.CertFile, config.KeyFile)
if err != nil {
return nil, err
}
//Add ca
caCert, err := ioutil.ReadFile(config.CaFile)
if err != nil {
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
tlsConfig.BuildNameToCertificate()
transport := &http.Transport{
TLSClientConfig: tlsConfig,
}
client := &http.Client{
Transport: transport,
}
return &APIClient{
client: client,
config: config,
}, nil
}
//Get data
func (ac *APIClient) Get(url string) ([]byte, error) {
if strings.TrimSpace(url) == "" {
return nil, errors.New("empty url")
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set(httpHeaderAccept, httpHeaderJSON)
req.SetBasicAuth(ac.config.Username, ac.config.Password)
resp, err := ac.client.Do(req)
if err != nil {
return nil, err
}
defer func() {
if resp.Body != nil {
resp.Body.Close()
}
}()
if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return data, nil
}
//Post data
func (ac *APIClient) Post(url string, data []byte) error {
if strings.TrimSpace(url) == "" {
return errors.New("Empty url")
}
req, err := http.NewRequest("POST", url, strings.NewReader(string(data)))
if err != nil {
return err
}
req.Header.Set(httpHeaderContentType, httpHeaderJSON)
req.SetBasicAuth(ac.config.Username, ac.config.Password)
resp, err := ac.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusCreated &&
resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
}
return nil
}
//Delete data
func (ac *APIClient) Delete(url string) error {
if strings.TrimSpace(url) == "" {
return errors.New("Empty url")
}
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
req.Header.Set(httpHeaderAccept, httpHeaderJSON)
req.SetBasicAuth(ac.config.Username, ac.config.Password)
resp, err := ac.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return errors.New(resp.Status)
}
return nil
}
//SwitchAccount : Switch account
func (ac *APIClient) SwitchAccount(username, password string) {
if len(strings.TrimSpace(username)) == 0 ||
len(strings.TrimSpace(password)) == 0 {
return
}
ac.config.Username = username
ac.config.Password = password
}

View File

@ -0,0 +1,17 @@
package envs
//ConcourseCIEnv : Env for concourse pipeline
var ConcourseCIEnv = Environment{
Protocol: "https",
TestingProject: "concoursecitesting01",
ImageName: "busybox",
ImageTag: "latest",
CAFile: "../../../ca.crt",
KeyFile: "../../../key.crt",
CertFile: "../../../cert.crt",
Account: "cody",
Password: "Admin!23",
Admin: "admin",
AdminPass: "pksxgxmifc0cnwa5px9h",
Hostname: "10.112.122.1",
}

View File

@ -0,0 +1,127 @@
package envs
import (
"fmt"
"os"
"strings"
"github.com/vmware/harbor/tests/apitests/api-testing/client"
)
//Environment keeps the testing env info
type Environment struct {
Protocol string //env var: HTTP_PROTOCOL
Hostname string //env var: TESTING_ENV_HOSTNAME
Account string //env var: TESTING_ENV_ACCOUNT
Password string //env var: TESTING_ENV_PASSWORD
Admin string //env var: TESTING_ENV_ADMIN
AdminPass string //env var: TESTING_ENV_ADMIN_PASS
TestingProject string //env var: TESTING_PROJECT_NAME
ImageName string //env var: TESTING_IMAGE_NAME
ImageTag string //env var: TESTING_IMAGE_TAG
CAFile string //env var: CA_FILE_PATH
CertFile string //env var: CERT_FILE_PATH
KeyFile string //env var: KEY_FILE_PATH
//API client
HTTPClient *client.APIClient
//Docker client
DockerClient *client.DockerClient
//Initialize status
loaded bool
}
//Load test env info
func (env *Environment) Load() error {
host := os.Getenv("TESTING_ENV_HOSTNAME")
if isNotEmpty(host) {
env.Hostname = host
}
account := os.Getenv("TESTING_ENV_ACCOUNT")
if isNotEmpty(account) {
env.Account = account
}
pwd := os.Getenv("TESTING_ENV_PASSWORD")
if isNotEmpty(pwd) {
env.Password = pwd
}
admin := os.Getenv("TESTING_ENV_ADMIN")
if isNotEmpty(admin) {
env.Admin = admin
}
adminPwd := os.Getenv("TESTING_ENV_ADMIN_PASS")
if isNotEmpty(adminPwd) {
env.AdminPass = adminPwd
}
pro := os.Getenv("TESTING_PROJECT_NAME")
if isNotEmpty(pro) {
env.TestingProject = pro
}
imgName := os.Getenv("TESTING_IMAGE_NAME")
if isNotEmpty(imgName) {
env.ImageName = imgName
}
imgTag := os.Getenv("TESTING_IMAGE_TAG")
if isNotEmpty(imgTag) {
env.ImageTag = imgTag
}
protocol := os.Getenv("HTTP_PROTOCOL")
if isNotEmpty(protocol) {
env.Protocol = protocol
}
caFile := os.Getenv("CA_FILE_PATH")
if isNotEmpty(caFile) {
env.CAFile = caFile
}
keyFile := os.Getenv("KEY_FILE_PATH")
if isNotEmpty(keyFile) {
env.KeyFile = keyFile
}
certFile := os.Getenv("CERT_FILE_PATH")
if isNotEmpty(certFile) {
env.CertFile = certFile
}
if !env.loaded {
cfg := client.APIClientConfig{
Username: env.Admin,
Password: env.AdminPass,
CaFile: env.CAFile,
CertFile: env.CertFile,
KeyFile: env.KeyFile,
}
httpClient, err := client.NewAPIClient(cfg)
if err != nil {
return err
}
env.HTTPClient = httpClient
env.DockerClient = &client.DockerClient{}
env.loaded = true
}
return nil
}
//RootURI : The root URI like https://<hostname>
func (env *Environment) RootURI() string {
return fmt.Sprintf("%s://%s", env.Protocol, env.Hostname)
}
func isNotEmpty(str string) bool {
return len(strings.TrimSpace(str)) > 0
}

View File

@ -0,0 +1,137 @@
package lib
import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/vmware/harbor/tests/apitests/api-testing/client"
"github.com/vmware/harbor/tests/apitests/api-testing/models"
)
//ImageUtil : For repository and tag functions
type ImageUtil struct {
rootURI string
testingClient *client.APIClient
}
//NewImageUtil : Constructor
func NewImageUtil(rootURI string, httpClient *client.APIClient) *ImageUtil {
if len(strings.TrimSpace(rootURI)) == 0 || httpClient == nil {
return nil
}
return &ImageUtil{
rootURI: rootURI,
testingClient: httpClient,
}
}
//DeleteRepo : Delete repo
func (iu *ImageUtil) DeleteRepo(repoName string) error {
if len(strings.TrimSpace(repoName)) == 0 {
return errors.New("Empty repo name for deleting")
}
url := fmt.Sprintf("%s%s%s", iu.rootURI, "/api/repositories/", repoName)
if err := iu.testingClient.Delete(url); err != nil {
return err
}
return nil
}
//ScanTag :Scan a tag
func (iu *ImageUtil) ScanTag(repoName string, tagName string) error {
if len(strings.TrimSpace(repoName)) == 0 {
return errors.New("Empty repo name for scanning")
}
if len(strings.TrimSpace(tagName)) == 0 {
return errors.New("Empty tag name for scanning")
}
url := fmt.Sprintf("%s%s%s%s%s%s", iu.rootURI, "/api/repositories/", repoName, "/tags/", tagName, "/scan")
if err := iu.testingClient.Post(url, nil); err != nil {
return err
}
tk := time.NewTicker(1 * time.Second)
defer tk.Stop()
done := make(chan bool)
errchan := make(chan error)
url = fmt.Sprintf("%s%s%s%s%s", iu.rootURI, "/api/repositories/", repoName, "/tags/", tagName)
go func() {
for _ = range tk.C {
data, err := iu.testingClient.Get(url)
if err != nil {
errchan <- err
return
}
var tag models.Tag
if err = json.Unmarshal(data, &tag); err != nil {
errchan <- err
return
}
if tag.ScanOverview != nil && tag.ScanOverview.Status == "finished" {
done <- true
}
}
}()
select {
case <-done:
return nil
case <-time.After(20 * time.Second):
return errors.New("Scan timeout after 30 seconds")
}
}
//GetRepos : Get repos in the project
func (iu *ImageUtil) GetRepos(projectName string) ([]models.Repository, error) {
if len(strings.TrimSpace(projectName)) == 0 {
return nil, errors.New("Empty project name for getting repos")
}
proUtil := NewProjectUtil(iu.rootURI, iu.testingClient)
pid := proUtil.GetProjectID(projectName)
if pid == -1 {
return nil, fmt.Errorf("Failed to get project ID with name %s", projectName)
}
url := fmt.Sprintf("%s%s%d", iu.rootURI, "/api/repositories?project_id=", pid)
data, err := iu.testingClient.Get(url)
if err != nil {
return nil, err
}
var repos []models.Repository
if err = json.Unmarshal(data, &repos); err != nil {
return nil, err
}
return repos, nil
}
//GetTags : Get tags
func (iu *ImageUtil) GetTags(repoName string) ([]models.Tag, error) {
if len(strings.TrimSpace(repoName)) == 0 {
return nil, errors.New("Empty repository name for getting tags")
}
url := fmt.Sprintf("%s%s%s%s", iu.rootURI, "/api/repositories/", repoName, "/tags")
tagData, err := iu.testingClient.Get(url)
if err != nil {
return nil, err
}
var tags []models.Tag
if err = json.Unmarshal(tagData, &tags); err != nil {
return nil, err
}
return tags, nil
}

View File

@ -0,0 +1,169 @@
package lib
import (
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/vmware/harbor/tests/apitests/api-testing/client"
"github.com/vmware/harbor/tests/apitests/api-testing/models"
)
//ProjectUtil : Util methods for project related
type ProjectUtil struct {
rootURI string
testingClient *client.APIClient
}
//NewProjectUtil : Constructor
func NewProjectUtil(rootURI string, httpClient *client.APIClient) *ProjectUtil {
if len(strings.TrimSpace(rootURI)) == 0 || httpClient == nil {
return nil
}
return &ProjectUtil{
rootURI: rootURI,
testingClient: httpClient,
}
}
//GetProjects : Get projects
//If name specified, then only get the specified project
func (pu *ProjectUtil) GetProjects(name string) ([]models.ExistingProject, error) {
url := pu.rootURI + "/api/projects"
if len(strings.TrimSpace(name)) > 0 {
url = url + "?name=" + name
}
data, err := pu.testingClient.Get(url)
if err != nil {
return nil, err
}
var pros []models.ExistingProject
if err = json.Unmarshal(data, &pros); err != nil {
return nil, err
}
return pros, nil
}
//GetProjectID : Get the project ID
//If no project existing with the name, then return -1
func (pu *ProjectUtil) GetProjectID(projectName string) int {
pros, err := pu.GetProjects(projectName)
if err != nil {
return -1
}
if len(pros) == 0 {
return -1
}
for _, pro := range pros {
if pro.Name == projectName {
return pro.ID
}
}
return -1
}
//CreateProject :Create project
func (pu *ProjectUtil) CreateProject(projectName string, accessLevel bool) error {
if len(strings.TrimSpace(projectName)) == 0 {
return errors.New("Empty project name for creating")
}
p := models.Project{
Name: projectName,
Metadata: &models.Metadata{
AccessLevel: fmt.Sprintf("%v", accessLevel),
},
}
body, err := json.Marshal(&p)
if err != nil {
return err
}
url := pu.rootURI + "/api/projects"
if err = pu.testingClient.Post(url, body); err != nil {
return err
}
return nil
}
//DeleteProject : Delete project
func (pu *ProjectUtil) DeleteProject(projectName string) error {
if len(strings.TrimSpace(projectName)) == 0 {
return errors.New("Empty project name for deleting")
}
pid := pu.GetProjectID(projectName)
if pid == -1 {
return errors.New("Failed to get project ID")
}
url := fmt.Sprintf("%s%s%d", pu.rootURI, "/api/projects/", pid)
if err := pu.testingClient.Delete(url); err != nil {
return err
}
return nil
}
//AssignRole : Assign role to user
func (pu *ProjectUtil) AssignRole(projectName, username string) error {
if len(strings.TrimSpace(projectName)) == 0 ||
len(strings.TrimSpace(username)) == 0 {
return errors.New("Project name and username are required for assigning role")
}
pid := pu.GetProjectID(projectName)
if pid == -1 {
return fmt.Errorf("Failed to get project ID with name %s", projectName)
}
m := models.Member{
UserName: username,
Roles: []int{2},
}
body, err := json.Marshal(&m)
if err != nil {
return err
}
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
}
//RevokeRole : RevokeRole role from user
func (pu *ProjectUtil) RevokeRole(projectName string, uid int) error {
if len(strings.TrimSpace(projectName)) == 0 {
return errors.New("Project name is required for revoking role")
}
if uid == 0 {
return errors.New("User ID is required for revoking role")
}
pid := pu.GetProjectID(projectName)
if pid == -1 {
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 {
return err
}
return nil
}

View File

@ -0,0 +1,43 @@
package lib
import (
"fmt"
)
type Report struct {
passed []string
failed []string
}
//Passed case
func (r *Report) Passed(caseName string) {
r.passed = append(r.passed, fmt.Sprintf("%s: [%s]", caseName, "PASSED"))
}
//Failed case
func (r *Report) Failed(caseName string, err error) {
r.failed = append(r.failed, fmt.Sprintf("%s: [%s] %s", caseName, "FAILED", err.Error()))
}
//Print report
func (r *Report) Print() {
passed := len(r.passed)
failed := len(r.failed)
total := passed + failed
fmt.Println("=====================================")
fmt.Printf("Overall: %d/%d passed , %d/%d failed\n", passed, total, failed, total)
fmt.Println("=====================================")
for _, res := range r.passed {
fmt.Println(res)
}
for _, res := range r.failed {
fmt.Println(res)
}
}
//IsFail : Overall result
func (r *Report) IsFail() bool {
return len(r.failed) > 0
}

View File

@ -0,0 +1,50 @@
package lib
import (
"encoding/json"
"fmt"
"strings"
"github.com/vmware/harbor/tests/apitests/api-testing/client"
"github.com/vmware/harbor/tests/apitests/api-testing/models"
)
//SystemUtil : For getting system info
type SystemUtil struct {
rootURI string
hostname string
testingClient *client.APIClient
}
//NewSystemUtil : Constructor
func NewSystemUtil(rootURI, hostname string, httpClient *client.APIClient) *SystemUtil {
if len(strings.TrimSpace(rootURI)) == 0 || httpClient == nil {
return nil
}
return &SystemUtil{
rootURI: rootURI,
hostname: hostname,
testingClient: httpClient,
}
}
//GetSystemInfo : Get systeminfo
func (nsu *SystemUtil) GetSystemInfo() error {
url := nsu.rootURI + "/api/systeminfo"
data, err := nsu.testingClient.Get(url)
if err != nil {
return err
}
var info models.SystemInfo
if err := json.Unmarshal(data, &info); err != nil {
return err
}
if info.RegistryURL != nsu.hostname {
return fmt.Errorf("Invalid registry url in system info: expect %s got %s ", nsu.hostname, info.RegistryURL)
}
return nil
}

View File

@ -0,0 +1,118 @@
package lib
import (
"encoding/json"
"errors"
"fmt"
"strings"
"github.com/vmware/harbor/tests/apitests/api-testing/client"
"github.com/vmware/harbor/tests/apitests/api-testing/models"
)
//UserUtil : For user related
type UserUtil struct {
rootURI string
testingClient *client.APIClient
}
//NewUserUtil : Constructor
func NewUserUtil(rootURI string, httpClient *client.APIClient) *UserUtil {
if len(strings.TrimSpace(rootURI)) == 0 || httpClient == nil {
return nil
}
return &UserUtil{
rootURI: rootURI,
testingClient: httpClient,
}
}
//CreateUser : Create user
func (uu *UserUtil) CreateUser(username, password string) error {
if len(strings.TrimSpace(username)) == 0 ||
len(strings.TrimSpace(password)) == 0 {
return errors.New("Username and password required for creating user")
}
u := models.User{
Username: username,
Password: password,
Email: username + "@vmware.com",
RealName: username + "pks",
Comment: "testing",
}
body, err := json.Marshal(&u)
if err != nil {
return err
}
url := fmt.Sprintf("%s%s", uu.rootURI, "/api/users")
if err := uu.testingClient.Post(url, body); err != nil {
return err
}
return nil
}
//DeleteUser : Delete testing account
func (uu *UserUtil) DeleteUser(username string) error {
uid := uu.GetUserID(username)
if uid == -1 {
return fmt.Errorf("Failed to get user with name %s", username)
}
url := fmt.Sprintf("%s%s%d", uu.rootURI, "/api/users/", uid)
if err := uu.testingClient.Delete(url); err != nil {
return err
}
return nil
}
//GetUsers : Get users
//If name specified, then return that one
func (uu *UserUtil) GetUsers(name string) ([]models.ExistingUser, error) {
url := fmt.Sprintf("%s%s", uu.rootURI, "/api/users")
if len(strings.TrimSpace(name)) > 0 {
url = url + "?username=" + name
}
data, err := uu.testingClient.Get(url)
if err != nil {
return nil, err
}
var users []models.ExistingUser
if err = json.Unmarshal(data, &users); err != nil {
return nil, err
}
return users, nil
}
//GetUserID : Get user ID
//If user with the username is not existing, then return -1
func (uu *UserUtil) GetUserID(username string) int {
if len(strings.TrimSpace(username)) == 0 {
return -1
}
users, err := uu.GetUsers(username)
if err != nil {
return -1
}
if len(users) == 0 {
return -1
}
for _, u := range users {
if u.Username == username {
return u.ID
}
}
return -1
}

View File

@ -0,0 +1,10 @@
package models
//Endpoint : For /api/targets
type Endpoint struct {
Endpoint string `json:"endpoint"`
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
Type int `json:"type"`
}

View File

@ -0,0 +1,20 @@
package models
//Repository : For /api/repositories
type Repository struct {
ID int `json:"id"`
Name string `json:"name"`
}
//Tag : For /api/repositories/:repo/tags
type Tag struct {
Digest string `json:"digest"`
Name string `json:"name"`
Signature map[string]interface{} `json:"signature, omitempty"`
ScanOverview *ScanOverview `json:"scan_overview, omitempty"`
}
//ScanOverview : For scanning
type ScanOverview struct {
Status string `json:"scan_status"`
}

View File

@ -0,0 +1,7 @@
package models
//Member : For /api/projects/:pid/members
type Member struct {
UserName string `json:"username"`
Roles []int `json:"roles"`
}

View File

@ -0,0 +1,18 @@
package models
//Project : For /api/projects
type Project struct {
Name string `json:"project_name"`
Metadata *Metadata `json:"metadata, omitempty"`
}
//Metadata : Metadata for project
type Metadata struct {
AccessLevel string `json:"public"`
}
//ExistingProject : For /api/projects?name=***
type ExistingProject struct {
Name string `json:"name"`
ID int `json:"project_id"`
}

View File

@ -0,0 +1,10 @@
package models
//ReplicationPolicy : For /api/replications
type ReplicationPolicy struct {
ProjectID int `json:"project_id"`
}
type ExistingReplicationPolicy struct {
}

View File

@ -0,0 +1,7 @@
package models
//SystemInfo : For GET /api/systeminfo
type SystemInfo struct {
AuthMode string `json:"auth_mode"`
RegistryURL string `json:"registry_url"`
}

View File

@ -0,0 +1,16 @@
package models
//User : For /api/users
type User struct {
Username string `json:"username"`
RealName string `json:"realname"`
Password string `json:"password"`
Email string `json:"email"`
Comment string `json:"comment"`
}
//ExistingUser : For GET /api/users
type ExistingUser struct {
User
ID int `json:"user_id"`
}

View File

@ -0,0 +1,11 @@
package suites
import (
"github.com/vmware/harbor/tests/apitests/api-testing/envs"
"github.com/vmware/harbor/tests/apitests/api-testing/lib"
)
//Suite : Run a group of test cases
type Suite interface {
Run(onEnvironment envs.Environment) *lib.Report
}

View File

@ -0,0 +1,22 @@
package suite01
import (
"testing"
"github.com/vmware/harbor/tests/apitests/api-testing/envs"
)
//TestRun : Start to run the case
func TestRun(t *testing.T) {
//Initialize env
if err := envs.ConcourseCIEnv.Load(); err != nil {
t.Fatal(err.Error())
}
suite := ConcourseCiSuite01{}
report := suite.Run(&envs.ConcourseCIEnv)
report.Print()
if report.IsFail() {
t.Fail()
}
}

View File

@ -0,0 +1,177 @@
package suite01
import (
"fmt"
"github.com/vmware/harbor/tests/apitests/api-testing/envs"
"github.com/vmware/harbor/tests/apitests/api-testing/lib"
)
//Steps of suite01:
// s0: Get systeminfo
// s1: create project
// s2: create user "cody"
// s3: assign cody as developer
// s4: push a busybox image to project
// s5: scan image
// s6: pull image from project
// s7: remove "cody" from project member list
// s8: pull image from project [FAIL]
// s9: remove repository busybox
// s10: delete project
// s11: delete user
//ConcourseCiSuite01 : For harbor journey in concourse pipeline
type ConcourseCiSuite01 struct{}
//Run : Run a group of cases
func (ccs *ConcourseCiSuite01) Run(onEnvironment *envs.Environment) *lib.Report {
report := &lib.Report{}
//s0
sys := lib.NewSystemUtil(onEnvironment.RootURI(), onEnvironment.Hostname, onEnvironment.HTTPClient)
if err := sys.GetSystemInfo(); err != nil {
report.Failed("GetSystemInfo", err)
} else {
report.Passed("GetSystemInfo")
}
//s1
pro := lib.NewProjectUtil(onEnvironment.RootURI(), onEnvironment.HTTPClient)
if err := pro.CreateProject(onEnvironment.TestingProject, false); err != nil {
report.Failed("CreateProject", err)
} else {
report.Passed("CreateProject")
}
//s2
usr := lib.NewUserUtil(onEnvironment.RootURI(), onEnvironment.HTTPClient)
if err := usr.CreateUser(onEnvironment.Account, onEnvironment.Password); err != nil {
report.Failed("CreateUser", err)
} else {
report.Passed("CreateUser")
}
//s3
if err := pro.AssignRole(onEnvironment.TestingProject, onEnvironment.Account); err != nil {
report.Failed("AssignRole", err)
} else {
report.Passed("AssignRole")
}
//s4
if err := ccs.pushImage(onEnvironment); err != nil {
report.Failed("pushImage", err)
} else {
report.Passed("pushImage")
}
//s5
img := lib.NewImageUtil(onEnvironment.RootURI(), onEnvironment.HTTPClient)
repoName := fmt.Sprintf("%s/%s", onEnvironment.TestingProject, onEnvironment.ImageName)
if err := img.ScanTag(repoName, onEnvironment.ImageTag); err != nil {
report.Failed("ScanTag", err)
} else {
report.Passed("ScanTag")
}
//s6
if err := ccs.pullImage(onEnvironment); err != nil {
report.Failed("pullImage[1]", err)
} else {
report.Passed("pullImage[1]")
}
//s7
uid := usr.GetUserID(onEnvironment.Account)
if err := pro.RevokeRole(onEnvironment.TestingProject, uid); err != nil {
report.Failed("RevokeRole", err)
} else {
report.Passed("RevokeRole")
}
//s8
if err := ccs.pullImage(onEnvironment); err == nil {
report.Failed("pullImage[2]", err)
} else {
report.Passed("pullImage[2]")
}
//s9
if err := img.DeleteRepo(repoName); err != nil {
report.Failed("DeleteRepo", err)
} else {
report.Passed("DeleteRepo")
}
//s10
if err := pro.DeleteProject(onEnvironment.TestingProject); err != nil {
report.Failed("DeleteProject", err)
} else {
report.Passed("DeleteProject")
}
//s11
if err := usr.DeleteUser(onEnvironment.Account); err != nil {
report.Failed("DeleteUser", err)
} else {
report.Passed("DeleteUser")
}
return report
}
func (ccs *ConcourseCiSuite01) pushImage(onEnvironment *envs.Environment) error {
docker := onEnvironment.DockerClient
if err := docker.Status(); err != nil {
return err
}
imagePulling := fmt.Sprintf("%s:%s", onEnvironment.ImageName, onEnvironment.ImageTag)
if err := docker.Pull(imagePulling); err != nil {
return err
}
if err := docker.Login(onEnvironment.Account, onEnvironment.Password, onEnvironment.Hostname); err != nil {
return err
}
imagePushing := fmt.Sprintf("%s/%s/%s:%s",
onEnvironment.Hostname,
onEnvironment.TestingProject,
onEnvironment.ImageName,
onEnvironment.ImageTag)
if err := docker.Tag(imagePulling, imagePushing); err != nil {
return err
}
if err := docker.Push(imagePushing); err != nil {
return err
}
return nil
}
func (ccs *ConcourseCiSuite01) pullImage(onEnvironment *envs.Environment) error {
docker := onEnvironment.DockerClient
if err := docker.Status(); err != nil {
return err
}
if err := docker.Login(onEnvironment.Account, onEnvironment.Password, onEnvironment.Hostname); err != nil {
return err
}
imagePulling := fmt.Sprintf("%s/%s/%s:%s",
onEnvironment.Hostname,
onEnvironment.TestingProject,
onEnvironment.ImageName,
onEnvironment.ImageTag)
if err := docker.Pull(imagePulling); err != nil {
return err
}
return nil
}