fix catalog performance issue (#14120)

Signed-off-by: Wang Yan <wangyan@vmware.com>
This commit is contained in:
Wang Yan 2021-01-31 21:31:21 +08:00 committed by GitHub
parent a211b0c9d7
commit 1b85c67f63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 339 additions and 255 deletions

View File

@ -15,6 +15,7 @@
package middlewares
import (
"github.com/goharbor/harbor/src/lib"
"net/http"
"regexp"
@ -51,6 +52,7 @@ var (
middleware.MethodAndPathSkipper(http.MethodGet, distribution.BlobURLRegexp),
middleware.MethodAndPathSkipper(http.MethodPatch, distribution.BlobUploadURLRegexp),
middleware.MethodAndPathSkipper(http.MethodPut, distribution.BlobUploadURLRegexp),
middleware.MethodAndPathSkipper(http.MethodGet, lib.V2CatalogURLRe),
pingSkipper,
}

View File

@ -16,6 +16,7 @@ package dao
import (
"context"
"fmt"
o "github.com/astaxie/beego/orm"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib/errors"
@ -40,6 +41,8 @@ type DAO interface {
Update(ctx context.Context, repository *models.RepoRecord, props ...string) (err error)
// AddPullCount increase one pull count for the specified repository
AddPullCount(ctx context.Context, id int64) error
// NonEmptyRepos returns the repositories without any artifact or all the artifacts are untagged.
NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error)
}
// New returns an instance of the default DAO
@ -155,3 +158,19 @@ func (d *dao) AddPullCount(ctx context.Context, id int64) error {
}
return nil
}
func (d *dao) NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error) {
var repos []*models.RepoRecord
ormer, err := orm.FromContext(ctx)
if err != nil {
return nil, err
}
sql := fmt.Sprintf(`select r.* from repository as r LEFT JOIN tag as t on r.repository_id = t.repository_id where t.repository_id is not null;`)
_, err = ormer.Raw(sql).QueryRows(&repos)
if err != nil {
return repos, err
}
return repos, nil
}

View File

@ -23,6 +23,10 @@ import (
"github.com/goharbor/harbor/src/lib/errors"
"github.com/goharbor/harbor/src/lib/orm"
"github.com/goharbor/harbor/src/lib/q"
af_dao "github.com/goharbor/harbor/src/pkg/artifact/dao"
tag_dao "github.com/goharbor/harbor/src/pkg/tag/dao"
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/suite"
"testing"
"time"
@ -34,13 +38,17 @@ var (
type daoTestSuite struct {
suite.Suite
dao DAO
id int64
ctx context.Context
dao DAO
tagDao tag_dao.DAO
afDao af_dao.DAO
id int64
ctx context.Context
}
func (d *daoTestSuite) SetupSuite() {
d.dao = New()
d.tagDao = tag_dao.New()
d.afDao = af_dao.New()
common_dao.PrepareTestForPostgresSQL()
d.ctx = orm.NewContext(nil, beegoorm.NewOrm())
}
@ -182,6 +190,57 @@ func (d *daoTestSuite) TestAddPullCount() {
d.dao.Delete(d.ctx, id)
}
func (d *daoTestSuite) TestEmptyRepos() {
repository := &models.RepoRecord{
Name: "TestEmptyRepos",
ProjectID: 10,
Description: "test pull count",
PullCount: 1,
}
id, err := d.dao.Create(d.ctx, repository)
d.Require().Nil(err)
art := &af_dao.Artifact{
Type: "IMAGE",
MediaType: v1.MediaTypeImageConfig,
ManifestMediaType: v1.MediaTypeImageIndex,
ProjectID: 1,
RepositoryID: 1,
RepositoryName: "library/hello-world",
Digest: "parent_digest",
PushTime: time.Now(),
PullTime: time.Now(),
Annotations: `{"anno1":"value1"}`,
}
afID, err := d.afDao.Create(d.ctx, art)
d.Require().Nil(err)
tag := &tag.Tag{
RepositoryID: id,
ArtifactID: afID,
Name: "latest",
PushTime: time.Now(),
PullTime: time.Now(),
}
_, err = d.tagDao.Create(d.ctx, tag)
d.Require().Nil(err)
repos, err := d.dao.NonEmptyRepos(d.ctx)
d.Require().Nil(err)
var success bool
for _, repo := range repos {
if repo.Name == "TestEmptyRepos" {
success = true
break
}
}
if !success {
d.Fail("TestEmptyRepos failure")
}
}
func TestDaoTestSuite(t *testing.T) {
suite.Run(t, &daoTestSuite{})
}

View File

@ -43,6 +43,8 @@ type Manager interface {
Update(ctx context.Context, repository *models.RepoRecord, props ...string) (err error)
// AddPullCount increase one pull count for the specified repository
AddPullCount(ctx context.Context, id int64) error
// NonEmptyRepos returns the repositories without any artifact or all the artifacts are untagged.
NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error)
}
// New returns a default implementation of Manager
@ -102,3 +104,7 @@ func (m *manager) Update(ctx context.Context, repository *models.RepoRecord, pro
func (m *manager) AddPullCount(ctx context.Context, id int64) error {
return m.dao.AddPullCount(ctx, id)
}
func (m *manager) NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error) {
return m.dao.NonEmptyRepos(ctx)
}

View File

@ -17,63 +17,31 @@ package repository
import (
"context"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/testing/pkg/repository/dao"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/suite"
"testing"
)
type fakeDao struct {
mock.Mock
}
func (f *fakeDao) Count(ctx context.Context, query *q.Query) (int64, error) {
args := f.Called()
return int64(args.Int(0)), args.Error(1)
}
func (f *fakeDao) List(ctx context.Context, query *q.Query) ([]*models.RepoRecord, error) {
args := f.Called()
return args.Get(0).([]*models.RepoRecord), args.Error(1)
}
func (f *fakeDao) Get(ctx context.Context, id int64) (*models.RepoRecord, error) {
args := f.Called()
return args.Get(0).(*models.RepoRecord), args.Error(1)
}
func (f *fakeDao) Create(ctx context.Context, repository *models.RepoRecord) (int64, error) {
args := f.Called()
return int64(args.Int(0)), args.Error(1)
}
func (f *fakeDao) Delete(ctx context.Context, id int64) error {
args := f.Called()
return args.Error(0)
}
func (f *fakeDao) Update(ctx context.Context, repository *models.RepoRecord, props ...string) error {
args := f.Called()
return args.Error(0)
}
func (f *fakeDao) AddPullCount(ctx context.Context, id int64) error {
args := f.Called()
return args.Error(0)
}
type managerTestSuite struct {
suite.Suite
mgr *manager
dao *fakeDao
dao *dao.DAO
}
func (m *managerTestSuite) SetupTest() {
m.dao = &fakeDao{}
m.dao = &dao.DAO{}
m.mgr = &manager{
dao: m.dao,
}
}
func (m *managerTestSuite) TestCount() {
m.dao.On("Count", mock.Anything).Return(1, nil)
total, err := m.mgr.Count(nil, nil)
m.Require().Nil(err)
m.Equal(int64(1), total)
m.dao.On("Count", mock.Anything, mock.Anything).Return(int64(1), nil)
n, err := m.mgr.Count(context.Background(), nil)
m.Nil(err)
m.Equal(int64(1), n)
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestList() {
@ -82,11 +50,11 @@ func (m *managerTestSuite) TestList() {
ProjectID: 1,
Name: "library/hello-world",
}
m.dao.On("List", mock.Anything).Return([]*models.RepoRecord{repository}, nil)
repositories, err := m.mgr.List(nil, nil)
m.Require().Nil(err)
m.Equal(1, len(repositories))
m.Equal(repository.RepositoryID, repositories[0].RepositoryID)
m.dao.On("List", mock.Anything, mock.Anything).Return([]*models.RepoRecord{repository}, nil)
rpers, err := m.mgr.List(context.Background(), nil)
m.Nil(err)
m.Equal(1, len(rpers))
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestGet() {
@ -95,8 +63,8 @@ func (m *managerTestSuite) TestGet() {
ProjectID: 1,
Name: "library/hello-world",
}
m.dao.On("Get", mock.Anything).Return(repository, nil)
repo, err := m.mgr.Get(nil, 1)
m.dao.On("Get", mock.Anything, mock.Anything).Return(repository, nil)
repo, err := m.mgr.Get(context.Background(), 1)
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
m.Require().NotNil(repo)
@ -109,8 +77,8 @@ func (m *managerTestSuite) TestGetByName() {
ProjectID: 1,
Name: "library/hello-world",
}
m.dao.On("List", mock.Anything).Return([]*models.RepoRecord{repository}, nil)
repo, err := m.mgr.GetByName(nil, "library/hello-world")
m.dao.On("List", mock.Anything, mock.Anything).Return([]*models.RepoRecord{repository}, nil)
repo, err := m.mgr.GetByName(context.Background(), "library/hello-world")
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
m.Require().NotNil(repo)
@ -118,39 +86,46 @@ func (m *managerTestSuite) TestGetByName() {
}
func (m *managerTestSuite) TestCreate() {
m.dao.On("Create", mock.Anything).Return(1, nil)
id, err := m.mgr.Create(nil, &models.RepoRecord{
ProjectID: 1,
Name: "library/hello-world",
})
m.Require().Nil(err)
m.dao.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil)
_, err := m.mgr.Create(context.Background(), &models.RepoRecord{})
m.Nil(err)
m.dao.AssertExpectations(m.T())
m.Equal(int64(1), id)
}
func (m *managerTestSuite) TestDelete() {
m.dao.On("Delete", mock.Anything).Return(nil)
err := m.mgr.Delete(nil, 1)
m.Require().Nil(err)
m.dao.On("Delete", mock.Anything, mock.Anything).Return(nil)
err := m.mgr.Delete(context.Background(), 1)
m.Nil(err)
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestUpdate() {
m.dao.On("Update", mock.Anything).Return(nil)
err := m.mgr.Update(nil, &models.RepoRecord{
RepositoryID: 1,
})
m.Require().Nil(err)
m.dao.On("Update", mock.Anything, mock.Anything).Return(nil)
err := m.mgr.Update(context.Background(), &models.RepoRecord{})
m.Nil(err)
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestAddPullCount() {
m.dao.On("AddPullCount", mock.Anything).Return(nil)
err := m.mgr.AddPullCount(nil, 1)
m.dao.On("AddPullCount", mock.Anything, mock.Anything).Return(nil)
err := m.mgr.AddPullCount(context.Background(), 1)
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
}
func (m *managerTestSuite) TestNonEmptyRepos() {
repository := &models.RepoRecord{
RepositoryID: 1,
ProjectID: 1,
Name: "library/hello-world",
}
m.dao.On("NonEmptyRepos", mock.Anything).Return([]*models.RepoRecord{repository}, nil)
repo, err := m.mgr.NonEmptyRepos(nil)
m.Require().Nil(err)
m.dao.AssertExpectations(m.T())
m.Equal(repository.RepositoryID, repo[0].RepositoryID)
}
func TestManager(t *testing.T) {
suite.Run(t, &managerTestSuite{})
}

View File

@ -15,14 +15,11 @@
package registry
import (
"context"
"encoding/json"
"fmt"
"github.com/goharbor/harbor/src/controller/artifact"
"github.com/goharbor/harbor/src/controller/repository"
"github.com/goharbor/harbor/src/lib/errors"
lib_http "github.com/goharbor/harbor/src/lib/http"
"github.com/goharbor/harbor/src/lib/q"
"github.com/goharbor/harbor/src/pkg/repository"
"github.com/goharbor/harbor/src/server/registry/util"
"net/http"
"sort"
@ -31,14 +28,12 @@ import (
func newRepositoryHandler() http.Handler {
return &repositoryHandler{
repoCtl: repository.Ctl,
artCtl: artifact.Ctl,
repoMgr: repository.Mgr,
}
}
type repositoryHandler struct {
repoCtl repository.Controller
artCtl artifact.Controller
repoMgr repository.Manager
}
func (r *repositoryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@ -58,8 +53,8 @@ func (r *repositoryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
}
repoNames := make([]string, 0)
// get all repositories
repoRecords, err := r.repoCtl.List(req.Context(), nil)
// get all the non repositories
repoRecords, err := r.repoMgr.NonEmptyRepos(req.Context())
if err != nil {
lib_http.SendError(w, err)
return
@ -69,14 +64,7 @@ func (r *repositoryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request)
return
}
for _, repo := range repoRecords {
valid, err := r.validateRepo(req.Context(), repo.RepositoryID)
if err != nil {
lib_http.SendError(w, err)
return
}
if valid {
repoNames = append(repoNames, repo.Name)
}
repoNames = append(repoNames, repo.Name)
}
sort.Strings(repoNames)
if !withN {
@ -140,34 +128,6 @@ func (r *repositoryHandler) sendResponse(w http.ResponseWriter, req *http.Reques
}
}
// empty repo and all of artifacts are untagged should be filtered out.
func (r *repositoryHandler) validateRepo(ctx context.Context, repositoryID int64) (bool, error) {
arts, err := r.artCtl.List(ctx, &q.Query{
Keywords: map[string]interface{}{
"RepositoryID": repositoryID,
},
}, &artifact.Option{
WithTag: true,
})
if err != nil {
return false, err
}
// empty repo
if len(arts) == 0 {
return false, nil
}
for _, art := range arts {
if len(art.Tags) != 0 {
return true, nil
}
}
// if all of artifact are untagged, filter out
return false, nil
}
type catalogAPIResponse struct {
Repositories []string `json:"repositories"`
}

View File

@ -17,14 +17,9 @@ package registry
import (
"encoding/json"
"github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/controller/artifact"
"github.com/goharbor/harbor/src/controller/repository"
"github.com/goharbor/harbor/src/controller/tag"
pkg_art "github.com/goharbor/harbor/src/pkg/artifact"
model_tag "github.com/goharbor/harbor/src/pkg/tag/model/tag"
artifacttesting "github.com/goharbor/harbor/src/testing/controller/artifact"
repotesting "github.com/goharbor/harbor/src/testing/controller/repository"
"github.com/goharbor/harbor/src/pkg/repository"
"github.com/goharbor/harbor/src/testing/mock"
repotesting "github.com/goharbor/harbor/src/testing/pkg/repository"
"github.com/stretchr/testify/suite"
"net/http"
"net/http/httptest"
@ -33,37 +28,31 @@ import (
type catalogTestSuite struct {
suite.Suite
originalRepoCtl repository.Controller
originalArtCtl artifact.Controller
repoCtl *repotesting.FakeController
artCtl *artifacttesting.Controller
originalRepoMgr repository.Manager
repoMgr *repotesting.FakeManager
}
func (c *catalogTestSuite) SetupSuite() {
c.originalRepoCtl = repository.Ctl
c.originalArtCtl = artifact.Ctl
c.originalRepoMgr = repository.Mgr
}
func (c *catalogTestSuite) SetupTest() {
c.repoCtl = &repotesting.FakeController{}
repository.Ctl = c.repoCtl
c.artCtl = &artifacttesting.Controller{}
artifact.Ctl = c.artCtl
c.repoMgr = &repotesting.FakeManager{}
repository.Mgr = c.repoMgr
}
func (c *catalogTestSuite) TearDownTest() {
}
func (c *catalogTestSuite) TearDownSuite() {
repository.Ctl = c.originalRepoCtl
artifact.Ctl = c.originalArtCtl
repository.Mgr = c.originalRepoMgr
}
func (c *catalogTestSuite) TestCatalog() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
mock.OnAnything(c.repoMgr, "NonEmptyRepos").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
@ -73,22 +62,7 @@ func (c *catalogTestSuite) TestCatalog() {
Name: "busybox",
},
}, nil)
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{
Artifact: pkg_art.Artifact{
ProjectID: 1,
RepositoryID: 1,
},
Tags: []*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
ArtifactID: 1,
},
},
},
},
}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)
@ -102,10 +76,9 @@ func (c *catalogTestSuite) TestCatalog() {
}
func (c *catalogTestSuite) TestCatalogPaginationN1() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog?n=1", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
c.repoMgr.On("NonEmptyRepos").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
@ -115,22 +88,6 @@ func (c *catalogTestSuite) TestCatalogPaginationN1() {
Name: "busybox",
},
}, nil)
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{
Artifact: pkg_art.Artifact{
ProjectID: 1,
RepositoryID: 1,
},
Tags: []*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
ArtifactID: 1,
},
},
},
},
}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)
@ -145,10 +102,9 @@ func (c *catalogTestSuite) TestCatalogPaginationN1() {
}
func (c *catalogTestSuite) TestCatalogPaginationN2() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog?n=3", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
c.repoMgr.On("NonEmptyRepos").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
@ -158,22 +114,6 @@ func (c *catalogTestSuite) TestCatalogPaginationN2() {
Name: "busybox",
},
}, nil)
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{
Artifact: pkg_art.Artifact{
ProjectID: 1,
RepositoryID: 1,
},
Tags: []*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
ArtifactID: 1,
},
},
},
},
}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)
@ -188,10 +128,9 @@ func (c *catalogTestSuite) TestCatalogPaginationN2() {
}
func (c *catalogTestSuite) TestCatalogPaginationN3() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog?last=busybox&n=1", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
c.repoMgr.On("NonEmptyRepos").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
@ -201,22 +140,6 @@ func (c *catalogTestSuite) TestCatalogPaginationN3() {
Name: "busybox",
},
}, nil)
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{
Artifact: pkg_art.Artifact{
ProjectID: 1,
RepositoryID: 1,
},
Tags: []*tag.Tag{
{
Tag: model_tag.Tag{
RepositoryID: 1,
ArtifactID: 1,
},
},
},
},
}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)
@ -230,59 +153,10 @@ func (c *catalogTestSuite) TestCatalogPaginationN3() {
c.Equal("hello-world", ctlg.Repositories[0])
}
func (c *catalogTestSuite) TestCatalogUntaggedArtifact() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
},
{
RepositoryID: 2,
Name: "busybox",
},
}, nil)
// untagged artifact
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{
Artifact: pkg_art.Artifact{
ProjectID: 1,
RepositoryID: 1,
},
},
}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)
var ctlg struct {
Repositories []string `json:"repositories"`
}
decoder := json.NewDecoder(w.Body)
err := decoder.Decode(&ctlg)
c.Nil(err)
c.Equal(0, len(ctlg.Repositories))
}
func (c *catalogTestSuite) TestCatalogEmptyRepo() {
c.SetupTest()
req := httptest.NewRequest(http.MethodGet, "/v2/_catalog", nil)
var w *httptest.ResponseRecorder
c.repoCtl.On("List").Return([]*models.RepoRecord{
{
RepositoryID: 1,
Name: "hello-world",
},
{
RepositoryID: 2,
Name: "busybox",
},
}, nil)
// empty repository
mock.OnAnything(c.artCtl, "List").Return([]*artifact.Artifact{
{},
}, nil)
c.repoMgr.On("NonEmptyRepos").Return([]*models.RepoRecord{}, nil)
w = httptest.NewRecorder()
newRepositoryHandler().ServeHTTP(w, req)
c.Equal(http.StatusOK, w.Code)

View File

@ -32,3 +32,4 @@ package pkg
//go:generate mockery --case snake --dir ../../pkg/rbac/dao --name DAO --output ./rbac/dao --outpkg dao
//go:generate mockery --case snake --dir ../../pkg/robot --name Manager --output ./robot --outpkg robot
//go:generate mockery --case snake --dir ../../pkg/robot/dao --name DAO --output ./robot/dao --outpkg dao
//go:generate mockery --case snake --dir ../../pkg/repository/dao --name DAO --output ./repository/dao --outpkg dao

View File

@ -0,0 +1,178 @@
// Code generated by mockery v2.1.0. DO NOT EDIT.
package dao
import (
context "context"
mock "github.com/stretchr/testify/mock"
models "github.com/goharbor/harbor/src/common/models"
q "github.com/goharbor/harbor/src/lib/q"
)
// DAO is an autogenerated mock type for the DAO type
type DAO struct {
mock.Mock
}
// AddPullCount provides a mock function with given fields: ctx, id
func (_m *DAO) AddPullCount(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// Count provides a mock function with given fields: ctx, query
func (_m *DAO) Count(ctx context.Context, query *q.Query) (int64, error) {
ret := _m.Called(ctx, query)
var r0 int64
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Create provides a mock function with given fields: ctx, repository
func (_m *DAO) Create(ctx context.Context, repository *models.RepoRecord) (int64, error) {
ret := _m.Called(ctx, repository)
var r0 int64
if rf, ok := ret.Get(0).(func(context.Context, *models.RepoRecord) int64); ok {
r0 = rf(ctx, repository)
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *models.RepoRecord) error); ok {
r1 = rf(ctx, repository)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Delete provides a mock function with given fields: ctx, id
func (_m *DAO) Delete(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: ctx, id
func (_m *DAO) Get(ctx context.Context, id int64) (*models.RepoRecord, error) {
ret := _m.Called(ctx, id)
var r0 *models.RepoRecord
if rf, ok := ret.Get(0).(func(context.Context, int64) *models.RepoRecord); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.RepoRecord)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// List provides a mock function with given fields: ctx, query
func (_m *DAO) List(ctx context.Context, query *q.Query) ([]*models.RepoRecord, error) {
ret := _m.Called(ctx, query)
var r0 []*models.RepoRecord
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*models.RepoRecord); ok {
r0 = rf(ctx, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*models.RepoRecord)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NonEmptyRepos provides a mock function with given fields: ctx
func (_m *DAO) NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error) {
ret := _m.Called(ctx)
var r0 []*models.RepoRecord
if rf, ok := ret.Get(0).(func(context.Context) []*models.RepoRecord); ok {
r0 = rf(ctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*models.RepoRecord)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Update provides a mock function with given fields: ctx, repository, props
func (_m *DAO) Update(ctx context.Context, repository *models.RepoRecord, props ...string) error {
_va := make([]interface{}, len(props))
for _i := range props {
_va[_i] = props[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, repository)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.RepoRecord, ...string) error); ok {
r0 = rf(ctx, repository, props...)
} else {
r0 = ret.Error(0)
}
return r0
}

View File

@ -85,3 +85,13 @@ func (f *FakeManager) AddPullCount(ctx context.Context, id int64) error {
args := f.Called()
return args.Error(0)
}
// NonEmptyRepos ...
func (f *FakeManager) NonEmptyRepos(ctx context.Context) ([]*models.RepoRecord, error) {
args := f.Called()
var repository []*models.RepoRecord
if args.Get(0) != nil {
repository = args.Get(0).([]*models.RepoRecord)
}
return repository, args.Error(1)
}