diff --git a/src/controller/immutable/controller_test.go b/src/controller/immutable/controller_test.go index 334629080..ab5eebb09 100644 --- a/src/controller/immutable/controller_test.go +++ b/src/controller/immutable/controller_test.go @@ -1,11 +1,12 @@ package immutable import ( + "testing" + "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/lib/q" - "github.com/goharbor/harbor/src/pkg/project" + "github.com/goharbor/harbor/src/pkg" proModels "github.com/goharbor/harbor/src/pkg/project/models" - "testing" "github.com/goharbor/harbor/src/common/utils/test" "github.com/goharbor/harbor/src/pkg/immutable/model" @@ -39,12 +40,12 @@ func (s *ControllerTestSuite) TestImmutableRule() { var err error ctx := s.Context() - projectID, err := project.Mgr.Create(ctx, &proModels.Project{ + projectID, err := pkg.ProjectMgr.Create(ctx, &proModels.Project{ Name: "testimmutablerule", OwnerID: 1, }) if s.Nil(err) { - defer project.Mgr.Delete(ctx, projectID) + defer pkg.ProjectMgr.Delete(ctx, projectID) } rule := &model.Metadata{ diff --git a/src/controller/member/controller.go b/src/controller/member/controller.go index 86db65286..cc3fe0f9e 100644 --- a/src/controller/member/controller.go +++ b/src/controller/member/controller.go @@ -22,6 +22,7 @@ import ( "github.com/goharbor/harbor/src/core/auth" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/member" "github.com/goharbor/harbor/src/pkg/member/models" "github.com/goharbor/harbor/src/pkg/project" @@ -81,7 +82,7 @@ type controller struct { // NewController ... func NewController() Controller { - return &controller{mgr: member.Mgr, projectMgr: project.Mgr, userManager: user.New()} + return &controller{mgr: member.Mgr, projectMgr: pkg.ProjectMgr, userManager: user.New()} } func (c *controller) Count(ctx context.Context, projectNameOrID interface{}, query *q.Query) (int, error) { diff --git a/src/controller/project/controller.go b/src/controller/project/controller.go index ade14a6ea..fbd45d280 100644 --- a/src/controller/project/controller.go +++ b/src/controller/project/controller.go @@ -24,6 +24,7 @@ import ( "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/orm" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/allowlist" "github.com/goharbor/harbor/src/pkg/notification" "github.com/goharbor/harbor/src/pkg/project" @@ -68,7 +69,7 @@ type Controller interface { // NewController creates an instance of the default project controller func NewController() Controller { return &controller{ - projectMgr: project.Mgr, + projectMgr: pkg.ProjectMgr, metaMgr: metadata.Mgr, allowlistMgr: allowlist.NewDefaultManager(), userMgr: user.Mgr, diff --git a/src/controller/quota/driver/project/util.go b/src/controller/quota/driver/project/util.go index 7ad7a83f2..abf83e10e 100644 --- a/src/controller/quota/driver/project/util.go +++ b/src/controller/quota/driver/project/util.go @@ -16,13 +16,14 @@ package project import ( "context" - proModels "github.com/goharbor/harbor/src/pkg/project/models" "strconv" + "github.com/goharbor/harbor/src/pkg" + proModels "github.com/goharbor/harbor/src/pkg/project/models" + "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/q" - "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/user" "github.com/graph-gophers/dataloader" ) @@ -45,7 +46,7 @@ func getProjectsBatchFn(ctx context.Context, keys dataloader.Keys) []*dataloader projectIDs = append(projectIDs, id) } - projects, err := project.Mgr.List(ctx, q.New(q.KeyWords{"project_id__in": projectIDs})) + projects, err := pkg.ProjectMgr.List(ctx, q.New(q.KeyWords{"project_id__in": projectIDs})) if err != nil { return handleError(err) } diff --git a/src/controller/registry/controller.go b/src/controller/registry/controller.go index 862eae48e..5cda26933 100644 --- a/src/controller/registry/controller.go +++ b/src/controller/registry/controller.go @@ -23,6 +23,7 @@ import ( "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/reg" "github.com/goharbor/harbor/src/pkg/reg/model" @@ -64,7 +65,7 @@ func NewController() Controller { return &controller{ regMgr: reg.Mgr, repMgr: replication.Mgr, - proMgr: project.Mgr, + proMgr: pkg.ProjectMgr, } } diff --git a/src/controller/repository/controller.go b/src/controller/repository/controller.go index 466a3c2cc..22a503cb8 100644 --- a/src/controller/repository/controller.go +++ b/src/controller/repository/controller.go @@ -60,7 +60,7 @@ type Controller interface { // NewController creates an instance of the default repository controller func NewController() Controller { return &controller{ - proMgr: project.Mgr, + proMgr: pkg.ProjectMgr, repoMgr: repository.Mgr, artMgr: pkg.ArtifactMgr, artCtl: artifact.Ctl, diff --git a/src/controller/retention/controller.go b/src/controller/retention/controller.go index 3be7e1719..fb754d41e 100644 --- a/src/controller/retention/controller.go +++ b/src/controller/retention/controller.go @@ -22,6 +22,7 @@ import ( "github.com/goharbor/harbor/src/jobservice/job" "github.com/goharbor/harbor/src/jobservice/logger" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/repository" "github.com/goharbor/harbor/src/pkg/retention" @@ -390,13 +391,13 @@ func (r *defaultController) UpdateTaskInfo(ctx context.Context, taskID int64, to // NewController ... func NewController() Controller { retentionMgr := retention.NewManager() - retentionLauncher := retention.NewLauncher(project.Mgr, repository.Mgr, retentionMgr, task.ExecMgr, task.Mgr) + retentionLauncher := retention.NewLauncher(pkg.ProjectMgr, repository.Mgr, retentionMgr, task.ExecMgr, task.Mgr) return &defaultController{ manager: retentionMgr, execMgr: task.ExecMgr, taskMgr: task.Mgr, launcher: retentionLauncher, - projectManager: project.Mgr, + projectManager: pkg.ProjectMgr, repositoryMgr: repository.Mgr, scheduler: scheduler.Sched, } diff --git a/src/controller/robot/controller.go b/src/controller/robot/controller.go index 81503e966..c44b84109 100644 --- a/src/controller/robot/controller.go +++ b/src/controller/robot/controller.go @@ -12,6 +12,7 @@ import ( "github.com/goharbor/harbor/src/lib/errors" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/permission/types" "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/rbac" @@ -57,7 +58,7 @@ type controller struct { func NewController() Controller { return &controller{ robotMgr: robot.Mgr, - proMgr: project.Mgr, + proMgr: pkg.ProjectMgr, rbacMgr: rbac.Mgr, } } diff --git a/src/core/auth/ldap/ldap_test.go b/src/core/auth/ldap/ldap_test.go index d26493505..84a87374b 100644 --- a/src/core/auth/ldap/ldap_test.go +++ b/src/core/auth/ldap/ldap_test.go @@ -25,11 +25,11 @@ import ( "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/orm" + "github.com/goharbor/harbor/src/pkg" _ "github.com/goharbor/harbor/src/pkg/config/db" _ "github.com/goharbor/harbor/src/pkg/config/inmemory" "github.com/goharbor/harbor/src/pkg/member" memberModels "github.com/goharbor/harbor/src/pkg/member/models" - "github.com/goharbor/harbor/src/pkg/project" userpkg "github.com/goharbor/harbor/src/pkg/user" userDao "github.com/goharbor/harbor/src/pkg/user/dao" "github.com/goharbor/harbor/src/pkg/usergroup" @@ -382,7 +382,7 @@ func TestSearchAndOnBoardUser(t *testing.T) { func TestAddProjectMemberWithLdapUser(t *testing.T) { memberMgr := member.Mgr ctx := orm.Context() - currentProject, err := project.Mgr.Get(ctx, "member_test_01") + currentProject, err := pkg.ProjectMgr.Get(ctx, "member_test_01") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } @@ -402,7 +402,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) { t.Errorf("Error occurred in AddOrUpdateProjectMember: pmid:%v", pmid) } - currentProject, err = project.Mgr.Get(ctx, "member_test_02") + currentProject, err = pkg.ProjectMgr.Get(ctx, "member_test_02") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } @@ -424,7 +424,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) { func TestAddProjectMemberWithLdapGroup(t *testing.T) { memberMgr := member.Mgr ctx := orm.Context() - currentProject, err := project.Mgr.Get(ctx, "member_test_01") + currentProject, err := pkg.ProjectMgr.Get(ctx, "member_test_01") if err != nil { t.Errorf("Error occurred when GetProjectByName: %v", err) } diff --git a/src/migration/artifact.go b/src/migration/artifact.go index 7bd52223d..d08dd2f2d 100644 --- a/src/migration/artifact.go +++ b/src/migration/artifact.go @@ -22,13 +22,12 @@ import ( "github.com/goharbor/harbor/src/lib/q" "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/artifact" - "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/repository" ) func abstractArtData(ctx context.Context) error { abstractor := art.NewAbstractor() - pros, err := project.Mgr.List(ctx, nil) + pros, err := pkg.ProjectMgr.List(ctx, nil) if err != nil { return err } diff --git a/src/pkg/cached/manager.go b/src/pkg/cached/manager.go index f5356d902..80b19c23d 100644 --- a/src/pkg/cached/manager.go +++ b/src/pkg/cached/manager.go @@ -25,6 +25,8 @@ const ( // Resource type definitions // ResourceTypeArtifact defines artifact type. ResourceTypeArtifact = "artifact" + // ResourceTypeProject defines project type. + ResourceTypeProject = "project" ) // Manager is the interface for resource cache manager. diff --git a/src/pkg/cached/project/redis/manager.go b/src/pkg/cached/project/redis/manager.go new file mode 100644 index 000000000..496330a8b --- /dev/null +++ b/src/pkg/cached/project/redis/manager.go @@ -0,0 +1,202 @@ +// Copyright Project Harbor Authors +// +// 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 redis + +import ( + "context" + "time" + + "github.com/goharbor/harbor/src/common/utils" + libcache "github.com/goharbor/harbor/src/lib/cache" + "github.com/goharbor/harbor/src/lib/config" + "github.com/goharbor/harbor/src/lib/errors" + "github.com/goharbor/harbor/src/lib/log" + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/lib/retry" + "github.com/goharbor/harbor/src/pkg/cached" + "github.com/goharbor/harbor/src/pkg/project" + "github.com/goharbor/harbor/src/pkg/project/models" +) + +var _ CachedManager = &manager{} + +// CachedManager is the interface combines raw resource manager and cached manager for better extension. +type CachedManager interface { + // Manager is the raw resource manager. + project.Manager + // Manager is the common interface for resource cache. + cached.Manager +} + +// manager is the cached manager implemented by redis. +type manager struct { + // delegator delegates the raw crud to DAO. + delegator project.Manager + // client returns the redis cache client. + client func() libcache.Cache + // keyBuilder builds cache object key. + keyBuilder *cached.ObjectKey + // lifetime is the cache life time. + lifetime time.Duration +} + +// NewManager returns the redis cache manager. +func NewManager(m project.Manager) *manager { + return &manager{ + delegator: m, + client: func() libcache.Cache { return libcache.Default() }, + keyBuilder: cached.NewObjectKey(cached.ResourceTypeProject), + lifetime: time.Duration(config.CacheExpireHours()) * time.Hour, + } +} + +func (m *manager) Create(ctx context.Context, project *models.Project) (int64, error) { + return m.delegator.Create(ctx, project) +} + +func (m *manager) Count(ctx context.Context, query *q.Query) (total int64, err error) { + return m.delegator.Count(ctx, query) +} + +func (m *manager) List(ctx context.Context, query *q.Query) ([]*models.Project, error) { + return m.delegator.List(ctx, query) +} + +func (m *manager) ListRoles(ctx context.Context, projectID int64, userID int, groupIDs ...int) ([]int, error) { + return m.delegator.ListRoles(ctx, projectID, userID, groupIDs...) +} + +func (m *manager) Delete(ctx context.Context, id int64) error { + p, err := m.Get(ctx, id) + if err != nil { + return err + } + + // pass on delete operation + if err := m.delegator.Delete(ctx, id); err != nil { + return err + } + // clean cache + m.cleanUp(ctx, p) + return nil +} + +func (m *manager) Get(ctx context.Context, idOrName interface{}) (*models.Project, error) { + var ( + key string + err error + ) + + id, name, err := utils.ParseProjectIDOrName(idOrName) + if err != nil { + return nil, err + } + + if id != 0 { + key, err = m.keyBuilder.Format("id", id) + if err != nil { + return nil, err + } + } + + if name != "" { + key, err = m.keyBuilder.Format("name", name) + if err != nil { + return nil, err + } + } + + p := &models.Project{} + if err = m.client().Fetch(ctx, key, p); err == nil { + return p, nil + } + + log.Debugf("get project %v from cache error: %v, will query from database.", idOrName, err) + + p, err = m.delegator.Get(ctx, idOrName) + if err != nil { + return nil, err + } + + if err = m.client().Save(ctx, key, p, m.lifetime); err != nil { + // log error if save to cache failed + log.Debugf("save project %s to cache error: %v", p.Name, err) + } + + return p, nil +} + +// cleanUp cleans up data in cache. +func (m *manager) cleanUp(ctx context.Context, p *models.Project) { + // clean index by id + idIdx, err := m.keyBuilder.Format("id", p.ProjectID) + if err != nil { + log.Errorf("format project id key error: %v", err) + } else { + // retry to avoid dirty data + if err = retry.Retry(func() error { return m.client().Delete(ctx, idIdx) }); err != nil { + log.Errorf("delete project cache key %s error: %v", idIdx, err) + } + } + + // clean index by name + nameIdx, err := m.keyBuilder.Format("name", p.Name) + if err != nil { + log.Errorf("format project name key error: %v", err) + } else { + if err = retry.Retry(func() error { return m.client().Delete(ctx, nameIdx) }); err != nil { + log.Errorf("delete project cache key %s error: %v", nameIdx, err) + } + } +} + +func (m *manager) ResourceType(ctx context.Context) string { + return cached.ResourceTypeProject +} + +func (m *manager) CountCache(ctx context.Context) (int64, error) { + // prefix is resource type + keys, err := m.client().Keys(ctx, m.ResourceType(ctx)) + if err != nil { + return 0, err + } + + return int64(len(keys)), nil +} + +func (m *manager) DeleteCache(ctx context.Context, key string) error { + return m.client().Delete(ctx, key) +} + +func (m *manager) FlushAll(ctx context.Context) error { + // prefix is resource type + keys, err := m.client().Keys(ctx, m.ResourceType(ctx)) + if err != nil { + return err + } + + var errs errors.Errors + for _, key := range keys { + if err = m.client().Delete(ctx, key); err != nil { + errs = append(errs, err) + } + } + + if errs.Len() > 0 { + return errs + } + + return nil +} diff --git a/src/pkg/cached/project/redis/manager_test.go b/src/pkg/cached/project/redis/manager_test.go new file mode 100644 index 000000000..65b8effb2 --- /dev/null +++ b/src/pkg/cached/project/redis/manager_test.go @@ -0,0 +1,139 @@ +// Copyright Project Harbor Authors +// +// 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 redis + +import ( + "context" + "errors" + "testing" + + "github.com/goharbor/harbor/src/lib/cache" + "github.com/goharbor/harbor/src/lib/q" + "github.com/goharbor/harbor/src/pkg/project/models" + testcache "github.com/goharbor/harbor/src/testing/lib/cache" + "github.com/goharbor/harbor/src/testing/mock" + testProject "github.com/goharbor/harbor/src/testing/pkg/project" + + "github.com/stretchr/testify/suite" +) + +type managerTestSuite struct { + suite.Suite + cachedManager CachedManager + projectMgr *testProject.Manager + cache *testcache.Cache + ctx context.Context +} + +func (m *managerTestSuite) SetupTest() { + m.projectMgr = &testProject.Manager{} + m.cache = &testcache.Cache{} + m.cachedManager = NewManager( + m.projectMgr, + ) + m.cachedManager.(*manager).client = func() cache.Cache { return m.cache } + m.ctx = context.TODO() +} + +func (m *managerTestSuite) TestCreate() { + m.projectMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) + id, err := m.cachedManager.Create(m.ctx, &models.Project{}) + m.NoError(err) + m.Equal(int64(1), id) +} + +func (m *managerTestSuite) TestCount() { + m.projectMgr.On("Count", mock.Anything, mock.Anything).Return(int64(100), nil) + c, err := m.cachedManager.Count(m.ctx, q.New(q.KeyWords{})) + m.NoError(err) + m.Equal(int64(100), c) +} + +func (m *managerTestSuite) List() { + m.projectMgr.On("List", mock.Anything, mock.Anything).Return([]*models.Project{}, nil) + ps, err := m.cachedManager.List(m.ctx, q.New(q.KeyWords{})) + m.NoError(err) + m.ElementsMatch([]*models.Project{}, ps) +} + +func (m *managerTestSuite) ListRoles() { + m.projectMgr.On("ListRoles", mock.Anything, mock.Anything, mock.Anything).Return([]int{1}, nil) + rs, err := m.cachedManager.ListRoles(m.ctx, 1, 1) + m.NoError(err) + m.Equal([]int{1}, rs) +} + +func (m *managerTestSuite) TestGet() { + // get from cache directly + m.cache.On("Fetch", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + _, err := m.cachedManager.Get(m.ctx, 100) + m.NoError(err, "should get from cache") + m.projectMgr.AssertNotCalled(m.T(), "Get", mock.Anything, mock.Anything) + + // not found in cache, read from dao + m.cache.On("Fetch", mock.Anything, mock.Anything, mock.Anything).Return(cache.ErrNotFound).Once() + m.cache.On("Save", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + m.projectMgr.On("Get", mock.Anything, mock.Anything).Return(&models.Project{}, nil).Once() + _, err = m.cachedManager.Get(m.ctx, 100) + m.NoError(err, "should get from projectMgr") + m.projectMgr.AssertCalled(m.T(), "Get", mock.Anything, mock.Anything) +} + +func (m *managerTestSuite) TestDelete() { + // delete from projectMgr error + errDelete := errors.New("delete failed") + m.projectMgr.On("Delete", mock.Anything, mock.Anything).Return(errDelete).Once() + m.cache.On("Fetch", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + err := m.cachedManager.Delete(m.ctx, 100) + m.ErrorIs(err, errDelete, "delete should error") + m.cache.AssertNotCalled(m.T(), "Delete", mock.Anything, mock.Anything) + + // delete from projectMgr success + m.projectMgr.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() + m.cache.On("Fetch", mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() + m.cache.On("Delete", mock.Anything, mock.Anything).Return(nil).Twice() + err = m.cachedManager.Delete(m.ctx, 100) + m.NoError(err, "delete should success") + m.cache.AssertCalled(m.T(), "Delete", mock.Anything, mock.Anything) +} + +func (m *managerTestSuite) TestResourceType() { + t := m.cachedManager.ResourceType(m.ctx) + m.Equal("project", t) +} + +func (m *managerTestSuite) TestCountCache() { + m.cache.On("Keys", mock.Anything, mock.Anything).Return([]string{"1"}, nil).Once() + c, err := m.cachedManager.CountCache(m.ctx) + m.NoError(err) + m.Equal(int64(1), c) +} + +func (m *managerTestSuite) TestDeleteCache() { + m.cache.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() + err := m.cachedManager.DeleteCache(m.ctx, "key") + m.NoError(err) +} + +func (m *managerTestSuite) TestFlushAll() { + m.cache.On("Keys", mock.Anything, mock.Anything).Return([]string{"1"}, nil).Once() + m.cache.On("Delete", mock.Anything, mock.Anything).Return(nil).Once() + err := m.cachedManager.FlushAll(m.ctx) + m.NoError(err) +} + +func TestManager(t *testing.T) { + suite.Run(t, &managerTestSuite{}) +} diff --git a/src/pkg/factory.go b/src/pkg/factory.go index 718ba81bf..a5cf4f413 100644 --- a/src/pkg/factory.go +++ b/src/pkg/factory.go @@ -15,35 +15,45 @@ package pkg import ( - "sync" - "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/pkg/artifact" - "github.com/goharbor/harbor/src/pkg/cached/artifact/redis" + cachedArtifact "github.com/goharbor/harbor/src/pkg/cached/artifact/redis" + cachedProject "github.com/goharbor/harbor/src/pkg/cached/project/redis" + "github.com/goharbor/harbor/src/pkg/project" ) // Define global resource manager. var ( - // once for only init one time. - once sync.Once // ArtifactMgr is the manager for artifact. ArtifactMgr artifact.Manager + // ProjectMgr is the manager for project. + ProjectMgr project.Manager ) // init initialize mananger for resources func init() { - once.Do(func() { - cacheEnabled := config.CacheEnabled() - initArtifactManager(cacheEnabled) - }) + cacheEnabled := config.CacheEnabled() + initArtifactMgr(cacheEnabled) + initProjectMgr(cacheEnabled) + } -func initArtifactManager(cacheEnabled bool) { +func initArtifactMgr(cacheEnabled bool) { artMgr := artifact.NewManager() // check cache enable if cacheEnabled { - ArtifactMgr = redis.NewManager(artMgr) + ArtifactMgr = cachedArtifact.NewManager(artMgr) } else { ArtifactMgr = artMgr } } + +func initProjectMgr(cacheEnabled bool) { + projectMgr := project.New() + // check cache enable + if cacheEnabled { + ProjectMgr = cachedProject.NewManager(projectMgr) + } else { + ProjectMgr = projectMgr + } +} diff --git a/src/pkg/factory_test.go b/src/pkg/factory_test.go index ee48fa156..c2e2934b0 100644 --- a/src/pkg/factory_test.go +++ b/src/pkg/factory_test.go @@ -18,19 +18,30 @@ import ( "testing" "github.com/goharbor/harbor/src/pkg/artifact" - "github.com/goharbor/harbor/src/pkg/cached/artifact/redis" + cachedArtifact "github.com/goharbor/harbor/src/pkg/cached/artifact/redis" + cachedProject "github.com/goharbor/harbor/src/pkg/cached/project/redis" + "github.com/goharbor/harbor/src/pkg/project" "github.com/stretchr/testify/assert" ) -func TestInit(t *testing.T) { +func TestInitArtifactMgr(t *testing.T) { // cache not enable - // artifact assert.NotNil(t, ArtifactMgr) assert.IsType(t, artifact.NewManager(), ArtifactMgr) // cache enable - initArtifactManager(true) - // artifact + initArtifactMgr(true) assert.NotNil(t, ArtifactMgr) - assert.IsType(t, redis.NewManager(artifact.NewManager()), ArtifactMgr) + assert.IsType(t, cachedArtifact.NewManager(artifact.NewManager()), ArtifactMgr) +} + +func TestInitProjectMgr(t *testing.T) { + // cache not enable + assert.NotNil(t, ProjectMgr) + assert.IsType(t, project.New(), ProjectMgr) + + // cache enable + initProjectMgr(true) + assert.NotNil(t, ProjectMgr) + assert.IsType(t, cachedProject.NewManager(project.New()), ProjectMgr) } diff --git a/src/pkg/member/dao/dao_test.go b/src/pkg/member/dao/dao_test.go index ecdb82da0..01bf7301d 100644 --- a/src/pkg/member/dao/dao_test.go +++ b/src/pkg/member/dao/dao_test.go @@ -16,10 +16,13 @@ package dao import ( "database/sql" + "testing" + "github.com/goharbor/harbor/src/common" _ "github.com/goharbor/harbor/src/common/dao" testDao "github.com/goharbor/harbor/src/common/dao" "github.com/goharbor/harbor/src/lib/orm" + "github.com/goharbor/harbor/src/pkg" "github.com/goharbor/harbor/src/pkg/member/models" "github.com/goharbor/harbor/src/pkg/project" "github.com/goharbor/harbor/src/pkg/user" @@ -28,7 +31,6 @@ import ( ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model" htesting "github.com/goharbor/harbor/src/testing" "github.com/stretchr/testify/suite" - "testing" ) type DaoTestSuite struct { @@ -67,7 +69,7 @@ func (s *DaoTestSuite) SetupSuite() { "delete from project_member where id > 1", } testDao.PrepareTestData(clearSqls, initSqls) - s.projectMgr = project.Mgr + s.projectMgr = pkg.ProjectMgr s.userMgr = user.Mgr ctx := s.Context() proj, err := s.projectMgr.Get(ctx, "member_test_01") diff --git a/src/pkg/project/manager.go b/src/pkg/project/manager.go index 443ddb945..5c072456d 100644 --- a/src/pkg/project/manager.go +++ b/src/pkg/project/manager.go @@ -26,11 +26,6 @@ import ( "github.com/goharbor/harbor/src/pkg/project/models" ) -var ( - // Mgr is the global project manager - Mgr = New() -) - // Manager is used for project management type Manager interface { // Create create project instance diff --git a/src/server/middleware/immutable/pushmf_test.go b/src/server/middleware/immutable/pushmf_test.go index 296f17661..740141152 100644 --- a/src/server/middleware/immutable/pushmf_test.go +++ b/src/server/middleware/immutable/pushmf_test.go @@ -12,7 +12,6 @@ import ( "github.com/goharbor/harbor/src/controller/immutable" "github.com/goharbor/harbor/src/pkg" - "github.com/goharbor/harbor/src/pkg/project" proModels "github.com/goharbor/harbor/src/pkg/project/models" "github.com/goharbor/harbor/src/common/dao" @@ -75,7 +74,7 @@ func randomString(n int) string { } func (suite *HandlerSuite) addProject(ctx context.Context, projectName string) int64 { - projectID, err := project.Mgr.Create(ctx, &proModels.Project{ + projectID, err := pkg.ProjectMgr.Create(ctx, &proModels.Project{ Name: projectName, OwnerID: 1, }) @@ -163,7 +162,7 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() { tagID := suite.addTags(ctx, repoID, afID, "release-1.10") defer func() { - project.Mgr.Delete(ctx, projectID) + pkg.ProjectMgr.Delete(ctx, projectID) pkg.ArtifactMgr.Delete(ctx, afID) repository.Mgr.Delete(ctx, repoID) tag.Mgr.Delete(ctx, tagID)