Add test case exporter

- cache ut
- cli ut
- project collector ut
- system collector ut

Signed-off-by: DQ <dengq@vmware.com>
This commit is contained in:
DQ 2020-12-09 20:34:01 +08:00
parent d95f22448c
commit 85bf88c74e
7 changed files with 394 additions and 38 deletions

View File

@ -7,6 +7,8 @@ import (
var c *cache
const defaultCacheCleanInterval = 10
type cachedValue struct {
Value interface{}
Expiration int64
@ -77,7 +79,13 @@ func CacheInit(opt *Opt) {
RWMutex: &sync.RWMutex{},
}
go func() {
ticker := time.NewTicker(time.Duration(opt.CacheCleanInterval) * time.Second)
var cacheCleanInterval int64
if opt.CacheCleanInterval > 0 {
cacheCleanInterval = opt.CacheCleanInterval
} else {
cacheCleanInterval = defaultCacheCleanInterval
}
ticker := time.NewTicker(time.Duration(cacheCleanInterval) * time.Second)
for {
select {
case <-ticker.C:

View File

@ -0,0 +1,38 @@
package exporter
import (
"time"
"github.com/stretchr/testify/suite"
)
type CacheTestSuite struct {
suite.Suite
}
func (c *CacheTestSuite) SetupTest() {
CacheInit(&Opt{
CacheDuration: 1,
})
}
func (c *CacheTestSuite) TestCacheFunction() {
// Empty cache should not contain key1
_, ok := CacheGet("key1")
c.False(ok)
// Put keys to CacheGet
CachePut("key1", "value1")
CachePut("key2", "value2")
// Get key1 should return value1
v, ok := CacheGet("key1")
c.True(ok)
c.Equal("value1", v)
// Delete key1, it should not exist anymore
CacheDelete("key1")
_, ok = CacheGet("key1")
c.False(ok)
// timeout 1 second
time.Sleep(2 * time.Second)
_, ok = CacheGet("key2")
c.False(ok)
}

View File

@ -1,10 +1,6 @@
package exporter
import (
"fmt"
"net/http"
"net/url"
"github.com/prometheus/client_golang/prometheus"
)
@ -24,39 +20,6 @@ var (
}
)
var hbrCli *HarborClient
// HarborClient is client for request harbor
type HarborClient struct {
HarborScheme string
HarborHost string
HarborPort int
*http.Client
}
func (hc HarborClient) harborURL(p string) url.URL {
return url.URL{
Scheme: hc.HarborScheme,
Host: fmt.Sprintf("%s:%d", hc.HarborHost, hc.HarborPort),
Path: p,
}
}
// Get ...
func (hc HarborClient) Get(p string) (*http.Response, error) {
hbrURL := hc.harborURL(p)
res, err := http.Get(hbrURL.String())
if err != nil {
return nil, err
}
return res, nil
}
// InitHarborClient initialize the harbor client
func InitHarborClient(hc *HarborClient) {
hbrCli = hc
}
func newDesc(subsystem, name, help string) *prometheus.Desc {
return prometheus.NewDesc(
prometheus.BuildFQName(namespace, subsystem, name),

View File

@ -0,0 +1,40 @@
package exporter
import (
"fmt"
"net/http"
"net/url"
)
var hbrCli *HarborClient
// HarborClient is client for request harbor
type HarborClient struct {
HarborScheme string
HarborHost string
HarborPort int
*http.Client
}
func (hc HarborClient) harborURL(p string) url.URL {
return url.URL{
Scheme: hc.HarborScheme,
Host: fmt.Sprintf("%s:%d", hc.HarborHost, hc.HarborPort),
Path: p,
}
}
// Get ...
func (hc HarborClient) Get(p string) (*http.Response, error) {
hbrURL := hc.harborURL(p)
res, err := http.Get(hbrURL.String())
if err != nil {
return nil, err
}
return res, nil
}
// InitHarborClient initialize the harbor client
func InitHarborClient(hc *HarborClient) {
hbrCli = hc
}

View File

@ -0,0 +1,46 @@
package exporter
import (
"net/http"
"testing"
)
func TestHarborClient_harborURL(t *testing.T) {
type fields struct {
HarborScheme string
HarborHost string
HarborPort int
Client *http.Client
}
type args struct {
p string
}
tests := []struct {
name string
fields fields
args args
want string
}{
{name: "Can get URL", fields: fields{
HarborScheme: "https",
HarborHost: "test.harbor.dev",
HarborPort: 8443,
Client: http.DefaultClient,
},
args: args{p: ""}, want: "https://test.harbor.dev:8443",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hc := HarborClient{
HarborScheme: tt.fields.HarborScheme,
HarborHost: tt.fields.HarborHost,
HarborPort: tt.fields.HarborPort,
Client: tt.fields.Client,
}
if got := hc.harborURL(tt.args.p); got.String() != tt.want {
t.Errorf("HarborClient.harborURL() = %v, want %v", got.String(), tt.want)
}
})
}
}

View File

@ -0,0 +1,151 @@
package exporter
import (
"context"
"strconv"
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/goharbor/harbor/src/common"
"github.com/goharbor/harbor/src/common/dao"
"github.com/goharbor/harbor/src/common/dao/project"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils/test"
proctl "github.com/goharbor/harbor/src/controller/project"
quotactl "github.com/goharbor/harbor/src/controller/quota"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/pkg/artifact"
qtypes "github.com/goharbor/harbor/src/pkg/quota/types"
"github.com/goharbor/harbor/src/pkg/repository"
)
var (
alice = models.User{Username: "alice", Password: "password", Email: "alice@test.com"}
bob = models.User{Username: "bob", Password: "password", Email: "bob@test.com"}
eve = models.User{Username: "eve", Password: "password", Email: "eve@test.com"}
testPro1 = models.Project{OwnerID: 1, Name: "test1", Metadata: map[string]string{"public": "true"}}
testPro2 = models.Project{OwnerID: 1, Name: "test2", Metadata: map[string]string{"public": "false"}}
rs1 = qtypes.ResourceList{qtypes.ResourceStorage: 100}
rs2 = qtypes.ResourceList{qtypes.ResourceStorage: 200}
repo1 = models.RepoRecord{Name: "repo1"}
repo2 = models.RepoRecord{Name: "repo2"}
pmIDs = []int{}
art1 = artifact.Artifact{RepositoryName: repo1.Name, Type: "IMAGE", Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180"}
art2 = artifact.Artifact{RepositoryName: repo1.Name, Type: "IMAGE", Digest: "sha256:3198b18471892718923712837192831287312893712893712897312db1a3bc73"}
)
func setupTest(t *testing.T) {
test.InitDatabaseFromEnv()
// register projAdmin and assign project admin role
aliceID, err := dao.Register(alice)
bobID, err := dao.Register(bob)
eveID, err := dao.Register(eve)
if err != nil {
t.Errorf("register user error %v", err)
}
// Create Project
ctx := orm.NewContext(context.Background(), dao.GetOrmer())
proID1, err := proctl.Ctl.Create(ctx, &testPro1)
proID2, err := proctl.Ctl.Create(ctx, &testPro2)
if err != nil {
t.Errorf("project creating %v", err)
}
testPro1.ProjectID = proID1
testPro2.ProjectID = proID2
// Create quota for project
quotactl.Ctl.Create(ctx, "project", strconv.Itoa(int(testPro1.ProjectID)), rs1)
quotactl.Ctl.Create(ctx, "project", strconv.Itoa(int(testPro2.ProjectID)), rs2)
if err != nil {
t.Errorf("add project error %v", err)
}
// Add repo to project
repo1.ProjectID = testPro1.ProjectID
repo1ID, err := repository.Mgr.Create(ctx, &repo1)
repo1.RepositoryID = repo1ID
repo2.ProjectID = testPro2.ProjectID
repo2ID, err := repository.Mgr.Create(ctx, &repo2)
repo2.RepositoryID = repo2ID
if err != nil {
t.Errorf("add repo error %v", err)
}
// Add artifacts
art1.ProjectID = testPro1.ProjectID
art1.RepositoryID = repo1ID
art1.PushTime = time.Now()
_, err = artifact.Mgr.Create(ctx, &art1)
art2.ProjectID = testPro2.ProjectID
art2.RepositoryID = repo2ID
art2.PushTime = time.Now()
_, err = artifact.Mgr.Create(ctx, &art2)
if err != nil {
t.Errorf("add repo error %v", err)
}
// Add member to project
pmIDs = make([]int, 0)
alice.UserID, bob.UserID, eve.UserID = int(aliceID), int(bobID), int(eveID)
p1m1ID, err := project.AddProjectMember(models.Member{ProjectID: proID1, Role: common.RoleDeveloper, EntityID: int(aliceID), EntityType: common.UserMember})
p2m1ID, err := project.AddProjectMember(models.Member{ProjectID: proID2, Role: common.RoleMaintainer, EntityID: int(bobID), EntityType: common.UserMember})
p2m2ID, err := project.AddProjectMember(models.Member{ProjectID: proID2, Role: common.RoleMaintainer, EntityID: int(eveID), EntityType: common.UserMember})
if err != nil {
t.Errorf("add project member error %v", err)
}
pmIDs = append(pmIDs, p1m1ID, p2m1ID, p2m2ID)
}
func tearDownTest(t *testing.T) {
dao.GetOrmer().Raw("delete from project_member where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from project_metadata where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from quota where reference=\"project\" and reference_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from quota_usage where reference=\"project\" and reference_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from project where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from artifact where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from repository where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from cve_allowlist where project_id in (?, ?)", []int64{testPro1.ProjectID, testPro2.ProjectID}).Exec()
dao.GetOrmer().Raw("delete from harbor_user where user_id in (?, ?, ?)", []int{alice.UserID, bob.UserID, eve.UserID}).Exec()
}
type PorjectCollectorTestSuite struct {
suite.Suite
}
func (c *PorjectCollectorTestSuite) TestProjectCollector() {
pMap := make(map[int64]*projectInfo)
updateProjectBasicInfo(pMap)
updateProjectMemberInfo(pMap)
updateProjectRepoInfo(pMap)
updateProjectArtifactInfo(pMap)
c.Equalf(testPro1.ProjectID, pMap[testPro1.ProjectID].ProjectID, "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].ProjectID, testPro1.ProjectID, "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].Name, testPro1.Name, "pMap %v", pMap)
c.Equalf(strconv.FormatBool(pMap[testPro1.ProjectID].Public), testPro1.Metadata["public"], "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].Quota, "{\"storage\": 100}", "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].Usage, "{\"storage\": 0}", "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].MemberTotal, float64(2), "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].PullTotal, float64(0), "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].Artifact.ArtifactTotal, float64(1), "pMap %v", pMap)
c.Equalf(pMap[testPro1.ProjectID].Artifact.ArtifactType, "IMAGE", "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].ProjectID, testPro2.ProjectID, "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].Name, testPro2.Name, "pMap %v", pMap)
c.Equalf(strconv.FormatBool(pMap[testPro2.ProjectID].Public), testPro2.Metadata["public"], "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].Quota, "{\"storage\": 200}", "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].Usage, "{\"storage\": 0}", "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].MemberTotal, float64(3), "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].PullTotal, float64(0), "pMap %v", pMap)
c.Equalf(pMap[testPro2.ProjectID].Artifact.ArtifactTotal, float64(1), "pMap %v", pMap)
}
func TestPorjectCollectorTestSuite(t *testing.T) {
setupTest(t)
defer tearDownTest(t)
suite.Run(t, new(PorjectCollectorTestSuite))
}

View File

@ -0,0 +1,110 @@
package exporter
import (
"reflect"
"testing"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/suite"
)
type SysCollectorSuite struct {
suite.Suite
}
func (c *SysCollectorSuite) SetupTest() {
CacheInit(&Opt{
CacheDuration: 1,
})
}
func TestNewSystemInfoCollector(t *testing.T) {
type args struct {
hbrCli *HarborClient
}
tests := []struct {
name string
args args
want *SystemInfoCollector
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewSystemInfoCollector(tt.args.hbrCli); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewSystemInfoCollector() = %v, want %v", got, tt.want)
}
})
}
}
func TestSystemInfoCollector_Describe(t *testing.T) {
type fields struct {
HarborClient *HarborClient
}
type args struct {
c chan<- *prometheus.Desc
}
tests := []struct {
name string
fields fields
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hc := &SystemInfoCollector{
HarborClient: tt.fields.HarborClient,
}
hc.Describe(tt.args.c)
})
}
}
func TestSystemInfoCollector_Collect(t *testing.T) {
type fields struct {
HarborClient *HarborClient
}
type args struct {
c chan<- prometheus.Metric
}
tests := []struct {
name string
fields fields
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hc := &SystemInfoCollector{
HarborClient: tt.fields.HarborClient,
}
hc.Collect(tt.args.c)
})
}
}
func TestSystemInfoCollector_getSysInfo(t *testing.T) {
type fields struct {
HarborClient *HarborClient
}
tests := []struct {
name string
fields fields
want []prometheus.Metric
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hc := &SystemInfoCollector{
HarborClient: tt.fields.HarborClient,
}
if got := hc.getSysInfo(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("SystemInfoCollector.getSysInfo() = %v, want %v", got, tt.want)
}
})
}
}