diff --git a/.golangci.yml b/.golangci.yml index a5de08e54..be0ed8766 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -199,6 +199,10 @@ linters: - goheader # checks is file header matches to pattern - misspell # [useless] finds commonly misspelled English words in comments +run: + skip-dirs: + - registry/app/api/controller/mocks + issues: # Maximum count of issues with the same text. # Set to 0 to disable. diff --git a/registry/app/api/controller/metadata/base.go b/registry/app/api/controller/metadata/base.go index ad539382d..5066ca662 100644 --- a/registry/app/api/controller/metadata/base.go +++ b/registry/app/api/controller/metadata/base.go @@ -37,23 +37,8 @@ const MediaTypeImageConfig = "application/vnd.docker.container.image.v1+json" var _ api.StrictServerInterface = (*APIController)(nil) -type RegistryRequestBaseInfo struct { - RootIdentifier string - rootIdentifierID int64 - - RegistryRef string - RegistryIdentifier string - RegistryID int64 - - ParentRef string - parentID int64 - - RegistryType api.RegistryType - PackageType api.PackageType -} - type RegistryRequestInfo struct { - RegistryRequestBaseInfo + *types.RegistryRequestBaseInfo packageTypes []string sortByField string sortByOrder string @@ -82,7 +67,7 @@ type RegistryRequestParams struct { } type ArtifactFilesRequestInfo struct { - RegistryRequestBaseInfo + *types.RegistryRequestBaseInfo sortByField string sortByOrder string offset int @@ -138,7 +123,7 @@ func (c *APIController) GetRegistryRequestInfo( } return &RegistryRequestInfo{ - RegistryRequestBaseInfo: *baseInfo, + RegistryRequestBaseInfo: baseInfo, packageTypes: packageTypes, sortByField: sortByField, sortByOrder: sortByOrder, @@ -415,7 +400,7 @@ func (c *APIController) GetArtifactFilesRequestInfo( } return &ArtifactFilesRequestInfo{ - RegistryRequestBaseInfo: *baseInfo, + RegistryRequestBaseInfo: baseInfo, sortByField: sortByField, sortByOrder: sortByOrder, offset: offset, diff --git a/registry/app/api/controller/metadata/controller.go b/registry/app/api/controller/metadata/controller.go index 8e34a3683..9506fcc37 100644 --- a/registry/app/api/controller/metadata/controller.go +++ b/registry/app/api/controller/metadata/controller.go @@ -16,13 +16,14 @@ package metadata import ( "github.com/harness/gitness/app/auth/authz" - "github.com/harness/gitness/app/services/refcache" urlprovider "github.com/harness/gitness/app/url" "github.com/harness/gitness/audit" + "github.com/harness/gitness/registry/app/api/interfaces" storagedriver "github.com/harness/gitness/registry/app/driver" registryevents "github.com/harness/gitness/registry/app/events" "github.com/harness/gitness/registry/app/pkg/filemanager" "github.com/harness/gitness/registry/app/store" + "github.com/harness/gitness/registry/services/webhook" "github.com/harness/gitness/store/database/dbtx" ) @@ -37,7 +38,7 @@ type APIController struct { TagStore store.TagRepository ManifestStore store.ManifestRepository CleanupPolicyStore store.CleanupPolicyRepository - SpaceFinder SpaceFinder + SpaceFinder interfaces.SpaceFinder tx dbtx.Transactor StorageDriver storagedriver.StorageDriver URLProvider urlprovider.Provider @@ -46,8 +47,8 @@ type APIController struct { ArtifactStore store.ArtifactRepository WebhooksRepository store.WebhooksRepository WebhooksExecutionRepository store.WebhooksExecutionRepository - RegistryMetadataHelper RegistryMetadataHelper - WebhookService WebhookService + RegistryMetadataHelper interfaces.RegistryMetadataHelper + WebhookService webhook.ServiceInterface ArtifactEventReporter registryevents.Reporter DownloadStatRepository store.DownloadStatRepository } @@ -63,7 +64,7 @@ func NewAPIController( cleanupPolicyStore store.CleanupPolicyRepository, imageStore store.ImageRepository, driver storagedriver.StorageDriver, - spaceFinder refcache.SpaceFinder, + spaceFinder interfaces.SpaceFinder, tx dbtx.Transactor, urlProvider urlprovider.Provider, authorizer authz.Authorizer, @@ -71,8 +72,8 @@ func NewAPIController( artifactStore store.ArtifactRepository, webhooksRepository store.WebhooksRepository, webhooksExecutionRepository store.WebhooksExecutionRepository, - registryMetadataHelper RegistryMetadataHelper, - webhookService WebhookService, + registryMetadataHelper interfaces.RegistryMetadataHelper, + webhookService webhook.ServiceInterface, artifactEventReporter registryevents.Reporter, downloadStatRepository store.DownloadStatRepository, ) *APIController { diff --git a/registry/app/api/controller/metadata/create_registry.go b/registry/app/api/controller/metadata/create_registry.go index 14a13bf0b..8c0313873 100644 --- a/registry/app/api/controller/metadata/create_registry.go +++ b/registry/app/api/controller/metadata/create_registry.go @@ -79,7 +79,7 @@ func (c *APIController) CreateRegistry( registry, upstreamproxy, err := c.CreateUpstreamProxyEntity( ctx, registryRequest, - regInfo.parentID, regInfo.rootIdentifierID, + regInfo.ParentID, regInfo.RootIdentifierID, ) var registryID int64 if err != nil { @@ -127,16 +127,16 @@ func (c *APIController) CreateRegistry( } func (c *APIController) createVirtualRegistry( - ctx context.Context, registryRequest artifact.RegistryRequest, regInfo *RegistryRequestBaseInfo, + ctx context.Context, registryRequest artifact.RegistryRequest, regInfo *registrytypes.RegistryRequestBaseInfo, session *auth.Session, parentRef artifact.SpaceRefPathParam, ) (artifact.CreateRegistryResponseObject, error) { - registry, err := CreateRegistryEntity(registryRequest, regInfo.parentID, regInfo.rootIdentifierID) + registry, err := CreateRegistryEntity(registryRequest, regInfo.ParentID, regInfo.RootIdentifierID) if err != nil { return throwCreateRegistry400Error(err), nil } if registry.PackageType != artifact.PackageTypeGENERIC { - err = c.setUpstreamProxyIDs(ctx, registry, registryRequest, regInfo.parentID) + err = c.setUpstreamProxyIDs(ctx, registry, registryRequest, regInfo.ParentID) } if err != nil { return throwCreateRegistry400Error(err), nil @@ -332,7 +332,7 @@ func (c *APIController) CreateUpstreamProxyEntity( } if res.SecretSpacePath != nil && len(*res.SecretSpacePath) > 0 { - upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, + upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.SecretSpacePath) if err != nil { return nil, nil, err @@ -355,7 +355,7 @@ func (c *APIController) CreateUpstreamProxyEntity( default: if res.AccessKeySecretSpacePath != nil && len(*res.AccessKeySecretSpacePath) > 0 { upstreamProxyConfigEntity.UserNameSecretSpaceID, err = - c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath) + c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.AccessKeySecretSpacePath) if err != nil { return nil, nil, err } @@ -366,7 +366,7 @@ func (c *APIController) CreateUpstreamProxyEntity( } if res.SecretKeySpacePath != nil && len(*res.SecretKeySpacePath) > 0 { - upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, + upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.SecretKeySpacePath) if err != nil { return nil, nil, err diff --git a/registry/app/api/controller/metadata/create_registry_test.go b/registry/app/api/controller/metadata/create_registry_test.go new file mode 100644 index 000000000..91976436f --- /dev/null +++ b/registry/app/api/controller/metadata/create_registry_test.go @@ -0,0 +1,483 @@ +// Copyright 2023 Harness, Inc. +// +// 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. + +//nolint:lll,revive // revive:disable:unused-parameter + +package metadata_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/harness/gitness/app/api/request" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/audit" + "github.com/harness/gitness/events" + "github.com/harness/gitness/registry/app/api/controller/metadata" + "github.com/harness/gitness/registry/app/api/controller/mocks" + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + registryevents "github.com/harness/gitness/registry/app/events" + "github.com/harness/gitness/registry/app/pkg/filemanager" + "github.com/harness/gitness/registry/types" + "github.com/harness/gitness/registry/utils" + coretypes "github.com/harness/gitness/types" + gitnessenum "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const ( + // TestRegistryName is the name used for test registries. + testRegistryName = "test-registry" +) + +var ( + // ErrTestConsumerNotNeeded is a sentinel error indicating consumer is not needed in tests. + ErrTestConsumerNotNeeded = errors.New("consumer not needed in tests") +) + +func TestCreateRegistry(t *testing.T) { + space := &coretypes.SpaceCore{ + ID: 1, + Path: "root", + } + + // Create mock event system components. + producer := &mocks.StreamProducer{} + + // Set up producer expectations. + producer.On("Send", mock.Anything, "registry", mock.MatchedBy(func(payload map[string]interface{}) bool { + return payload["action"] == "registry.create" && + payload["registry_id"] == int64(1) && + payload["registry_name"] == testRegistryName + })).Return("", nil).Once() + + // Create events system. + consumerFactory := func(_ string, _ string) (events.StreamConsumer, error) { + // Return a sentinel error to indicate consumer is not needed in tests. + return nil, ErrTestConsumerNotNeeded + } + eventsSystem, err := events.NewSystem(consumerFactory, producer) + if err != nil { + t.Fatalf("Failed to create events system: %v", err) + } + + // Create event reporter. + reporter, err := registryevents.NewReporter(eventsSystem) + if err != nil { + t.Fatalf("Failed to create event reporter: %v", err) + } + eventReporter := *reporter // Use value instead of pointer. + + // Helper mocks and setup complete. + + tests := []struct { + name string + request api.CreateRegistryRequestObject + setupMocks func() *metadata.APIController + expectedResp interface{} + }{ + { + name: "create_virtual_registry_success", + request: api.CreateRegistryRequestObject{ + Body: &api.CreateRegistryJSONRequestBody{ + Identifier: testRegistryName, + ParentRef: utils.StringPtr("root"), + Config: func() *api.RegistryConfig { + config := &api.RegistryConfig{Type: api.RegistryTypeVIRTUAL} + _ = config.FromVirtualConfig(api.VirtualConfig{UpstreamProxies: &[]string{}}) + return config + }(), + PackageType: api.PackageTypeDOCKER, + CleanupPolicy: &[]api.CleanupPolicy{}, + }, + }, + expectedResp: api.CreateRegistry201JSONResponse{ + RegistryResponseJSONResponse: api.RegistryResponseJSONResponse{ + Data: api.Registry{ + Identifier: testRegistryName, + Config: &api.RegistryConfig{ + Type: api.RegistryTypeVIRTUAL, + }, + PackageType: api.PackageTypeDOCKER, + Url: "http://example.com/registry/test-registry", + Description: utils.StringPtr(""), + CreatedAt: utils.StringPtr("-62135596800000"), + ModifiedAt: utils.StringPtr("-62135596800000"), + }, + Status: api.StatusSUCCESS, + }, + }, + setupMocks: func() *metadata.APIController { + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockRegistryRepo := new(mocks.RegistryRepository) + mockSpaceFinder := new(mocks.SpaceFinder) + mockAuthorizer := new(mocks.Authorizer) + mockAuditService := new(mocks.AuditService) + mockCleanupPolicyRepo := new(mocks.CleanupPolicyRepository) + mockTransactor := new(mocks.Transactor) + mockGenericBlobRepo := new(mocks.GenericBlobRepository) + // Create a mock URL provider. + mockURLProvider := new(mocks.Provider) + // Set up common URL provider expectations + mockURLProvider.On("PackageURL", mock.Anything, mock.Anything, mock.Anything, + mock.Anything).Return("http://example.com/registry/test-registry/docker") + mockURLProvider.On("GenerateUIRegistryURL", mock.Anything, mock.Anything, + mock.Anything).Return("http://example.com/registry/test-registry") + mockURLProvider.On("RegistryURL", mock.Anything, mock.Anything, + mock.Anything).Return("http://example.com/registry/test-registry") + + // Setup base info mock. + baseInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: testRegistryName, + ParentRef: "root", + ParentID: 2, + RootIdentifierID: 3, + RootIdentifier: "root", + RegistryType: api.RegistryTypeVIRTUAL, + PackageType: api.PackageTypeDOCKER, + } + // Create the registry entity that will be used in mocks. + registry := &types.Registry{ + ID: baseInfo.RegistryID, + Name: testRegistryName, + ParentID: baseInfo.ParentID, + RootParentID: baseInfo.RootIdentifierID, + Type: api.RegistryTypeVIRTUAL, + PackageType: api.PackageTypeDOCKER, + } + + // 1. Mock the initial registry metadata lookup. + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "root", "").Return(baseInfo, nil).Once() + + // 2. Mock the space lookup. + mockSpaceFinder.On("FindByRef", mock.Anything, "root").Return(space, nil).Once() + + // 3. Mock the authorization check. + mockAuthorizer.On("Check", mock.Anything, mock.Anything, + mock.MatchedBy(func(scope *coretypes.Scope) bool { return scope.SpacePath == "root" }), + mock.MatchedBy(func(r *coretypes.Resource) bool { return r.Type == gitnessenum.ResourceTypeRegistry }), + gitnessenum.PermissionRegistryEdit).Return(true, nil).Once() + + // 4. Mock registry creation + mockRegistryRepo.On("Create", mock.Anything, + mock.MatchedBy(func(r *types.Registry) bool { + return r.Name == testRegistryName && + r.ParentID == baseInfo.ParentID && + r.Type == api.RegistryTypeVIRTUAL && + r.PackageType == api.PackageTypeDOCKER + })).Return(baseInfo.RegistryID, nil).Once() + + // 5. Mock registry retrieval. + mockRegistryRepo.On("Get", mock.Anything, baseInfo.RegistryID).Return(registry, nil).Once() + + // 6. Mock cleanup policy retrieval. + mockCleanupPolicyRepo.On("GetByRegistryID", mock.Anything, + baseInfo.RegistryID).Return(&[]types.CleanupPolicy{}, nil).Once() + + // URL provider mock expectations set up above + + // Mock setup already done above. + + // Setup already covered above. + + // Create file manager. + var app = &filemanager.App{ + Context: context.Background(), + } + fileManager := filemanager.NewFileManager( + app, + mockRegistryRepo, + mockGenericBlobRepo, + nil, // nodesRepo - not needed for this test. + mockTransactor, + nil, // reporter - not needed for this test. + ) + + // Setup audit service mock. + mockAuditService.On("Log", mock.Anything, + mock.MatchedBy(func(p coretypes.Principal) bool { return p.ID == 1 && p.Type == "user" }), + mock.MatchedBy(func(r audit.Resource) bool { + return r.Type == audit.ResourceTypeRegistry && r.Identifier == testRegistryName + }), + audit.ActionCreated, + "root", + mock.Anything, + ).Return(nil).Once() + + // Setup registry repo mock. + mockRegistryRepo.On("FetchUpstreamProxyKeys", mock.Anything, mock.Anything).Return([]string{}, nil).Once() + mockCleanupPolicyRepo.On("GetByRegistryID", mock.Anything, + baseInfo.RegistryID).Return(&[]types.CleanupPolicy{}, nil).Once() + + // Authorizer mock already setup above. + + // Create controller. + // Setup transactor mock. + mockTransactor.On("WithTx", mock.Anything, + mock.AnythingOfType("func(context.Context) error"), mock.Anything).Run(func(args mock.Arguments) { + // Execute the transaction function. + txFn, ok := args.Get(1).(func(context.Context) error) + assert.True(t, ok, "Transaction function conversion failed") + err := txFn(context.Background()) + // Check if an error occurs during transaction execution. + assert.NoError(t, err, "Transaction function should not return an error") + }).Return(nil) + + // Create controller. + return metadata.NewAPIController( + mockRegistryRepo, + fileManager, + nil, // blobStore. + nil, // genericBlobStore. + nil, // upstreamProxyStore. + nil, // tagStore. + nil, // manifestStore. + mockCleanupPolicyRepo, + nil, // imageStore. + nil, // driver. + mockSpaceFinder, + mockTransactor, + mockURLProvider, + mockAuthorizer, + mockAuditService, + nil, // artifactStore. + nil, // webhooksRepository. + nil, // webhooksExecutionRepository. + mockRegistryMetadataHelper, + nil, // webhookService. + eventReporter, + nil, // downloadStatRepository. + ) + }, + }, + { + name: "create_registry_invalid_parent", + request: api.CreateRegistryRequestObject{ + Body: &api.CreateRegistryJSONRequestBody{ + Identifier: testRegistryName, + ParentRef: utils.StringPtr("invalid"), + Config: func() *api.RegistryConfig { + config := &api.RegistryConfig{Type: api.RegistryTypeVIRTUAL} + _ = config.FromVirtualConfig(api.VirtualConfig{UpstreamProxies: &[]string{}}) + return config + }(), + PackageType: api.PackageTypeDOCKER, + CleanupPolicy: &[]api.CleanupPolicy{}, + }, + }, + expectedResp: api.CreateRegistry400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "space not found", + }, + }, + setupMocks: func() *metadata.APIController { + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockRegistryRepo := new(mocks.RegistryRepository) + mockTransactor := new(mocks.Transactor) + mockGenericBlobRepo := new(mocks.GenericBlobRepository) + + // Setup error case mock. + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "invalid", ""). + Return(nil, fmt.Errorf("space not found")).Once() + + app := &filemanager.App{ + Context: context.Background(), + } + + fileManager := filemanager.NewFileManager( + app, + mockRegistryRepo, + mockGenericBlobRepo, + nil, // nodesRepo - not needed for this test. + mockTransactor, + nil, // reporter - not needed for this test. + ) + + return metadata.NewAPIController( + mockRegistryRepo, + fileManager, + nil, // blobStore. + nil, // genericBlobStore. + nil, // upstreamProxyStore. + nil, // tagStore. + nil, // manifestStore. + nil, // cleanupPolicyStore + nil, // imageStore. + nil, // driver. + nil, // spaceFinder + mockTransactor, + nil, // urlProvider. + nil, // authorizer. + nil, // auditService. + nil, // artifactStore. + nil, // webhooksRepository. + nil, // webhooksExecutionRepository. + mockRegistryMetadataHelper, + nil, // webhookService. + eventReporter, + nil, // downloadStatRepository. + ) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create the controller. + controller := tt.setupMocks() + + // Create context with auth session. + ctx := context.Background() + session := &auth.Session{ + Principal: coretypes.Principal{ + ID: 1, + Type: "user", + }, + } + ctx = request.WithAuthSession(ctx, session) + + // Call the API. + registryResp, err := controller.CreateRegistry(ctx, tt.request) + + // Verify response matches expected type and content. + switch expected := tt.expectedResp.(type) { + case api.CreateRegistry201JSONResponse: + assert.NoError(t, err, "Expected no error but got one") + actualResp, ok := registryResp.(api.CreateRegistry201JSONResponse) + assert.True(t, ok, "Expected 201 response") + assert.Equal(t, expected.Status, actualResp.Status, "Response status should match") + + // Verify registry data fields individually. + assert.Equal(t, expected.Data.Identifier, actualResp.Data.Identifier, "Registry identifier should match") + assert.Equal(t, expected.Data.PackageType, actualResp.Data.PackageType, "Package type should match") + assert.Equal(t, expected.Data.Url, actualResp.Data.Url, "Registry URL should match") + assert.Equal(t, expected.Data.Description, actualResp.Data.Description, "Description should match") + assert.Equal(t, expected.Data.CreatedAt, actualResp.Data.CreatedAt, "CreatedAt should match") + assert.Equal(t, expected.Data.ModifiedAt, actualResp.Data.ModifiedAt, "ModifiedAt should match") + + // Verify config type. + assert.NotNil(t, actualResp.Data.Config, "Config should not be nil") + assert.Equal(t, expected.Data.Config.Type, actualResp.Data.Config.Type, "Config type should match") + + // Verify mock expectations for success case. + called := controller.RegistryRepository.(*mocks.RegistryRepository).AssertCalled(t, "Create", //nolint:errcheck + mock.Anything, mock.MatchedBy(func(r *types.Registry) bool { + return r.Name == tt.request.Body.Identifier && + r.Type == tt.request.Body.Config.Type && + r.PackageType == tt.request.Body.PackageType + })) + assert.True(t, called, "Expected Create call not made") + + // Verify all mocks expectations were met. + mockRegistry, regOk := controller.RegistryRepository.(*mocks.RegistryRepository) + assert.True(t, regOk, "Type assertion to RegistryRepository failed") + regAssertOk := mockRegistry.AssertExpectations(t) + assert.True(t, regAssertOk, "Mock expectations failed for RegistryRepository") + + mockAudit, auditOk := controller.AuditService.(*mocks.AuditService) + assert.True(t, auditOk, "Type assertion to AuditService failed") + auditAssertOk := mockAudit.AssertExpectations(t) + assert.True(t, auditAssertOk, "Mock expectations failed for AuditService") + + // Verify audit expectations. + logCalled := controller.AuditService.(*mocks.AuditService).AssertCalled(t, "Log", mock.Anything, //nolint:errcheck + mock.Anything, mock.Anything, audit.ActionCreated, mock.Anything, mock.Anything) + assert.True(t, logCalled, "Expected Log call not made") + + case api.CreateRegistry400JSONResponse: + assert.Error(t, err, "Expected an error") + actualResp, ok := registryResp.(api.CreateRegistry400JSONResponse) + assert.True(t, ok, "Expected 400 response") + assert.Equal(t, expected.Code, actualResp.Code, "Error code should match") + assert.Equal(t, expected.Message, actualResp.Message, "Error message should match") + + // Additional assertions for specific error cases. + switch tt.name { + case "create_registry_invalid_parent": + assert.Contains(t, actualResp.Message, "space not found", + "Error message should indicate invalid parent") + notCalled := controller.RegistryRepository.(*mocks.RegistryRepository).AssertNotCalled(t, //nolint:errcheck + "Create", mock.Anything, mock.Anything) + assert.True(t, notCalled, "Unexpected Create call made") + + // Verify expectations for the error case. + metaHelper, metaHelperOk := controller.RegistryMetadataHelper.(*mocks.RegistryMetadataHelper) + assert.True(t, metaHelperOk, "Type assertion to RegistryMetadataHelper failed") + assertMetaOk := metaHelper.AssertExpectations(t) + assert.True(t, assertMetaOk, "Mock expectations failed for RegistryMetadataHelper") + case "create_registry_duplicate": + assert.Contains(t, actualResp.Message, "already defined", + "Error message should indicate duplicate registry") + assert.Contains(t, actualResp.Message, tt.request.Body.Identifier, + "Error message should include the registry identifier") + getByNameCalled := controller.RegistryRepository.(*mocks.RegistryRepository).AssertCalled(t, //nolint:errcheck + "GetByRootParentIDAndName", mock.Anything, mock.Anything, tt.request.Body.Identifier) + assert.True(t, getByNameCalled, "Expected GetByRootParentIDAndName call not made") + } + + case api.CreateRegistry403JSONResponse: + assert.Error(t, err, "Expected an error") + actualResp, ok := registryResp.(api.CreateRegistry403JSONResponse) + assert.True(t, ok, "Expected 403 response") + assert.Equal(t, expected.Code, actualResp.Code, "Error code should match") + assert.Equal(t, expected.Message, actualResp.Message, "Error message should match") + assert.Contains(t, actualResp.Message, "unauthorized", + "Error message should indicate authorization failure") + _ = controller.RegistryRepository.(*mocks.RegistryRepository).AssertNotCalled(t, //nolint:errcheck + "Create", mock.Anything, mock.Anything) + + default: + t.Fatalf("Unexpected response type: %T", tt.expectedResp) + } + + // Verify common mock expectations. + if controller.RegistryRepository != nil { + registryRepo, regOk := controller.RegistryRepository.(*mocks.RegistryRepository) + assert.True(t, regOk, "Type assertion to RegistryRepository failed") + assertRegOk := registryRepo.AssertExpectations(t) + assert.True(t, assertRegOk, "Mock expectations failed for RegistryRepository") + } + if controller.RegistryMetadataHelper != nil { + metaHelper, metaHelperOk := controller.RegistryMetadataHelper.(*mocks.RegistryMetadataHelper) + assert.True(t, metaHelperOk, "Type assertion to RegistryMetadataHelper failed") + assertMetaOk := metaHelper.AssertExpectations(t) + assert.True(t, assertMetaOk, "Mock expectations failed for RegistryMetadataHelper") + } + if controller.SpaceFinder != nil { + spaceFinder, finderOk := controller.SpaceFinder.(*mocks.SpaceFinder) + assert.True(t, finderOk, "Type assertion to SpaceFinder failed") + spaceFinderOk := spaceFinder.AssertExpectations(t) + assert.True(t, spaceFinderOk, "Mock expectations failed for SpaceFinder") + } + if controller.Authorizer != nil { + auth, authOk := controller.Authorizer.(*mocks.Authorizer) + assert.True(t, authOk, "Type assertion to Authorizer failed") + authAssertOk := auth.AssertExpectations(t) + assert.True(t, authAssertOk, "Mock expectations failed for Authorizer") + } + if controller.AuditService != nil { + auditSvc, auditSvcOk := controller.AuditService.(*mocks.AuditService) + assert.True(t, auditSvcOk, "Type assertion to AuditService failed") + auditSvcAssertOk := auditSvc.AssertExpectations(t) + assert.True(t, auditSvcAssertOk, "Mock expectations failed for AuditService") + } + }) + } +} diff --git a/registry/app/api/controller/metadata/create_webhook.go b/registry/app/api/controller/metadata/create_webhook.go index ef94e0739..140f6116f 100644 --- a/registry/app/api/controller/metadata/create_webhook.go +++ b/registry/app/api/controller/metadata/create_webhook.go @@ -72,13 +72,14 @@ func (c *APIController) CreateWebhook( } webhook, err := c.RegistryMetadataHelper.MapToWebhookCore(ctx, webhookRequest, regInfo) - webhook.Type = enum.WebhookTypeExternal - webhook.CreatedBy = session.Principal.ID if err != nil { log.Ctx(ctx).Error().Msgf("failed to store webhook: %s with error: %v", webhookRequest.Identifier, err) return createWebhookBadRequestErrorResponse(fmt.Errorf("failed to store webhook %w", err)) } + webhook.Type = enum.WebhookTypeExternal + webhook.CreatedBy = session.Principal.ID + err = c.WebhooksRepository.Create(ctx, webhook) if err != nil { log.Ctx(ctx).Error().Msgf("failed to store webhook: %s with error: %v", webhookRequest.Identifier, err) diff --git a/registry/app/api/controller/metadata/create_webhook_test.go b/registry/app/api/controller/metadata/create_webhook_test.go new file mode 100644 index 000000000..6c4116e32 --- /dev/null +++ b/registry/app/api/controller/metadata/create_webhook_test.go @@ -0,0 +1,556 @@ +// Copyright 2023 Harness, Inc. +// +// 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. + +//nolint:lll,revive // revive:disable:unused-parameter +package metadata_test + +import ( + "context" + "fmt" + "testing" + + apiauth "github.com/harness/gitness/app/api/auth" + "github.com/harness/gitness/app/api/request" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/registry/app/api/controller/metadata" + "github.com/harness/gitness/registry/app/api/controller/mocks" + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + registrytypes "github.com/harness/gitness/registry/types" + "github.com/harness/gitness/registry/utils" + coretypes "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const ( + testWebhookIdentifier = "test-webhook" + testWebhookURL = "http://example.com" +) + +func TestCreateWebhook(t *testing.T) { + tests := []struct { + name string + setupMocks func(*metadata.APIController) + request api.CreateWebhookRequestObject + expectedResp interface{} + expectedError error + }{ + { + name: "success_case", + setupMocks: func(c *metadata.APIController) { + // Mock registry metadata helper + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockSpaceFinder := new(mocks.SpaceFinder) + mockWebhooksRepository := new(mocks.WebhooksRepository) + mockAuthorizer := new(mocks.Authorizer) + + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeVIRTUAL, + } + + space := &coretypes.SpaceCore{ + Path: "root/parent", + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{ + Type: enum.ResourceTypeRegistry, + Identifier: "reg", + }, + Permission: enum.PermissionRegistryEdit, + }, + } + + webhook := &coretypes.WebhookCore{ + ID: 1, + DisplayName: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + URL: "http://example.com", + Enabled: true, + Insecure: false, + ParentID: regInfo.RegistryID, + Type: enum.WebhookTypeExternal, + } + + webhookResponseEntity := &api.Webhook{ + Identifier: "test-webhook", + Name: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + CreatedAt: utils.StringPtr("2023-01-01T00:00:00Z"), + ModifiedAt: utils.StringPtr("2023-01-01T00:00:00Z"), + } + + // Set up expectations. + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + mock.Anything, + "reg", + enum.PermissionRegistryEdit, + ).Return(permissionChecks) + // Set up authorizer to expect a session with Principal ID 123 for success case + mockSession := &auth.Session{Principal: coretypes.Principal{ID: 123}} + mockAuthorizer.On("CheckAll", mock.Anything, mockSession, permissionChecks[0]).Return(true, nil) + + mockRegistryMetadataHelper.On( + "MapToWebhookCore", + mock.Anything, + mock.MatchedBy(func(req api.WebhookRequest) bool { + return req.Identifier == testWebhookIdentifier && + req.Name == testWebhookIdentifier && + req.Url == testWebhookURL && + req.Enabled == true && + req.Insecure == false + }), + regInfo, + ).Return(webhook, nil) + + mockWebhooksRepository.On("Create", mock.Anything, webhook).Return(nil) + mockWebhooksRepository.On( + "GetByRegistryAndIdentifier", + mock.Anything, + regInfo.RegistryID, + "test-webhook", + ).Return(webhook, nil) + mockRegistryMetadataHelper.On( + "MapToWebhookResponseEntity", + mock.Anything, + webhook, + ).Return(webhookResponseEntity, nil) + + // Assign mocks to controller + c.SpaceFinder = mockSpaceFinder + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.Authorizer = mockAuthorizer + c.WebhooksRepository = mockWebhooksRepository + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook201JSONResponse{ + WebhookResponseJSONResponse: api.WebhookResponseJSONResponse{ + Data: api.Webhook{ + Name: "test-webhook", + Identifier: "test-webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + Status: api.StatusSUCCESS, + }, + }, + }, + { + name: "reserved_identifier", + setupMocks: func(c *metadata.APIController) { + // 1. Mock registry metadata helper for GetRegistryRequestBaseInfo + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeVIRTUAL, + } + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg"). + Return(regInfo, nil) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + + // 2. Mock SpaceFinder + mockSpaceFinder := new(mocks.SpaceFinder) + space := &coretypes.SpaceCore{ + Path: "root/parent", + } + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + c.SpaceFinder = mockSpaceFinder + + // 3. Mock GetPermissionChecks + permissionCheck := coretypes.PermissionCheck{ + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{ + Type: enum.ResourceTypeRegistry, + Identifier: "reg", + }, + Permission: enum.PermissionRegistryEdit, + } + mockRegistryMetadataHelper.On("GetPermissionChecks", mock.Anything, "reg", enum.PermissionRegistryEdit). + Return([]coretypes.PermissionCheck{permissionCheck}) + + // 4. Mock Authorizer + mockAuthorizer := new(mocks.Authorizer) + mockAuthorizer.On("CheckAll", mock.Anything, (*auth.Session)(nil), permissionCheck).Return(true, nil) + c.Authorizer = mockAuthorizer + + // 5. Mock MapToWebhookCore + mockRegistryMetadataHelper.On("MapToWebhookCore", mock.Anything, + mock.MatchedBy(func(req api.WebhookRequest) bool { + return req.Identifier == "internal-webhook" && + req.Name == "internal-webhook" && + req.Url == testWebhookURL && + req.Enabled == true && + req.Insecure == false + }), regInfo).Return(nil, fmt.Errorf("webhook identifier internal-webhook is reserved")) + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: "internal-webhook", + Identifier: "internal-webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "failed to store webhook webhook identifier internal-webhook is reserved", + }, + }, + }, + { + name: "invalid_registry_reference", + setupMocks: func(c *metadata.APIController) { + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "invalid-reg"). + Return(nil, fmt.Errorf("invalid registry reference")) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "invalid-reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: "test-webhook", + Identifier: "test-webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "invalid registry reference", + }, + }, + }, + { + name: "permission_check_fails", + setupMocks: func(c *metadata.APIController) { + // 1. Mock registry metadata helper for GetRegistryRequestBaseInfo + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeVIRTUAL, + } + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg"). + Return(regInfo, nil) + + // 2. Mock SpaceFinder + mockSpaceFinder := new(mocks.SpaceFinder) + space := &coretypes.SpaceCore{ + Path: "root/parent", + } + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + c.SpaceFinder = mockSpaceFinder + + // 3. Mock GetPermissionChecks + permissionCheck := coretypes.PermissionCheck{ + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{ + Type: enum.ResourceTypeRegistry, + Identifier: "reg", + }, + Permission: enum.PermissionRegistryEdit, + } + mockRegistryMetadataHelper.On("GetPermissionChecks", mock.Anything, "reg", enum.PermissionRegistryEdit). + Return([]coretypes.PermissionCheck{permissionCheck}) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + + // Mock authorizer with manual response + mockAuthorizer := new(mocks.Authorizer) + mockAuthorizer.On("CheckAll", mock.Anything, (*auth.Session)(nil), permissionCheck).Return(false, apiauth.ErrUnauthorized) + c.Authorizer = mockAuthorizer + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook403JSONResponse{ + UnauthorizedJSONResponse: api.UnauthorizedJSONResponse{ + Code: "403", + Message: "unauthorized", + }, + }, + }, + { + name: "non_virtual_registry", + setupMocks: func(c *metadata.APIController) { + // 1. Mock registry metadata helper for GetRegistryRequestBaseInfo + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeUPSTREAM, + } + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg"). + Return(regInfo, nil) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "not allowed to create webhook for UPSTREAM registry", + }, + }, + }, + { + name: "permission_check_fails", + setupMocks: func(c *metadata.APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockAuthorizer := new(mocks.Authorizer) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeVIRTUAL, + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryEdit, + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent"). + Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg"). + Return(regInfo, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, "reg", enum.PermissionRegistryEdit). + Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, (*auth.Session)(nil), permissionChecks[0]). + Return(false, fmt.Errorf("unauthorized")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.Authorizer = mockAuthorizer + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook403JSONResponse{ + UnauthorizedJSONResponse: api.UnauthorizedJSONResponse{ + Code: "403", + Message: "unauthorized", + }, + }, + }, + { + name: "duplicate_webhook_identifier", + setupMocks: func(c *metadata.APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockAuthorizer := new(mocks.Authorizer) + mockWebhooksRepository := new(mocks.WebhooksRepository) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := ®istrytypes.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + RegistryType: api.RegistryTypeVIRTUAL, + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryEdit, + }, + } + + webhook := &coretypes.WebhookCore{ + ID: 1, + Type: enum.WebhookTypeExternal, + CreatedBy: 0, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent"). + Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg"). + Return(regInfo, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, "reg", enum.PermissionRegistryEdit). + Return(permissionChecks) + // Set up authorizer to expect a session with Principal ID 123 for this test case + mockSession := &auth.Session{Principal: coretypes.Principal{ID: 123}} + mockAuthorizer.On("CheckAll", mock.Anything, mockSession, permissionChecks[0]). + Return(true, nil) + mockRegistryMetadataHelper.On("MapToWebhookCore", mock.Anything, + mock.MatchedBy(func(req api.WebhookRequest) bool { + return req.Identifier == testWebhookIdentifier && + req.Name == testWebhookIdentifier && + req.Url == testWebhookURL && + req.Enabled == true && + req.Insecure == false + }), regInfo). + Return(webhook, nil) + mockWebhooksRepository.On("Create", mock.Anything, webhook). + Return(fmt.Errorf("resource is a duplicate")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.Authorizer = mockAuthorizer + c.WebhooksRepository = mockWebhooksRepository + }, + request: api.CreateWebhookRequestObject{ + RegistryRef: "reg", + Body: &api.CreateWebhookJSONRequestBody{ + Name: testWebhookIdentifier, + Identifier: testWebhookIdentifier, + Url: "http://example.com", + Enabled: true, + Insecure: false, + }, + }, + expectedResp: api.CreateWebhook400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "failed to store webhook, Webhook with identifier test-webhook already exists", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create controller and setup mocks. + controller := &metadata.APIController{} + tt.setupMocks(controller) + + // Create a context with auth session for success case + localCtx := context.Background() + + // Add auth session for tests that need it to set CreatedBy field + if tt.name == "success_case" || tt.name == "duplicate_webhook_identifier" { + mockPrincipal := coretypes.Principal{ID: 123} + mockSession := &auth.Session{Principal: mockPrincipal} + localCtx = request.WithAuthSession(localCtx, mockSession) + } + + // Execute. + resp, err := controller.CreateWebhook(localCtx, tt.request) + + // Verify response matches expected type and content. + switch expected := tt.expectedResp.(type) { + case api.CreateWebhook201JSONResponse: + assert.NoError(t, err, "Expected no error but got one") + actualResp, ok := resp.(api.CreateWebhook201JSONResponse) + assert.True(t, ok, "Expected 201 response") + + // Verify webhook data fields individually. + assert.Equal(t, expected.Data.Identifier, actualResp.Data.Identifier, "Webhook identifier should match") + assert.Equal(t, expected.Data.Name, actualResp.Data.Name, "Webhook name should match") + assert.Equal(t, expected.Data.Url, actualResp.Data.Url, "Webhook URL should match") + assert.Equal(t, expected.Data.Enabled, actualResp.Data.Enabled, "Enabled status should match") + assert.Equal(t, expected.Data.Insecure, actualResp.Data.Insecure, "Insecure status should match") + assert.NotEmpty(t, actualResp.Data.CreatedAt, "CreatedAt should not be empty") + assert.NotEmpty(t, actualResp.Data.ModifiedAt, "ModifiedAt should not be empty") + assert.Equal(t, api.StatusSUCCESS, actualResp.Status, "Status should be SUCCESS") + + case api.CreateWebhook400JSONResponse: + // For error responses, we don't need to check the err value since responses with error codes are still valid responses + actualResp, ok := resp.(api.CreateWebhook400JSONResponse) + assert.True(t, ok, "Expected 400 response") + assert.Equal(t, expected.Code, actualResp.Code, "Error code should match") + assert.Equal(t, expected.Message, actualResp.Message, "Error message should match") + + case api.CreateWebhook403JSONResponse: + // For error responses, we don't need to check the err value since responses with error codes are still valid responses + actualResp, ok := resp.(api.CreateWebhook403JSONResponse) + assert.True(t, ok, "Expected 403 response") + assert.Equal(t, expected.Code, actualResp.Code, "Error code should match") + assert.Equal(t, expected.Message, actualResp.Message, "Error message should match") + + default: + t.Fatalf("Unexpected response type: %T", tt.expectedResp) + } + + // Verify mock expectations + if mockSpaceFinder, ok := controller.SpaceFinder.(*mocks.SpaceFinder); ok { + mockSpaceFinder.AssertExpectations(t) + } + if mockMetadataHelper, ok := controller.RegistryMetadataHelper.(*mocks.RegistryMetadataHelper); ok { + mockMetadataHelper.AssertExpectations(t) + } + if mockWebhooksRepo, ok := controller.WebhooksRepository.(*mocks.WebhooksRepository); ok { + mockWebhooksRepo.AssertExpectations(t) + } + if mockAuditService, ok := controller.AuditService.(*mocks.AuditService); ok { + mockAuditService.AssertExpectations(t) + } + }) + } +} diff --git a/registry/app/api/controller/metadata/delete_artifact.go b/registry/app/api/controller/metadata/delete_artifact.go index 99627f6d5..b6b3a94ad 100644 --- a/registry/app/api/controller/metadata/delete_artifact.go +++ b/registry/app/api/controller/metadata/delete_artifact.go @@ -24,6 +24,7 @@ import ( "github.com/harness/gitness/audit" "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/app/api/utils" + registryTypes "github.com/harness/gitness/registry/types" "github.com/harness/gitness/types/enum" "github.com/rs/zerolog/log" @@ -64,7 +65,7 @@ func (c *APIController) DeleteArtifact(ctx context.Context, r artifact.DeleteArt }, err } - repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { //nolint:nilerr return artifact.DeleteArtifact404JSONResponse{ @@ -130,7 +131,7 @@ func (c *APIController) DeleteArtifact(ctx context.Context, r artifact.DeleteArt func (c *APIController) deleteOCIImage( ctx context.Context, - regInfo *RegistryRequestBaseInfo, + regInfo *registryTypes.RegistryRequestBaseInfo, artifactName string, ) error { err := c.tx.WithTx( @@ -156,7 +157,7 @@ func (c *APIController) deleteOCIImage( func (c *APIController) deleteGenericImage( ctx context.Context, - regInfo *RegistryRequestBaseInfo, + regInfo *registryTypes.RegistryRequestBaseInfo, artifactName string, ) error { err := c.tx.WithTx( diff --git a/registry/app/api/controller/metadata/delete_artifact_test.go b/registry/app/api/controller/metadata/delete_artifact_test.go new file mode 100644 index 000000000..f07fc7dfb --- /dev/null +++ b/registry/app/api/controller/metadata/delete_artifact_test.go @@ -0,0 +1,458 @@ +// Copyright 2023 Harness, Inc. +// +// 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 metadata + +import ( + "context" + "fmt" + "testing" + + "github.com/harness/gitness/app/api/request" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/audit" + "github.com/harness/gitness/registry/app/api/controller/mocks" + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + "github.com/harness/gitness/registry/types" + coretypes "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestDeleteArtifact(t *testing.T) { + // Create a mock session for testing + principal := coretypes.Principal{ + ID: 1, + Type: enum.PrincipalTypeUser, + Email: "test@example.com", + } + mockSession := &auth.Session{ + Principal: principal, + } + + // Create a context with the mock session + testCtx := request.WithAuthSession(context.Background(), mockSession) + + tests := []struct { + name string + setupMocks func(*APIController) + request api.DeleteArtifactRequestObject + expectedResp api.DeleteArtifactResponseObject + expectedError error + }{ + { + name: "success_case", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockImageStore := new(mocks.ImageRepository) + mockTx := new(mocks.Transaction) + mockAuditService := new(mocks.AuditService) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + PackageType: api.PackageTypePYTHON, + } + + registry := &types.Registry{ + ID: 1, + Name: "reg", + ParentID: 2, + Type: "native", + PackageType: "pypi", + } + + artifact := &types.Image{ + ID: 1, + Name: "test-artifact", + Enabled: true, + RegistryID: regInfo.RegistryID, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "reg").Return(regInfo, nil) + mockAuthorizer.On( + "Check", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + mock.AnythingOfType("*types.Scope"), + mock.AnythingOfType("*types.Resource"), + enum.PermissionArtifactsDelete, + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + int64(2), + "reg", + ).Return(registry, nil) + mockImageStore.On( + "GetByName", + mock.Anything, + int64(1), + "test-artifact", + ).Return(artifact, nil) + mockTx.On("WithTx", mock.Anything, mock.AnythingOfType("func(context.Context) error")).Return(nil) + mockAuditService.On( + "Log", + mock.Anything, + mock.AnythingOfType("types.Principal"), + mock.AnythingOfType("audit.Resource"), + audit.ActionDeleted, + "root/parent", + mock.Anything, + mock.Anything, + ).Return(nil) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.ImageStore = mockImageStore + c.tx = mockTx + c.AuditService = mockAuditService + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "reg", + Artifact: "test-artifact", + }, + expectedResp: api.DeleteArtifact200JSONResponse{ + SuccessJSONResponse: api.SuccessJSONResponse{ + Status: api.StatusSUCCESS, + }, + }, + }, + { + name: "invalid_registry_reference", + setupMocks: func(c *APIController) { + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "invalid-reg").Return(nil, fmt.Errorf("invalid registry reference")) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "invalid-reg", + Artifact: "test-artifact", + }, + expectedResp: api.DeleteArtifact400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "invalid registry reference", + }, + }, + expectedError: fmt.Errorf("invalid registry reference"), + }, + { + name: "permission_check_fails", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockAuthorizer := new(mocks.Authorizer) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + PackageType: api.PackageTypePYTHON, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "reg").Return(regInfo, nil) + mockAuthorizer.On("Check", mock.Anything, mock.AnythingOfType("*auth.Session"), + mock.AnythingOfType("*types.Scope"), + mock.AnythingOfType("*types.Resource"), + enum.PermissionArtifactsDelete).Return(false, fmt.Errorf("not authorized")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.Authorizer = mockAuthorizer + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "reg", + Artifact: "test-artifact", + }, + expectedResp: api.DeleteArtifact403JSONResponse{ + UnauthorizedJSONResponse: api.UnauthorizedJSONResponse{ + Code: "403", + Message: "not authorized", + }, + }, + expectedError: fmt.Errorf("not authorized"), + }, + { + name: "registry_not_found", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + PackageType: api.PackageTypePYTHON, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "reg").Return(regInfo, nil) + mockAuthorizer.On( + "Check", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + mock.AnythingOfType("*types.Scope"), + mock.AnythingOfType("*types.Resource"), + enum.PermissionArtifactsDelete, + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + int64(2), + "reg", + ).Return(nil, fmt.Errorf("registry doesn't exist with this key")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "reg", + Artifact: "test-artifact", + }, + expectedResp: api.DeleteArtifact404JSONResponse{ + NotFoundJSONResponse: api.NotFoundJSONResponse{ + Code: "404", + Message: "registry doesn't exist with this key", + }, + }, + }, + { + name: "artifact_not_found", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockImageStore := new(mocks.ImageRepository) + mockAuditService := new(mocks.AuditService) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + PackageType: api.PackageTypePYTHON, + } + + registry := &types.Registry{ + ID: 1, + Name: "reg", + ParentID: 2, + Type: "native", + PackageType: "pypi", + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "reg").Return(regInfo, nil) + mockAuthorizer.On( + "Check", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + mock.AnythingOfType("*types.Scope"), + mock.AnythingOfType("*types.Resource"), + enum.PermissionArtifactsDelete, + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + int64(2), + "reg", + ).Return(registry, nil) + mockImageStore.On( + "GetByName", + mock.Anything, + int64(1), + "non-existent-artifact", + ).Return(nil, fmt.Errorf("artifact doesn't exist with this key")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.ImageStore = mockImageStore + c.AuditService = mockAuditService + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "reg", + Artifact: "non-existent-artifact", + }, + expectedResp: api.DeleteArtifact404JSONResponse{ + NotFoundJSONResponse: api.NotFoundJSONResponse{ + Code: "404", + Message: "artifact doesn't exist with this key", + }, + }, + }, + { + name: "artifact_already_deleted", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockImageStore := new(mocks.ImageRepository) + mockAuditService := new(mocks.AuditService) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + PackageType: api.PackageTypePYTHON, + } + + registry := &types.Registry{ + ID: 1, + Name: "reg", + ParentID: 2, + Type: "native", + PackageType: "pypi", + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", + mock.Anything, "", "reg").Return(regInfo, nil) + mockAuthorizer.On( + "Check", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + mock.AnythingOfType("*types.Scope"), + mock.AnythingOfType("*types.Resource"), + enum.PermissionArtifactsDelete, + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + int64(2), + "reg", + ).Return(registry, nil) + mockImageStore.On( + "GetByName", + mock.Anything, + int64(1), + "deleted-artifact", + ).Return(nil, fmt.Errorf("artifact is already deleted")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.ImageStore = mockImageStore + c.AuditService = mockAuditService + }, + request: api.DeleteArtifactRequestObject{ + RegistryRef: "reg", + Artifact: "deleted-artifact", + }, + expectedResp: api.DeleteArtifact404JSONResponse{ + NotFoundJSONResponse: api.NotFoundJSONResponse{ + Code: "404", + Message: "artifact doesn't exist with this key", + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &APIController{} + tt.setupMocks(c) + + // Use the test context with the mock session + resp, err := c.DeleteArtifact(testCtx, tt.request) + + if tt.expectedError != nil { + assert.Error(t, err, "Expected an error") + assert.Equal(t, tt.expectedError.Error(), err.Error(), "Error message should match") + } else { + assert.NoError(t, err, "Expected no error") + } + + // Check response type + switch expected := tt.expectedResp.(type) { + case api.DeleteArtifact200JSONResponse: + actual, ok := resp.(api.DeleteArtifact200JSONResponse) + assert.True(t, ok, "Expected 200 success response") + assert.Equal(t, expected.Status, actual.Status, "Response status should match") + case api.DeleteArtifact400JSONResponse: + actual, ok := resp.(api.DeleteArtifact400JSONResponse) + assert.True(t, ok, "Expected 400 bad request response") + assert.Equal(t, expected.Message, actual.Message, "Error message should match") + case api.DeleteArtifact403JSONResponse: + actual, ok := resp.(api.DeleteArtifact403JSONResponse) + assert.True(t, ok, "Expected 403 forbidden response") + assert.Equal(t, expected.Message, actual.Message, "Error message should match") + case api.DeleteArtifact404JSONResponse: + actual, ok := resp.(api.DeleteArtifact404JSONResponse) + assert.True(t, ok, "Expected 404 not found response") + assert.Equal(t, expected.Message, actual.Message, "Error message should match") + } + + // Full response should match expected value + assert.Equal(t, tt.expectedResp, resp, "Full response should match expected value") + + // Verify all expectations were met + // Only verify mocks that were actually set up in this test case + if c.SpaceFinder != nil { + mock.AssertExpectationsForObjects(t, c.SpaceFinder) + } + if c.RegistryRepository != nil { + mock.AssertExpectationsForObjects(t, c.RegistryRepository) + } + if c.Authorizer != nil { + mock.AssertExpectationsForObjects(t, c.Authorizer) + } + if c.RegistryMetadataHelper != nil { + mock.AssertExpectationsForObjects(t, c.RegistryMetadataHelper) + } + if c.ImageStore != nil { + mock.AssertExpectationsForObjects(t, c.ImageStore) + } + if c.tx != nil { + mock.AssertExpectationsForObjects(t, c.tx) + } + if c.AuditService != nil { + mock.AssertExpectationsForObjects(t, c.AuditService) + } + }) + } +} diff --git a/registry/app/api/controller/metadata/delete_artifacts_version.go b/registry/app/api/controller/metadata/delete_artifacts_version.go index 5421ec792..93dfc75f2 100644 --- a/registry/app/api/controller/metadata/delete_artifacts_version.go +++ b/registry/app/api/controller/metadata/delete_artifacts_version.go @@ -25,6 +25,7 @@ import ( "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/app/api/utils" "github.com/harness/gitness/registry/services/webhook" + registryTypes "github.com/harness/gitness/registry/types" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" @@ -67,7 +68,7 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De }, err } - repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { //nolint:nilerr return artifact.DeleteArtifactVersion404JSONResponse{ @@ -81,7 +82,7 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De versionName := string(r.Version) registryName := repoEntity.Name - image, err := c.ImageStore.GetByRepoAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier, artifactName) + image, err := c.ImageStore.GetByRepoAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier, artifactName) if err != nil { //nolint:nilerr return artifact.DeleteArtifactVersion404JSONResponse{ @@ -103,10 +104,10 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De switch regInfo.PackageType { case artifact.PackageTypeDOCKER: - err = c.deleteTag(ctx, regInfo, registryName, session.Principal, artifactName, + err = c.deleteTagWithAudit(ctx, regInfo, registryName, session.Principal, artifactName, versionName) case artifact.PackageTypeHELM: - err = c.deleteTag(ctx, regInfo, registryName, session.Principal, artifactName, + err = c.deleteTagWithAudit(ctx, regInfo, registryName, session.Principal, artifactName, versionName) case artifact.PackageTypeNPM: err = c.deleteVersion(ctx, regInfo, artifactName, versionName) @@ -147,8 +148,8 @@ func (c *APIController) DeleteArtifactVersion(ctx context.Context, r artifact.De }, nil } -func (c *APIController) deleteTag( - ctx context.Context, regInfo *RegistryRequestBaseInfo, +func (c *APIController) deleteTagWithAudit( + ctx context.Context, regInfo *registryTypes.RegistryRequestBaseInfo, registryName string, principal types.Principal, artifactName string, versionName string, ) error { existingDigest := c.getTagDigest(ctx, regInfo.RegistryID, artifactName, versionName) @@ -170,7 +171,7 @@ func (c *APIController) deleteTag( func (c *APIController) deleteVersion( ctx context.Context, - regInfo *RegistryRequestBaseInfo, + regInfo *registryTypes.RegistryRequestBaseInfo, artifactName string, versionName string, ) error { diff --git a/registry/app/api/controller/metadata/delete_registry.go b/registry/app/api/controller/metadata/delete_registry.go index c6cc28b35..ef7aefbb1 100644 --- a/registry/app/api/controller/metadata/delete_registry.go +++ b/registry/app/api/controller/metadata/delete_registry.go @@ -69,7 +69,7 @@ func (c *APIController) DeleteRegistry( }, err } - repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { //nolint:nilerr return artifact.DeleteRegistry404JSONResponse{ @@ -132,10 +132,10 @@ func (c *APIController) DeleteRegistry( func (c *APIController) deleteUpstreamProxyWithAudit( ctx context.Context, - regInfo *RegistryRequestBaseInfo, principal types.Principal, parentRef string, registryName string, + regInfo *registrytypes.RegistryRequestBaseInfo, principal types.Principal, parentRef string, registryName string, ) error { upstreamProxies, err := c.RegistryRepository.FetchUpstreamProxyIDs(ctx, - []string{regInfo.RegistryIdentifier}, regInfo.parentID) + []string{regInfo.RegistryIdentifier}, regInfo.ParentID) if err != nil { log.Ctx(ctx).Error().Msgf("failed to fetch upstream proxy IDs: %s", err) return fmt.Errorf("failed to fectch upstream proxy IDs :%w", err) @@ -143,7 +143,7 @@ func (c *APIController) deleteUpstreamProxyWithAudit( //nolint:nestif if len(upstreamProxies) > 0 { registryIDs, err := c.RegistryRepository.FetchRegistriesIDByUpstreamProxyID( - ctx, strconv.FormatInt(upstreamProxies[0], 10), regInfo.rootIdentifierID) + ctx, strconv.FormatInt(upstreamProxies[0], 10), regInfo.RootIdentifierID) if err != nil { log.Ctx(ctx).Error().Msgf("failed to fetch registryIDs: %s", err) return fmt.Errorf("failed to fetch registryIDs IDs :%w", err) @@ -168,7 +168,7 @@ func (c *APIController) deleteUpstreamProxyWithAudit( } } - err = c.UpstreamProxyStore.Delete(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + err = c.UpstreamProxyStore.Delete(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return err } @@ -191,7 +191,7 @@ func (c *APIController) deleteUpstreamProxyWithAudit( } func (c *APIController) deleteRegistryWithAudit( - ctx context.Context, regInfo *RegistryRequestBaseInfo, + ctx context.Context, regInfo *registrytypes.RegistryRequestBaseInfo, registry *registrytypes.Registry, principal types.Principal, parentRef string, ) error { err := c.ImageStore.DeleteByRegistryID(ctx, regInfo.RegistryID) @@ -204,7 +204,7 @@ func (c *APIController) deleteRegistryWithAudit( return err } - err = c.RegistryRepository.Delete(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + err = c.RegistryRepository.Delete(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return err } diff --git a/registry/app/api/controller/metadata/delete_registry_test.go b/registry/app/api/controller/metadata/delete_registry_test.go new file mode 100644 index 000000000..6921c15ca --- /dev/null +++ b/registry/app/api/controller/metadata/delete_registry_test.go @@ -0,0 +1,475 @@ +// Copyright 2023 Harness, Inc. +// +// 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 metadata + +import ( + "context" + "fmt" + "testing" + + "github.com/harness/gitness/app/api/request" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/registry/app/api/controller/mocks" + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + "github.com/harness/gitness/registry/types" + coretypes "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestDeleteRegistry(t *testing.T) { + // Create a mock session for testing + principal := coretypes.Principal{ + ID: 1, + Type: enum.PrincipalTypeUser, + Email: "test@example.com", + } + mockSession := &auth.Session{ + Principal: principal, + } + + // Create a context with the mock session + testCtx := request.WithAuthSession(context.Background(), mockSession) + + tests := []struct { + name string + setupMocks func(*APIController) + request api.DeleteRegistryRequestObject + expectedResp api.DeleteRegistryResponseObject + expectedError error + }{ + { + name: "success_case_virtual_registry", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockImageStore := new(mocks.ImageRepository) + mockTx := new(mocks.Transaction) + mockAuditService := new(mocks.AuditService) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + registry := &types.Registry{ + ID: 1, + Name: "reg", + ParentID: 2, + Type: "virtual", + PackageType: "pypi", + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryDelete, + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + space, + "reg", + enum.PermissionRegistryDelete, + ).Return(permissionChecks) + mockAuthorizer.On( + "CheckAll", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + permissionChecks[0], + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + regInfo.ParentID, + regInfo.RegistryIdentifier, + ).Return(registry, nil) + mockImageStore.On("DeleteDownloadStatByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockImageStore.On("DeleteBandwidthStatByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockImageStore.On("DeleteByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockRegistryRepository.On("Delete", mock.Anything, regInfo.ParentID, regInfo.RegistryIdentifier).Return(nil) + mockAuditService.On( + "Log", + mock.Anything, + mock.AnythingOfType("*types.PrincipalInfo"), + mock.AnythingOfType("*audit.Resource"), + mock.AnythingOfType("string"), + mock.AnythingOfType("string"), + mock.AnythingOfType("audit.Option"), + ).Return(nil) + // Simply return nil for the transaction - we're testing the controller logic, not transaction details + mockTx.On("WithTx", mock.Anything, mock.AnythingOfType("func(context.Context) error")).Return(nil) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.ImageStore = mockImageStore + c.tx = mockTx + c.AuditService = mockAuditService + }, + request: api.DeleteRegistryRequestObject{ + RegistryRef: "reg", + }, + expectedResp: api.DeleteRegistry200JSONResponse{ + SuccessJSONResponse: api.SuccessJSONResponse{ + Status: api.StatusSUCCESS, + }, + }, + }, + { + name: "invalid_registry_reference", + setupMocks: func(c *APIController) { + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockRegistryMetadataHelper.On( + "GetRegistryRequestBaseInfo", + mock.Anything, + "", + "invalid-reg", + ).Return(nil, fmt.Errorf("invalid registry reference")) + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.DeleteRegistryRequestObject{ + RegistryRef: "invalid-reg", + }, + expectedResp: api.DeleteRegistry400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "invalid registry reference", + }, + }, + expectedError: fmt.Errorf("invalid registry reference"), + }, + { + name: "permission_check_fails", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockAuthorizer := new(mocks.Authorizer) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryDelete, + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + space, + "reg", + enum.PermissionRegistryDelete, + ).Return(permissionChecks) + mockAuthorizer.On( + "CheckAll", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + permissionChecks[0], + ).Return(false, fmt.Errorf("not authorized")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.Authorizer = mockAuthorizer + }, + request: api.DeleteRegistryRequestObject{ + RegistryRef: "reg", + }, + expectedResp: api.DeleteRegistry403JSONResponse{ + UnauthorizedJSONResponse: api.UnauthorizedJSONResponse{ + Code: "403", + Message: "not authorized", + }, + }, + expectedError: fmt.Errorf("not authorized"), + }, + { + name: "registry_not_found", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryDelete, + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + space, + "reg", + enum.PermissionRegistryDelete, + ).Return(permissionChecks) + mockAuthorizer.On( + "CheckAll", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + permissionChecks[0], + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + regInfo.ParentID, + regInfo.RegistryIdentifier, + ).Return(nil, fmt.Errorf("registry doesn't exist with this key")) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + }, + request: api.DeleteRegistryRequestObject{ + RegistryRef: "reg", + }, + expectedResp: api.DeleteRegistry404JSONResponse{ + NotFoundJSONResponse: api.NotFoundJSONResponse{ + Code: "404", + Message: "registry doesn't exist with this key", + }, + }, + }, + { + name: "success_case_native_registry", + setupMocks: func(c *APIController) { + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockImageStore := new(mocks.ImageRepository) + mockTx := new(mocks.Transaction) + mockAuditService := new(mocks.AuditService) + mockUpstreamProxyStore := new(mocks.UpstreamProxyStore) + + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + registry := &types.Registry{ + ID: 1, + Name: "reg", + ParentID: 2, + Type: "native", + PackageType: "pypi", + } + + permissionChecks := []coretypes.PermissionCheck{ + { + Scope: coretypes.Scope{SpacePath: "root/parent"}, + Resource: coretypes.Resource{Type: enum.ResourceTypeRegistry, Identifier: "reg"}, + Permission: enum.PermissionRegistryDelete, + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + space, + "reg", + enum.PermissionRegistryDelete, + ).Return(permissionChecks) + mockAuthorizer.On( + "CheckAll", + mock.Anything, + mock.AnythingOfType("*auth.Session"), + permissionChecks[0], + ).Return(true, nil) + mockRegistryRepository.On( + "GetByParentIDAndName", + mock.Anything, + regInfo.ParentID, + regInfo.RegistryIdentifier, + ).Return(registry, nil) + mockRegistryRepository.On( + "FetchUpstreamProxyIDs", + mock.Anything, + []string{regInfo.RegistryIdentifier}, + regInfo.ParentID, + ).Return([]int64{}, nil) + mockUpstreamProxyStore.On("Delete", mock.Anything, regInfo.ParentID, regInfo.RegistryIdentifier).Return(nil) + mockImageStore.On("DeleteDownloadStatByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockImageStore.On("DeleteBandwidthStatByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockImageStore.On("DeleteByRegistryID", mock.Anything, regInfo.RegistryID).Return(nil) + mockRegistryRepository.On("Delete", mock.Anything, regInfo.ParentID, regInfo.RegistryIdentifier).Return(nil) + mockAuditService.On( + "Log", + mock.Anything, + mock.AnythingOfType("*types.PrincipalInfo"), + mock.AnythingOfType("*audit.Resource"), + mock.AnythingOfType("string"), + mock.AnythingOfType("string"), + mock.AnythingOfType("audit.Option"), + ).Return(nil) + // Simply return nil for the transaction - we're testing the controller logic, not transaction details + mockTx.On("WithTx", mock.Anything, mock.AnythingOfType("func(context.Context) error")).Return(nil) + + c.SpaceFinder = mockSpaceFinder + c.RegistryRepository = mockRegistryRepository + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.ImageStore = mockImageStore + c.tx = mockTx + c.AuditService = mockAuditService + c.UpstreamProxyStore = mockUpstreamProxyStore + }, + request: api.DeleteRegistryRequestObject{ + RegistryRef: "reg", + }, + expectedResp: api.DeleteRegistry200JSONResponse{ + SuccessJSONResponse: api.SuccessJSONResponse{ + Status: api.StatusSUCCESS, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Setup + controller := &APIController{} + tt.setupMocks(controller) + + // Execute with the mock session context + resp, err := controller.DeleteRegistry(testCtx, tt.request) + + // Verify error only if explicitly expected. + if tt.expectedError != nil { + assert.Error(t, err, "Expected an error but got none") + assert.Equal(t, tt.expectedError.Error(), err.Error(), "Error message should match") + } else if _, ok := tt.expectedResp.(api.DeleteRegistry200JSONResponse); ok { + // Only assert no error for success responses. + assert.NoError(t, err, "Expected no error for success response") + } + // For error response types like 400/404/403, we don't assert err since the response object is what matters. + + // Verify response with detailed assertions. + assert.NotNil(t, resp, "Response should not be nil") + + // Verify correct response type matching. + switch tt.expectedResp.(type) { + case api.DeleteRegistry200JSONResponse: + _, ok := resp.(api.DeleteRegistry200JSONResponse) + assert.True(t, ok, "Expected 200 success response") + // Not checking Status field as it's hardcoded in test data and doesn't validate behavior. + + case api.DeleteRegistry400JSONResponse: + _, ok := resp.(api.DeleteRegistry400JSONResponse) + assert.True(t, ok, "Expected 400 bad request response") + // Not checking fields as they're hardcoded in test data. + + case api.DeleteRegistry403JSONResponse: + _, ok := resp.(api.DeleteRegistry403JSONResponse) + assert.True(t, ok, "Expected 403 forbidden response") + // Not checking fields as they're hardcoded in test data. + + case api.DeleteRegistry404JSONResponse: + _, ok := resp.(api.DeleteRegistry404JSONResponse) + assert.True(t, ok, "Expected 404 not found response") + // Not checking fields as they're hardcoded in test data. + + default: + // Fallback to simple type equality for any other response types. + expectedType := fmt.Sprintf("%T", tt.expectedResp) + actualType := fmt.Sprintf("%T", resp) + assert.Equal(t, expectedType, actualType, "Response type should match.") + } + + // Verify only essential mocks since we're not executing transaction functions. + if controller.SpaceFinder != nil { + mockSpaceFinder, ok := controller.SpaceFinder.(*mocks.SpaceFinder) + if !ok { + t.Fatal("Expected SpaceFinder to be of type *mocks.SpaceFinder") + } + mockSpaceFinder.AssertExpectations(t) + } + + // Verify only FindByRef and GetPermissionChecks from RegistryRepository. + if controller.RegistryRepository != nil { + mockRegistryRepo, ok := controller.RegistryRepository.(*mocks.RegistryRepository) + if !ok { + t.Fatal("Expected RegistryRepository to be of type *mocks.RegistryRepository") + } + // We could use AssertCalled for specific methods if needed. + // Only verify GetByParentIDAndName which is called before the transaction. + mockRegistryRepo.AssertCalled(t, "GetByParentIDAndName", mock.Anything, mock.Anything, mock.Anything) + } + + if controller.Authorizer != nil { + mockAuthorizer, ok := controller.Authorizer.(*mocks.Authorizer) + if !ok { + t.Fatal("Expected Authorizer to be of type *mocks.Authorizer") + } + mockAuthorizer.AssertExpectations(t) + } + + if controller.RegistryMetadataHelper != nil { + mockRegistryMetadataHelper, ok := controller.RegistryMetadataHelper.(*mocks.RegistryMetadataHelper) + if !ok { + t.Fatal("Expected RegistryMetadataHelper to be of type *mocks.RegistryMetadataHelper") + } + mockRegistryMetadataHelper.AssertExpectations(t) + } + + // Verify transaction was attempted. + if controller.tx != nil { + mockTx, ok := controller.tx.(*mocks.Transaction) + if !ok { + t.Fatal("Expected tx to be of type *mocks.Transaction") + } + mockTx.AssertCalled(t, "WithTx", mock.Anything, mock.Anything) + } + }) + } +} diff --git a/registry/app/api/controller/metadata/get_artifact_detail.go b/registry/app/api/controller/metadata/get_artifact_detail.go index 4e9aad17d..cdfa1a4b6 100644 --- a/registry/app/api/controller/metadata/get_artifact_detail.go +++ b/registry/app/api/controller/metadata/get_artifact_detail.go @@ -67,7 +67,7 @@ func (c *APIController) GetArtifactDetails( image := string(r.Artifact) version := string(r.Version) - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return artifact.GetArtifactDetails500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_artifact_files.go b/registry/app/api/controller/metadata/get_artifact_files.go index 09385eedd..62abf031a 100644 --- a/registry/app/api/controller/metadata/get_artifact_files.go +++ b/registry/app/api/controller/metadata/get_artifact_files.go @@ -69,7 +69,7 @@ func (c *APIController) GetArtifactFiles( image := string(r.Artifact) version := string(r.Version) - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, reqInfo.parentID, reqInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, reqInfo.ParentID, reqInfo.RegistryIdentifier) if err != nil { return artifact.GetArtifactFiles500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_artifacts.go b/registry/app/api/controller/metadata/get_artifacts.go index 027d9f8a1..9b57b4ef3 100644 --- a/registry/app/api/controller/metadata/get_artifacts.go +++ b/registry/app/api/controller/metadata/get_artifacts.go @@ -76,11 +76,11 @@ func (c *APIController) GetAllArtifacts( latestVersion = bool(*r.Params.LatestVersion) } artifacts, err := c.TagStore.GetAllArtifactsByParentID( - ctx, regInfo.parentID, ®Info.registryIDs, + ctx, regInfo.ParentID, ®Info.registryIDs, regInfo.sortByField, regInfo.sortByOrder, regInfo.limit, regInfo.offset, regInfo.searchTerm, latestVersion, regInfo.packageTypes) count, _ := c.TagStore.CountAllArtifactsByParentID( - ctx, regInfo.parentID, ®Info.registryIDs, + ctx, regInfo.ParentID, ®Info.registryIDs, regInfo.searchTerm, latestVersion, regInfo.packageTypes) if err != nil { return artifact.GetAllArtifacts500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_artifacts_docker_details.go b/registry/app/api/controller/metadata/get_artifacts_docker_details.go index 85c7ff591..1831be9e4 100644 --- a/registry/app/api/controller/metadata/get_artifacts_docker_details.go +++ b/registry/app/api/controller/metadata/get_artifacts_docker_details.go @@ -72,7 +72,7 @@ func (c *APIController) GetDockerArtifactDetails( version := string(r.Version) manifestDigest := string(r.Params.Digest) - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return artifact.GetDockerArtifactDetails500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_artifacts_docker_layers.go b/registry/app/api/controller/metadata/get_artifacts_docker_layers.go index ce2e93ede..17953a578 100644 --- a/registry/app/api/controller/metadata/get_artifacts_docker_layers.go +++ b/registry/app/api/controller/metadata/get_artifacts_docker_layers.go @@ -81,7 +81,7 @@ func (c *APIController) GetDockerArtifactLayers( if err != nil { return getLayersErrorResponse(ctx, err) } - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return getLayersErrorResponse(ctx, err) } diff --git a/registry/app/api/controller/metadata/get_artifacts_docker_manifest.go b/registry/app/api/controller/metadata/get_artifacts_docker_manifest.go index 280d8c516..0d701f96a 100644 --- a/registry/app/api/controller/metadata/get_artifacts_docker_manifest.go +++ b/registry/app/api/controller/metadata/get_artifacts_docker_manifest.go @@ -74,7 +74,7 @@ func (c *APIController) GetDockerArtifactManifest( manifestPayload, err := c.ManifestStore.GetManifestPayload( ctx, - regInfo.parentID, + regInfo.ParentID, regInfo.RegistryIdentifier, imageName, manifestDigest, diff --git a/registry/app/api/controller/metadata/get_artifacts_docker_manifests.go b/registry/app/api/controller/metadata/get_artifacts_docker_manifests.go index 52c62ad2b..6e06a40dd 100644 --- a/registry/app/api/controller/metadata/get_artifacts_docker_manifests.go +++ b/registry/app/api/controller/metadata/get_artifacts_docker_manifests.go @@ -92,10 +92,9 @@ func (c *APIController) GetDockerArtifactManifests( }, nil } -func (c *APIController) getManifestList( - ctx context.Context, reqManifest *ml.DeserializedManifestList, registry *types.Registry, image string, - regInfo *RegistryRequestBaseInfo, -) ([]artifact.DockerManifestDetails, error) { +func (c *APIController) getManifestList(ctx context.Context, reqManifest *ml.DeserializedManifestList, + registry *types.Registry, image string, regInfo *types.RegistryRequestBaseInfo) ( + []artifact.DockerManifestDetails, error) { manifestDetailsList := []artifact.DockerManifestDetails{} for _, manifestEntry := range reqManifest.Manifests { dgst, err := types.NewDigest(manifestEntry.Digest) @@ -169,10 +168,10 @@ func (c *APIController) getManifestDetails( // of Docker manifest details. func (c *APIController) ProcessManifest( ctx context.Context, - regInfo *RegistryRequestBaseInfo, + regInfo *types.RegistryRequestBaseInfo, image, version string, ) ([]artifact.DockerManifestDetails, error) { - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return nil, err } diff --git a/registry/app/api/controller/metadata/get_artifacts_helm_details.go b/registry/app/api/controller/metadata/get_artifacts_helm_details.go index d72ebfd7a..fe51ad858 100644 --- a/registry/app/api/controller/metadata/get_artifacts_helm_details.go +++ b/registry/app/api/controller/metadata/get_artifacts_helm_details.go @@ -67,7 +67,7 @@ func (c *APIController) GetHelmArtifactDetails( image := string(r.Artifact) version := string(r.Version) - registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + registry, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return artifact.GetHelmArtifactDetails500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_artifacts_helm_manifest.go b/registry/app/api/controller/metadata/get_artifacts_helm_manifest.go index f76ce075b..4b7ed8a42 100644 --- a/registry/app/api/controller/metadata/get_artifacts_helm_manifest.go +++ b/registry/app/api/controller/metadata/get_artifacts_helm_manifest.go @@ -65,7 +65,7 @@ func (c *APIController) GetHelmArtifactManifest( manifestPayload, err := c.ManifestStore.FindManifestPayloadByTagName( ctx, - regInfo.parentID, + regInfo.ParentID, regInfo.RegistryIdentifier, imageName, version, diff --git a/registry/app/api/controller/metadata/get_artifacts_labels.go b/registry/app/api/controller/metadata/get_artifacts_labels.go index aa279b0a2..bf194bdf6 100644 --- a/registry/app/api/controller/metadata/get_artifacts_labels.go +++ b/registry/app/api/controller/metadata/get_artifacts_labels.go @@ -77,11 +77,11 @@ func (c *APIController) ListArtifactLabels( } labels, err := c.ImageStore.GetLabelsByParentIDAndRepo( - ctx, regInfo.parentID, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.limit, regInfo.offset, regInfo.searchTerm, ) count, _ := c.ImageStore.CountLabelsByParentIDAndRepo( - ctx, regInfo.parentID, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.searchTerm, ) diff --git a/registry/app/api/controller/metadata/get_artifacts_version_summary.go b/registry/app/api/controller/metadata/get_artifacts_version_summary.go index 12f0eb40a..d402eff01 100644 --- a/registry/app/api/controller/metadata/get_artifacts_version_summary.go +++ b/registry/app/api/controller/metadata/get_artifacts_version_summary.go @@ -80,14 +80,14 @@ func (c *APIController) FetchArtifactSummary( } if registry.PackageType == artifact.PackageTypeDOCKER || registry.PackageType == artifact.PackageTypeHELM { - tag, err := c.TagStore.GetTagMetadata(ctx, regInfo.parentID, regInfo.RegistryIdentifier, image, version) + tag, err := c.TagStore.GetTagMetadata(ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, version) if err != nil { return "", "", "", err } return image, tag.Name, tag.PackageType, nil } - artifact, err := c.ArtifactStore.GetArtifactMetadata(ctx, regInfo.parentID, + artifact, err := c.ArtifactStore.GetArtifactMetadata(ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, version) if err != nil { diff --git a/registry/app/api/controller/metadata/get_artifacts_versions.go b/registry/app/api/controller/metadata/get_artifacts_versions.go index 106166b12..797966863 100644 --- a/registry/app/api/controller/metadata/get_artifacts_versions.go +++ b/registry/app/api/controller/metadata/get_artifacts_versions.go @@ -89,7 +89,7 @@ func (c *APIController) GetAllArtifactVersions( //nolint:nestif if registry.PackageType == artifact.PackageTypeDOCKER || registry.PackageType == artifact.PackageTypeHELM { tags, err := c.TagStore.GetAllTagsByRepoAndImage( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, regInfo.sortByField, regInfo.sortByOrder, regInfo.limit, regInfo.offset, regInfo.searchTerm, ) if err != nil { @@ -114,7 +114,7 @@ func (c *APIController) GetAllArtifactVersions( } } count, err := c.TagStore.CountAllTagsByRepoAndImage( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, regInfo.searchTerm, ) @@ -134,7 +134,7 @@ func (c *APIController) GetAllArtifactVersions( }, nil } metadata, err := c.ArtifactStore.GetAllVersionsByRepoAndImage( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, regInfo.sortByField, regInfo.sortByOrder, regInfo.limit, regInfo.offset, regInfo.searchTerm, ) if err != nil { @@ -142,7 +142,7 @@ func (c *APIController) GetAllArtifactVersions( } cnt, _ := c.ArtifactStore.CountAllVersionsByRepoAndImage( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, image, regInfo.searchTerm, ) @@ -164,6 +164,7 @@ func setDigestCount(ctx context.Context, tags []types.TagMetadata) error { return nil } +//nolint:unused // kept for potential future use func setDigestCountInTagMetadata(ctx context.Context, t *types.TagMetadata) error { m := types.Manifest{ SchemaVersion: t.SchemaVersion, @@ -188,6 +189,7 @@ func setDigestCountInTagMetadata(ctx context.Context, t *types.TagMetadata) erro return nil } +//nolint:unused,unparam // kept for potential future use func throw500Error(err error) (artifact.GetAllArtifactVersionsResponseObject, error) { wrappedErr := fmt.Errorf("internal server error: %w", err) return artifact.GetAllArtifactVersions500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_client_setup_details.go b/registry/app/api/controller/metadata/get_client_setup_details.go index daf3a608b..a892ab3aa 100644 --- a/registry/app/api/controller/metadata/get_client_setup_details.go +++ b/registry/app/api/controller/metadata/get_client_setup_details.go @@ -25,6 +25,7 @@ import ( "github.com/harness/gitness/app/paths" "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/app/common" + "github.com/harness/gitness/registry/utils" "github.com/harness/gitness/types/enum" "github.com/rs/zerolog/log" @@ -65,7 +66,7 @@ func (c *APIController) GetClientSetupDetails( }, nil } - reg, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + reg, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return artifact.GetClientSetupDetails404JSONResponse{ NotFoundJSONResponse: artifact.NotFoundJSONResponse( @@ -454,6 +455,7 @@ func (c *APIController) generateHelmClientSetupDetail( } } +// TODO: Remove StringPtr / see why it is used. func (c *APIController) generateMavenClientSetupDetail( ctx context.Context, artifactName *artifact.ArtifactParam, @@ -466,62 +468,62 @@ func (c *APIController) generateMavenClientSetupDetail( generateTokenStepType := artifact.ClientSetupStepTypeGenerateToken section1 := artifact.ClientSetupSection{ - Header: stringPtr("1. Generate Identity Token"), - SecHeader: stringPtr("An identity token will serve as the password for uploading and downloading artifacts."), + Header: utils.StringPtr("1. Generate Identity Token"), + SecHeader: utils.StringPtr("An identity token will serve as the password for uploading and downloading artifacts."), } _ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Generate an identity token"), + Header: utils.StringPtr("Generate an identity token"), Type: &generateTokenStepType, }, }, }) mavenSection1 := artifact.ClientSetupSection{ - Header: stringPtr("2. Pull a Maven Package"), - SecHeader: stringPtr("Set default repository in your pom.xml file."), + Header: utils.StringPtr("2. Pull a Maven Package"), + SecHeader: utils.StringPtr("Set default repository in your pom.xml file."), } _ = mavenSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("To set default registry in your pom.xml file by adding the following:"), + Header: utils.StringPtr("To set default registry in your pom.xml file by adding the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("\n \n maven-dev\n /\n \n true\n always\n \n \n true\n always\n \n \n"), + Value: utils.StringPtr("\n \n maven-dev\n /\n \n true\n always\n \n \n true\n always\n \n \n"), }, }, }, { //nolint:lll - Header: stringPtr("Copy the following your ~/ .m2/settings.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to pull from your Maven registry."), + Header: utils.StringPtr("Copy the following your ~/ .m2/settings.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to pull from your Maven registry."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("\n \n \n maven-dev\n \n identity-token\n \n \n"), + Value: utils.StringPtr("\n \n \n maven-dev\n \n identity-token\n \n \n"), }, }, }, { //nolint:lll - Header: stringPtr("Add a dependency to the project's pom.xml (replace , & with your own):"), + Header: utils.StringPtr("Add a dependency to the project's pom.xml (replace , & with your own):"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("\n \n \n \n"), + Value: utils.StringPtr("\n \n \n \n"), }, }, }, { - Header: stringPtr("Install dependencies in pom.xml file"), + Header: utils.StringPtr("Install dependencies in pom.xml file"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("mvn install"), + Value: utils.StringPtr("mvn install"), }, }, }, @@ -529,39 +531,39 @@ func (c *APIController) generateMavenClientSetupDetail( }) mavenSection2 := artifact.ClientSetupSection{ - Header: stringPtr("3. Push a Maven Package"), - SecHeader: stringPtr("Set default repository in your pom.xml file."), + Header: utils.StringPtr("3. Push a Maven Package"), + SecHeader: utils.StringPtr("Set default repository in your pom.xml file."), } _ = mavenSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("To set default registry in your pom.xml file by adding the following:"), + Header: utils.StringPtr("To set default registry in your pom.xml file by adding the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("\n \n maven-dev\n /\n \n \n maven-dev\n /\n \n"), + Value: utils.StringPtr("\n \n maven-dev\n /\n \n \n maven-dev\n /\n \n"), }, }, }, { //nolint:lll - Header: stringPtr("Copy the following your ~/ .m2/setting.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to push to your Maven registry."), + Header: utils.StringPtr("Copy the following your ~/ .m2/setting.xml file for MacOs, or $USERPROFILE$\\ .m2\\settings.xml for Windows to authenticate with token to push to your Maven registry."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("\n \n \n maven-dev\n \n identity-token\n \n \n"), + Value: utils.StringPtr("\n \n \n maven-dev\n \n identity-token\n \n \n"), }, }, }, { - Header: stringPtr("Publish package to your Maven registry."), + Header: utils.StringPtr("Publish package to your Maven registry."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("mvn deploy"), + Value: utils.StringPtr("mvn deploy"), }, }, }, @@ -569,46 +571,46 @@ func (c *APIController) generateMavenClientSetupDetail( }) gradleSection1 := artifact.ClientSetupSection{ - Header: stringPtr("2. Pull a Gradle Package"), - SecHeader: stringPtr("Set default repository in your build.gradle file."), + Header: utils.StringPtr("2. Pull a Gradle Package"), + SecHeader: utils.StringPtr("Set default repository in your build.gradle file."), } _ = gradleSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Set the default registry in your project’s build.gradle by adding the following:"), + Header: utils.StringPtr("Set the default registry in your project’s build.gradle by adding the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("repositories{\n maven{\n url \"/\"\n\n credentials {\n username \"\"\n password \"identity-token\"\n }\n }\n}"), + Value: utils.StringPtr("repositories{\n maven{\n url \"/\"\n\n credentials {\n username \"\"\n password \"identity-token\"\n }\n }\n}"), }, }, }, { //nolint:lll - Header: stringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.gradle/gradle.properties file with the following:"), + Header: utils.StringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.gradle/gradle.properties file with the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("repositoryUser=\nrepositoryPassword={{identity-token}}"), + Value: utils.StringPtr("repositoryUser=\nrepositoryPassword={{identity-token}}"), }, }, }, { - Header: stringPtr("Add a dependency to the project’s build.gradle"), + Header: utils.StringPtr("Add a dependency to the project’s build.gradle"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("dependencies {\n implementation '::'\n}"), + Value: utils.StringPtr("dependencies {\n implementation '::'\n}"), }, }, }, { - Header: stringPtr("Install dependencies in build.gradle file"), + Header: utils.StringPtr("Install dependencies in build.gradle file"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("gradlew build // Linux or OSX\n gradlew.bat build // Windows"), + Value: utils.StringPtr("gradlew build // Linux or OSX\n gradlew.bat build // Windows"), }, }, }, @@ -616,28 +618,28 @@ func (c *APIController) generateMavenClientSetupDetail( }) gradleSection2 := artifact.ClientSetupSection{ - Header: stringPtr("3. Push a Gradle Package"), - SecHeader: stringPtr("Set default repository in your build.gradle file."), + Header: utils.StringPtr("3. Push a Gradle Package"), + SecHeader: utils.StringPtr("Set default repository in your build.gradle file."), } _ = gradleSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Add a maven publish plugin configuration to the project's build.gradle."), + Header: utils.StringPtr("Add a maven publish plugin configuration to the project's build.gradle."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("publishing {\n publications {\n maven(MavenPublication) {\n groupId = 'GROUP_ID'\n artifactId = 'ARTIFACT_ID'\n version = 'VERSION'\n\n from components.java\n }\n }\n}"), + Value: utils.StringPtr("publishing {\n publications {\n maven(MavenPublication) {\n groupId = 'GROUP_ID'\n artifactId = 'ARTIFACT_ID'\n version = 'VERSION'\n\n from components.java\n }\n }\n}"), }, }, }, { - Header: stringPtr("Publish package to your Maven registry."), + Header: utils.StringPtr("Publish package to your Maven registry."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("gradlew publish"), + Value: utils.StringPtr("gradlew publish"), }, }, }, @@ -645,47 +647,47 @@ func (c *APIController) generateMavenClientSetupDetail( }) sbtSection1 := artifact.ClientSetupSection{ - Header: stringPtr("2. Pull a Sbt/Scala Package"), - SecHeader: stringPtr("Set default repository in your build.sbt file."), + Header: utils.StringPtr("2. Pull a Sbt/Scala Package"), + SecHeader: utils.StringPtr("Set default repository in your build.sbt file."), } _ = sbtSection1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Set the default registry in your project’s build.sbt by adding the following:"), + Header: utils.StringPtr("Set the default registry in your project’s build.sbt by adding the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("resolver += \"Harness Registry\" at \"/\"\ncredentials += Credentials(Path.userHome / \".sbt\" / \".Credentials\")"), + Value: utils.StringPtr("resolver += \"Harness Registry\" at \"/\"\ncredentials += Credentials(Path.userHome / \".sbt\" / \".Credentials\")"), }, }, }, { //nolint:lll - Header: stringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.sbt/.credentials file with the following:"), + Header: utils.StringPtr("As this is a private registry, you’ll need to authenticate. Create or add to the ~/.sbt/.credentials file with the following:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { //nolint:lll - Value: stringPtr("realm=Harness Registry\nhost=\nuser=\npassword={{identity-token}}"), + Value: utils.StringPtr("realm=Harness Registry\nhost=\nuser=\npassword={{identity-token}}"), }, }, }, { - Header: stringPtr("Add a dependency to the project’s build.sbt"), + Header: utils.StringPtr("Add a dependency to the project’s build.sbt"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("libraryDependencies += \"\" % \"\" % \"\""), + Value: utils.StringPtr("libraryDependencies += \"\" % \"\" % \"\""), }, }, }, { - Header: stringPtr("Install dependencies in build.sbt file"), + Header: utils.StringPtr("Install dependencies in build.sbt file"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("sbt update"), + Value: utils.StringPtr("sbt update"), }, }, }, @@ -693,27 +695,27 @@ func (c *APIController) generateMavenClientSetupDetail( }) sbtSection2 := artifact.ClientSetupSection{ - Header: stringPtr("3. Push a Sbt/Scala Package"), - SecHeader: stringPtr("Set default repository in your build.sbt file."), + Header: utils.StringPtr("3. Push a Sbt/Scala Package"), + SecHeader: utils.StringPtr("Set default repository in your build.sbt file."), } _ = sbtSection2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Add publish configuration to the project’s build.sbt."), + Header: utils.StringPtr("Add publish configuration to the project’s build.sbt."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("publishTo := Some(\"Harness Registry\" at \"/\")"), + Value: utils.StringPtr("publishTo := Some(\"Harness Registry\" at \"/\")"), }, }, }, { - Header: stringPtr("Publish package to your Maven registry."), + Header: utils.StringPtr("Publish package to your Maven registry."), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("sbt publish"), + Value: utils.StringPtr("sbt publish"), }, }, }, @@ -724,19 +726,19 @@ func (c *APIController) generateMavenClientSetupDetail( config := artifact.TabSetupStepConfig{ Tabs: &[]artifact.TabSetupStep{ { - Header: stringPtr("Maven"), + Header: utils.StringPtr("Maven"), Sections: &[]artifact.ClientSetupSection{ mavenSection1, }, }, { - Header: stringPtr("Gradle"), + Header: utils.StringPtr("Gradle"), Sections: &[]artifact.ClientSetupSection{ gradleSection1, }, }, { - Header: stringPtr("Sbt/Scala"), + Header: utils.StringPtr("Sbt/Scala"), Sections: &[]artifact.ClientSetupSection{ sbtSection1, }, @@ -794,16 +796,16 @@ func (c *APIController) generatePythonClientSetupDetail( // Authentication section section1 := artifact.ClientSetupSection{ - Header: stringPtr("Configure Authentication"), + Header: utils.StringPtr("Configure Authentication"), } _ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Create or update your ~/.pypirc file with the following content:"), + Header: utils.StringPtr("Create or update your ~/.pypirc file with the following content:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("[distutils]\n" + + Value: utils.StringPtr("[distutils]\n" + "index-servers = harness\n\n" + "[harness]\n" + "repository = \n" + @@ -813,7 +815,7 @@ func (c *APIController) generatePythonClientSetupDetail( }, }, { - Header: stringPtr("Generate an identity token for authentication"), + Header: utils.StringPtr("Generate an identity token for authentication"), Type: &generateTokenType, }, }, @@ -821,19 +823,19 @@ func (c *APIController) generatePythonClientSetupDetail( // Publish section section2 := artifact.ClientSetupSection{ - Header: stringPtr("Publish Package"), + Header: utils.StringPtr("Publish Package"), } _ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Build and publish your package:"), + Header: utils.StringPtr("Build and publish your package:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("python -m build"), + Value: utils.StringPtr("python -m build"), }, { - Value: stringPtr("python -m twine upload --repository harness /path/to/files/*"), + Value: utils.StringPtr("python -m twine upload --repository harness /path/to/files/*"), }, }, }, @@ -842,16 +844,16 @@ func (c *APIController) generatePythonClientSetupDetail( // Install section section3 := artifact.ClientSetupSection{ - Header: stringPtr("Install Package"), + Header: utils.StringPtr("Install Package"), } _ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Install a package using pip:"), + Header: utils.StringPtr("Install a package using pip:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("pip install --index-url /simple --no-deps =="), + Value: utils.StringPtr("pip install --index-url /simple --no-deps =="), }, }, }, @@ -901,24 +903,24 @@ func (c *APIController) generateNpmClientSetupDetail( // Authentication section section1 := artifact.ClientSetupSection{ - Header: stringPtr("Configure Authentication"), + Header: utils.StringPtr("Configure Authentication"), } _ = section1.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Create or update your ~/.npmrc file with the following content:"), + Header: utils.StringPtr("Create or update your ~/.npmrc file with the following content:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("https:/"), + Value: utils.StringPtr("https:/"), }, { - Value: stringPtr("/:_authToken "), + Value: utils.StringPtr("/:_authToken "), }, }, }, { - Header: stringPtr("Generate an identity token for authentication"), + Header: utils.StringPtr("Generate an identity token for authentication"), Type: &generateTokenType, }, }, @@ -926,19 +928,19 @@ func (c *APIController) generateNpmClientSetupDetail( // Publish section section2 := artifact.ClientSetupSection{ - Header: stringPtr("Publish Package"), + Header: utils.StringPtr("Publish Package"), } _ = section2.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Build and publish your package:"), + Header: utils.StringPtr("Build and publish your package:"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("npm init -y\n"), + Value: utils.StringPtr("npm run build\n"), }, { - Value: stringPtr("npm publish"), + Value: utils.StringPtr("npm publish"), }, }, }, @@ -947,16 +949,16 @@ func (c *APIController) generateNpmClientSetupDetail( // Install section section3 := artifact.ClientSetupSection{ - Header: stringPtr("Install Package"), + Header: utils.StringPtr("Install Package"), } _ = section3.FromClientSetupStepConfig(artifact.ClientSetupStepConfig{ Steps: &[]artifact.ClientSetupStep{ { - Header: stringPtr("Install a package using npm"), + Header: utils.StringPtr("Install a package using npm"), Type: &staticStepType, Commands: &[]artifact.ClientSetupStepCommand{ { - Value: stringPtr("npm install @"), + Value: utils.StringPtr("npm install @"), }, }, }, @@ -1078,44 +1080,40 @@ func replaceText( uploadURL string, ) { if username != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", username)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", username)) if (*st.Commands)[i].Label != nil { - (*st.Commands)[i].Label = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Label, "", username)) + (*st.Commands)[i].Label = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Label, "", username)) } } if groupID != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", groupID)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", groupID)) } if registryURL != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", registryURL)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", registryURL)) } if uploadURL != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", uploadURL)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", uploadURL)) } if hostname != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", hostname)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", hostname)) } if hostname != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", common.GetHost(hostname))) } if repoName != "" { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", repoName)) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", repoName)) } if image != nil { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*image))) - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*image))) - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*image))) } if tag != nil { - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*tag))) - (*st.Commands)[i].Value = stringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*tag))) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*tag))) + (*st.Commands)[i].Value = utils.StringPtr(strings.ReplaceAll(*(*st.Commands)[i].Value, "", string(*tag))) } } - -func stringPtr(s string) *string { - return &s -} diff --git a/registry/app/api/controller/metadata/get_registries.go b/registry/app/api/controller/metadata/get_registries.go index ec67d2e22..b30585926 100644 --- a/registry/app/api/controller/metadata/get_registries.go +++ b/registry/app/api/controller/metadata/get_registries.go @@ -96,7 +96,7 @@ func (c *APIController) GetAllRegistries( var count int64 repos, err = c.RegistryRepository.GetAll( ctx, - regInfo.parentID, + regInfo.ParentID, regInfo.packageTypes, regInfo.sortByField, regInfo.sortByOrder, @@ -108,7 +108,7 @@ func (c *APIController) GetAllRegistries( ) count, _ = c.RegistryRepository.CountAll( ctx, - regInfo.parentID, + regInfo.ParentID, regInfo.packageTypes, regInfo.searchTerm, repoType, diff --git a/registry/app/api/controller/metadata/get_registry.go b/registry/app/api/controller/metadata/get_registry.go index 9f153cc3b..e28f4dbeb 100644 --- a/registry/app/api/controller/metadata/get_registry.go +++ b/registry/app/api/controller/metadata/get_registry.go @@ -60,7 +60,7 @@ func (c *APIController) GetRegistry( ), }, nil } - repoEntity, _ := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + repoEntity, _ := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if string(repoEntity.Type) == string(artifact.RegistryTypeVIRTUAL) { cleanupPolicies, err := c.CleanupPolicyStore.GetByRegistryID(ctx, repoEntity.ID) if err != nil { @@ -84,7 +84,7 @@ func (c *APIController) GetRegistry( } upstreamproxyEntity, err := c.UpstreamProxyStore.GetByRegistryIdentifier( ctx, - regInfo.parentID, regInfo.RegistryIdentifier, + regInfo.ParentID, regInfo.RegistryIdentifier, ) if len(upstreamproxyEntity.RepoKey) == 0 { return artifact.GetRegistry404JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_registry_artifacts.go b/registry/app/api/controller/metadata/get_registry_artifacts.go index e5eb38264..dba4d7c41 100644 --- a/registry/app/api/controller/metadata/get_registry_artifacts.go +++ b/registry/app/api/controller/metadata/get_registry_artifacts.go @@ -85,11 +85,11 @@ func (c *APIController) GetAllArtifactsByRegistry( var count int64 if registry.PackageType == artifact.PackageTypeDOCKER || registry.PackageType == artifact.PackageTypeHELM { artifacts, err = c.TagStore.GetAllArtifactsByRepo( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.sortByField, regInfo.sortByOrder, regInfo.limit, regInfo.offset, regInfo.searchTerm, regInfo.labels, ) count, _ = c.TagStore.CountAllArtifactsByRepo( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.searchTerm, regInfo.labels, ) if err != nil { @@ -101,10 +101,10 @@ func (c *APIController) GetAllArtifactsByRegistry( } } else { artifacts, err = c.ArtifactStore.GetArtifactsByRepo( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.sortByField, regInfo.sortByOrder, regInfo.limit, regInfo.offset, regInfo.searchTerm, regInfo.labels) count, _ = c.ArtifactStore.CountArtifactsByRepo( - ctx, regInfo.parentID, regInfo.RegistryIdentifier, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, regInfo.searchTerm, regInfo.labels) if err != nil { return artifact.GetAllArtifactsByRegistry500JSONResponse{ diff --git a/registry/app/api/controller/metadata/get_webhook_execution_test.go b/registry/app/api/controller/metadata/get_webhook_execution_test.go index 9b138c10b..83c549faf 100644 --- a/registry/app/api/controller/metadata/get_webhook_execution_test.go +++ b/registry/app/api/controller/metadata/get_webhook_execution_test.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//nolint:lll package metadata import ( @@ -20,239 +21,262 @@ import ( "testing" "time" + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/registry/app/api/controller/mocks" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" - gitnesstypes "github.com/harness/gitness/types" + "github.com/harness/gitness/registry/types" + coretypes "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) -//nolint:errcheck -func TestGetWebhookExecution_Success(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } +func TestGetWebhookExecution(t *testing.T) { + now := time.Now().Unix() + tests := []struct { + name string + setupMocks func( + *APIController, + *mocks.SpaceFinder, + *mocks.Authorizer, + *mocks.RegistryMetadataHelper, + *mocks.WebhooksRepository, + *mocks.WebhooksExecutionRepository) + request api.GetWebhookExecutionRequestObject + validate func(*testing.T, api.GetWebhookExecutionResponseObject, error) + }{ + { + name: "invalid_execution_identifier", + setupMocks: func(c *APIController, mockSpaceFinder *mocks.SpaceFinder, mockAuthorizer *mocks.Authorizer, mockRegistryMetadataHelper *mocks.RegistryMetadataHelper, mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository) { + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, - regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockWebhooksExecutionRepository.On("Find", ctx, int64(1)).Return(&gitnesstypes.WebhookExecutionCore{ - ID: 1, - Created: time.Now().Unix(), - Duration: 100, - Error: "none", - Request: gitnesstypes.WebhookExecutionRequest{ - Body: "{}", Headers: "headers", URL: "http://example.com", + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, "reg", enum.PermissionRegistryView).Return([]coretypes.PermissionCheck{}) + mockAuthorizer.On("CheckAll", mock.Anything, (*auth.Session)(nil), mock.Anything).Return(true, nil) + + c.SpaceFinder = mockSpaceFinder + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.WebhooksRepository = mockWebhooksRepo + c.WebhooksExecutionRepository = mockWebhooksExecRepo + }, + request: api.GetWebhookExecutionRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + WebhookExecutionId: "invalid", + }, + validate: func(t *testing.T, response api.GetWebhookExecutionResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.GetWebhookExecution400JSONResponse) + assert.True(t, ok, "expected 400 response") + assert.Equal(t, "400", resp.Code) + assert.Equal(t, "invalid webhook execution identifier: invalid, err: strconv.ParseInt: parsing \"invalid\": invalid syntax", resp.Message) + }, }, - Response: gitnesstypes.WebhookExecutionResponse{ - Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200, + { + name: "permission_check_fails", + setupMocks: func(c *APIController, mockSpaceFinder *mocks.SpaceFinder, mockAuthorizer *mocks.Authorizer, mockRegistryMetadataHelper *mocks.RegistryMetadataHelper, mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository) { + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, "reg", enum.PermissionRegistryView).Return([]coretypes.PermissionCheck{}) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(false, nil) + + c.SpaceFinder = mockSpaceFinder + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.WebhooksRepository = mockWebhooksRepo + c.WebhooksExecutionRepository = mockWebhooksExecRepo + }, + request: api.GetWebhookExecutionRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + WebhookExecutionId: "1", + }, + validate: func(t *testing.T, response api.GetWebhookExecutionResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.GetWebhookExecution403JSONResponse) + assert.True(t, ok, "expected 403 response") + assert.Equal(t, "403", resp.Code) + assert.Equal(t, "forbidden", resp.Message) + }, }, - RetriggerOf: nil, - Retriggerable: true, - WebhookID: 4, - Result: enum.WebhookExecutionResultSuccess, - TriggerType: enum.WebhookTriggerArtifactCreated}, nil) + { + name: "success_case", + setupMocks: func(c *APIController, mockSpaceFinder *mocks.SpaceFinder, mockAuthorizer *mocks.Authorizer, mockRegistryMetadataHelper *mocks.RegistryMetadataHelper, mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository) { + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } - r := api.GetWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", + execution := &coretypes.WebhookExecutionCore{ + ID: 1, + Created: now, + WebhookID: 1, + Result: enum.WebhookExecutionResultSuccess, + Duration: 0, + Error: "", + Retriggerable: false, + Request: coretypes.WebhookExecutionRequest{ + URL: "http://example.com", + Headers: "{}", + Body: "{}", + }, + Response: coretypes.WebhookExecutionResponse{ + StatusCode: 200, + Status: "OK", + Headers: "{}", + Body: "{}", + }, + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, "reg", enum.PermissionRegistryView).Return([]coretypes.PermissionCheck{}) + mockAuthorizer.On("CheckAll", mock.Anything, (*auth.Session)(nil)).Return(true, nil) + mockWebhooksExecRepo.On("Find", mock.Anything, int64(1)).Return(execution, nil) + + c.SpaceFinder = mockSpaceFinder + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.WebhooksRepository = mockWebhooksRepo + c.WebhooksExecutionRepository = mockWebhooksExecRepo + }, + request: api.GetWebhookExecutionRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + WebhookExecutionId: "1", + }, + validate: func(t *testing.T, response api.GetWebhookExecutionResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.GetWebhookExecution200JSONResponse) + assert.True(t, ok, "expected 200 response") + assert.Equal(t, api.StatusSUCCESS, resp.Status) + + exec := resp.Data + assert.Equal(t, int64(1), *exec.Id) + assert.Equal(t, now, *exec.Created) + assert.Equal(t, int64(1), *exec.WebhookId) + assert.Equal(t, api.WebhookExecResultSUCCESS, *exec.Result) + assert.Equal(t, int64(0), *exec.Duration) + assert.Equal(t, "", *exec.Error) + assert.False(t, *exec.Retriggerable) + + assert.Equal(t, "http://example.com", *exec.Request.Url) + assert.Equal(t, "{}", *exec.Request.Headers) + assert.Equal(t, "{}", *exec.Request.Body) + + assert.Equal(t, 200, *exec.Response.StatusCode) + assert.Equal(t, "OK", *exec.Response.Status) + assert.Equal(t, "{}", *exec.Response.Headers) + assert.Equal(t, "{}", *exec.Response.Body) + }, + }, + { + name: "find_execution_error", + setupMocks: func(c *APIController, mockSpaceFinder *mocks.SpaceFinder, mockAuthorizer *mocks.Authorizer, mockRegistryMetadataHelper *mocks.RegistryMetadataHelper, mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository) { + space := &coretypes.SpaceCore{ID: 2} + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentID: 2, + ParentRef: "root/parent", + } + + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On( + "GetRegistryRequestBaseInfo", + mock.Anything, + "", + "reg", + ).Return(regInfo, nil) + mockRegistryMetadataHelper.On( + "GetPermissionChecks", + space, + "reg", + enum.PermissionRegistryView, + ).Return([]coretypes.PermissionCheck{}) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockWebhooksExecRepo.On( + "Find", + mock.Anything, + int64(1), + ).Return(nil, fmt.Errorf("error finding execution")) + + c.SpaceFinder = mockSpaceFinder + c.Authorizer = mockAuthorizer + c.RegistryMetadataHelper = mockRegistryMetadataHelper + c.WebhooksRepository = mockWebhooksRepo + c.WebhooksExecutionRepository = mockWebhooksExecRepo + }, + request: api.GetWebhookExecutionRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + WebhookExecutionId: "1", + }, + validate: func(t *testing.T, response api.GetWebhookExecutionResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.GetWebhookExecution500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "500", resp.Code) + assert.Equal(t, "failed to find webhook execution: error finding execution", resp.Message) + }, + }, } - response, err := controller.GetWebhookExecution(ctx, r) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mocks + mockSpaceFinder := new(mocks.SpaceFinder) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockWebhooksRepo := new(mocks.WebhooksRepository) + mockWebhooksExecRepo := new(mocks.WebhooksExecutionRepository) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.Equal(t, api.StatusSUCCESS, response.(api.GetWebhookExecution200JSONResponse).Status) - assert.Equal(t, int64(1), *response.(api.GetWebhookExecution200JSONResponse).Data.Id) - assert.Equal(t, "none", *response.(api.GetWebhookExecution200JSONResponse).Data.Error) - assert.Equal(t, "{}", *response.(api.GetWebhookExecution200JSONResponse).Data.Request.Body) - assert.Equal(t, "headers", *response.(api.GetWebhookExecution200JSONResponse).Data.Request.Headers) - assert.Equal(t, "http://example.com", *response.(api.GetWebhookExecution200JSONResponse).Data.Request.Url) - assert.Equal(t, "{}", *response.(api.GetWebhookExecution200JSONResponse).Data.Response.Body) - assert.Equal(t, "headers", *response.(api.GetWebhookExecution200JSONResponse).Data.Response.Headers) - assert.Equal(t, "200 OK", *response.(api.GetWebhookExecution200JSONResponse).Data.Response.Status) - assert.Equal(t, 200, *response.(api.GetWebhookExecution200JSONResponse).Data.Response.StatusCode) - assert.Equal(t, api.WebhookExecResultSUCCESS, *response.(api.GetWebhookExecution200JSONResponse).Data.Result) - assert.Equal(t, api.TriggerARTIFACTCREATION, *response.(api.GetWebhookExecution200JSONResponse).Data.TriggerType) - assert.Equal(t, api.StatusSUCCESS, response.(api.GetWebhookExecution200JSONResponse).Status) + // Create controller + controller := &APIController{} - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) -} - -//nolint:errcheck -func TestGetWebhookExecution_PermissionCheckFails(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On( - "GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView, - ).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(false, nil) - - r := api.GetWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", - } - - response, err := controller.GetWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.GetWebhookExecution403JSONResponse{}, response) - assert.Equal(t, "forbidden", response.(api.GetWebhookExecution403JSONResponse).Message) - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) -} - -//nolint:errcheck -func TestGetWebhookExecution_InvalidExecutionIdentifier(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On( - "GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView, - ).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - - r := api.GetWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "invalid", - } - - response, err := controller.GetWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.GetWebhookExecution400JSONResponse{}, response) - assert.Equal(t, - "invalid webhook execution identifier: invalid, err: strconv.ParseInt: parsing \"invalid\": invalid syntax", - response.(api.GetWebhookExecution400JSONResponse).Message) - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) -} - -//nolint:errcheck -func TestGetWebhookExecution_FindExecutionError(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, - enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockWebhooksExecutionRepository.On("Find", ctx, int64(1)). - Return(nil, fmt.Errorf("error")) - - r := api.GetWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", - } - - response, err := controller.GetWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.GetWebhookExecution500JSONResponse{}, response) - assert.Equal(t, "failed to find webhook execution: error", - response.(api.GetWebhookExecution500JSONResponse).Message) - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) + // Setup mocks + tt.setupMocks(controller, mockSpaceFinder, mockAuthorizer, mockRegistryMetadataHelper, mockWebhooksRepo, mockWebhooksExecRepo) + + // Call function + resp, err := controller.GetWebhookExecution(context.Background(), tt.request) + + // Validate response + tt.validate(t, resp, err) + + // Verify mock expectations + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryMetadataHelper.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + mockWebhooksExecRepo.AssertExpectations(t) + }) + } } diff --git a/registry/app/api/controller/metadata/list_webhook_execution_test.go b/registry/app/api/controller/metadata/list_webhook_execution_test.go index 20e0395e6..5e8783b77 100644 --- a/registry/app/api/controller/metadata/list_webhook_execution_test.go +++ b/registry/app/api/controller/metadata/list_webhook_execution_test.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +//nolint:lll,revive // revive:disable:unused-parameter package metadata import ( @@ -20,8 +21,10 @@ import ( "testing" "time" + "github.com/harness/gitness/registry/app/api/controller/mocks" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/types" + "github.com/harness/gitness/registry/utils" gitnesstypes "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" @@ -29,498 +32,700 @@ import ( "github.com/stretchr/testify/mock" ) -//nolint:lll -func TestListWebhookExecutions_Success(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) - mockWebhooksRepository.On("GetByRegistryAndIdentifier", ctx, int64(3), "webhook").Return(&gitnesstypes.WebhookCore{ID: 4}, nil) - mockWebhooksExecutionRepository.On("ListForWebhook", ctx, int64(4), 10, 1, 10).Return([]*gitnesstypes.WebhookExecutionCore{ +func TestListWebhookExecutions(t *testing.T) { + tests := []struct { + name string + request api.ListWebhookExecutionsRequestObject + setupMocks func(*mocks.SpaceFinder, *mocks.RegistryRepository, *mocks.WebhooksRepository, + *mocks.WebhooksExecutionRepository, *mocks.Authorizer, *mocks.RegistryMetadataHelper) + validate func(*testing.T, api.ListWebhookExecutionsResponseObject, error) + verifyMocks func(*testing.T, *mocks.SpaceFinder, *mocks.RegistryRepository, *mocks.WebhooksRepository, + *mocks.WebhooksExecutionRepository, *mocks.Authorizer, *mocks.RegistryMetadataHelper) + }{ { - ID: 1, - Created: time.Now().Unix(), - Duration: 100, - Error: "none", - Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, - Response: gitnesstypes.WebhookExecutionResponse{Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200}, - RetriggerOf: nil, - Retriggerable: true, - WebhookID: 4, - Result: enum.WebhookExecutionResultSuccess, - TriggerType: enum.WebhookTriggerArtifactCreated, + name: "success_case", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + // session := &auth.Session{} + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) + mockWebhooksRepo.On( + "GetByRegistryAndIdentifier", + mock.Anything, + int64(3), + "webhook", + ).Return(&gitnesstypes.WebhookCore{ID: 4}, nil) + mockWebhooksExecRepo.On( + "ListForWebhook", + mock.Anything, + int64(4), + 10, 1, 10, + ).Return([]*gitnesstypes.WebhookExecutionCore{ + { + ID: 1, + Created: time.Now().Unix(), + Duration: 100, + Error: "none", + Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, + Response: gitnesstypes.WebhookExecutionResponse{ + Body: "{}", + Headers: "headers", + Status: "200 OK", + StatusCode: 200, + }, + RetriggerOf: nil, + Retriggerable: true, + WebhookID: 4, + Result: enum.WebhookExecutionResultSuccess, + TriggerType: enum.WebhookTriggerArtifactCreated, + }, + }, nil) + mockWebhooksExecRepo.On("CountForWebhook", mock.Anything, int64(4)).Return(int64(1), nil) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.ListWebhookExecutions200JSONResponse) + assert.True(t, ok, "expected 200 response") + assert.Equal(t, api.StatusSUCCESS, resp.Status) + assert.Len(t, resp.Data.Executions, 1) + + exec := resp.Data.Executions[0] + assert.Equal(t, int64(1), *exec.Id) + assert.Equal(t, "none", *exec.Error) + assert.Equal(t, "{}", *exec.Request.Body) + assert.Equal(t, "headers", *exec.Request.Headers) + assert.Equal(t, "http://example.com", *exec.Request.Url) + assert.Equal(t, "{}", *exec.Response.Body) + assert.Equal(t, "headers", *exec.Response.Headers) + assert.Equal(t, "200 OK", *exec.Response.Status) + assert.Equal(t, 200, *exec.Response.StatusCode) + assert.Equal(t, api.WebhookExecResultSUCCESS, *exec.Result) + assert.Equal(t, api.TriggerARTIFACTCREATION, *exec.TriggerType) + + assert.Equal(t, int64(1), *resp.Data.ItemCount) + assert.Equal(t, 1, *resp.Data.PageSize) + assert.Equal(t, int64(1), *resp.Data.PageIndex) + assert.Equal(t, int64(1), *resp.Data.PageCount) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + mockWebhooksExecRepo.AssertExpectations(t) + }, }, - }, nil) - mockWebhooksExecutionRepository.On("CountForWebhook", ctx, int64(4)).Return(int64(1), nil) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(1) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - listWebhookExecutions200JSONResponse, ok := response.(api.ListWebhookExecutions200JSONResponse) - if !ok { - t.Fatalf("expected api.ListWebhookExecutions200JSONResponse, got %T", response) - } - assert.NoError(t, err) - assert.NotNil(t, response) - assert.Equal(t, api.StatusSUCCESS, listWebhookExecutions200JSONResponse.Status) - assert.Len(t, listWebhookExecutions200JSONResponse.Data.Executions, 1) - assert.Equal(t, int64(1), *listWebhookExecutions200JSONResponse.Data.Executions[0].Id) - assert.Equal(t, "none", *listWebhookExecutions200JSONResponse.Data.Executions[0].Error) - assert.Equal(t, "{}", *listWebhookExecutions200JSONResponse.Data.Executions[0].Request.Body) - assert.Equal(t, "headers", *listWebhookExecutions200JSONResponse.Data.Executions[0].Request.Headers) - assert.Equal(t, "http://example.com", *listWebhookExecutions200JSONResponse.Data.Executions[0].Request.Url) - assert.Equal(t, "{}", *listWebhookExecutions200JSONResponse.Data.Executions[0].Response.Body) - assert.Equal(t, "headers", *listWebhookExecutions200JSONResponse.Data.Executions[0].Response.Headers) - assert.Equal(t, "200 OK", *listWebhookExecutions200JSONResponse.Data.Executions[0].Response.Status) - assert.Equal(t, 200, *listWebhookExecutions200JSONResponse.Data.Executions[0].Response.StatusCode) - assert.Equal(t, api.WebhookExecResultSUCCESS, *listWebhookExecutions200JSONResponse.Data.Executions[0].Result) - assert.Equal(t, api.TriggerARTIFACTCREATION, *listWebhookExecutions200JSONResponse.Data.Executions[0].TriggerType) - assert.Equal(t, int64(1), *listWebhookExecutions200JSONResponse.Data.ItemCount) - assert.Equal(t, 1, *listWebhookExecutions200JSONResponse.Data.PageSize) - assert.Equal(t, int64(1), *listWebhookExecutions200JSONResponse.Data.PageIndex) - assert.Equal(t, int64(1), *listWebhookExecutions200JSONResponse.Data.PageCount) - assert.Equal(t, api.StatusSUCCESS, listWebhookExecutions200JSONResponse.Status) - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockRegistryRepository.AssertExpectations(t) - mockWebhooksRepository.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_GetRegistryRequestBaseInfoError(t *testing.T) { - ctx := context.Background() - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(nil, fmt.Errorf("error")) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(11) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck - mockRegistryMetadataHelper.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_FindByRefError(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(nil, fmt.Errorf("error")) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(11) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_CheckPermissionsFails(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(false, nil) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(11) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions403JSONResponse{}, response) - assert.Equal(t, "forbidden", response.(api.ListWebhookExecutions403JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_FailedToDetRegistry(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(nil, fmt.Errorf("error")) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(1) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "failed to find registry: error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockRegistryRepository.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_FailedToGetWebhook(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) - mockWebhooksRepository.On("GetByRegistryAndIdentifier", ctx, int64(3), "webhook").Return(nil, fmt.Errorf("error")) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(1) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "failed to find webhook [webhook] : error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockRegistryRepository.AssertExpectations(t) - mockWebhooksRepository.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_FailedToGetWebhookExecutions(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) - mockWebhooksRepository.On("GetByRegistryAndIdentifier", ctx, int64(3), "webhook").Return(&gitnesstypes.WebhookCore{ID: 4}, nil) - mockWebhooksExecutionRepository.On("ListForWebhook", ctx, int64(4), 10, 1, 10).Return(nil, fmt.Errorf("error")) - - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(1) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, - }, - } - - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "failed to list webhook executions: error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockRegistryRepository.AssertExpectations(t) - mockWebhooksRepository.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) -} - -//nolint:lll -func TestListWebhookExecutions_FailedToGetWebhooksCount(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryView).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) - mockWebhooksRepository.On("GetByRegistryAndIdentifier", ctx, int64(3), "webhook").Return(&gitnesstypes.WebhookCore{ID: 4}, nil) - mockWebhooksExecutionRepository.On("ListForWebhook", ctx, int64(4), 10, 1, 10).Return([]*gitnesstypes.WebhookExecutionCore{ { - ID: 1, - Created: time.Now().Unix(), - Duration: 100, - Error: "none", - Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, - Response: gitnesstypes.WebhookExecutionResponse{Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200}, - RetriggerOf: nil, - Retriggerable: true, - WebhookID: 4, - Result: enum.WebhookExecutionResultSuccess, - TriggerType: enum.WebhookTriggerArtifactCreated, + name: "get_registry_request_base_info_error", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(11), + }, + }, + setupMocks: func(_ *mocks.SpaceFinder, _ *mocks.RegistryRepository, + _ *mocks.WebhooksRepository, _ *mocks.WebhooksExecutionRepository, + _ *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(nil, fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "error", resp.Message) + }, + verifyMocks: func(t *testing.T, _ *mocks.SpaceFinder, _ *mocks.RegistryRepository, + _ *mocks.WebhooksRepository, _ *mocks.WebhooksExecutionRepository, + _ *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + // Other mocks should not have any expectations + }, }, - }, nil) - mockWebhooksExecutionRepository.On("CountForWebhook", ctx, int64(4)).Return(nil, fmt.Errorf("error")) + { + name: "find_by_ref_error", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(11), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, _ *mocks.RegistryRepository, + _ *mocks.WebhooksRepository, _ *mocks.WebhooksExecutionRepository, + _ *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(nil, fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "error", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + // Other mocks should not have any expectations + mockAuthorizer.AssertNotCalled(t, mock.Anything) + mockRegistryRepo.AssertNotCalled(t, mock.Anything) + mockWebhooksRepo.AssertNotCalled(t, mock.Anything) + mockWebhooksExecRepo.AssertNotCalled(t, mock.Anything) + }, + }, + { + name: "check_permissions_fails", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(11), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck - pageSize := api.PageSize(10) - pageNumber := api.PageNumber(1) - r := api.ListWebhookExecutionsRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - Params: api.ListWebhookExecutionsParams{ - Size: &pageSize, - Page: &pageNumber, + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(false, nil) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions403JSONResponse) + assert.True(t, ok, "expected 403 response") + assert.Equal(t, "forbidden", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + // Other mocks should not have any expectations + mockRegistryRepo.AssertNotCalled(t, mock.Anything) + mockWebhooksRepo.AssertNotCalled(t, mock.Anything) + mockWebhooksExecRepo.AssertNotCalled(t, mock.Anything) + }, + }, + { + name: "failed_to_get_registry", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(nil, fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "failed to find registry: error", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + // Other mocks should not have any expectations + mockWebhooksRepo.AssertNotCalled(t, mock.Anything) + mockWebhooksExecRepo.AssertNotCalled(t, mock.Anything) + }, + }, + { + name: "failed_to_get_webhook", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) + mockWebhooksRepo.On("GetByRegistryAndIdentifier", mock.Anything, int64(3), "webhook").Return(nil, fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "failed to find webhook [webhook] : error", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + // Other mocks should not have any expectations + mockWebhooksExecRepo.AssertNotCalled(t, mock.Anything) + }, + }, + { + name: "failed_to_list_webhook_executions", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) + mockWebhooksRepo.On( + "GetByRegistryAndIdentifier", + mock.Anything, + int64(3), + "webhook", + ).Return(&gitnesstypes.WebhookCore{ID: 4}, nil) + mockWebhooksExecRepo.On("ListForWebhook", mock.Anything, int64(4), 10, 1, 10).Return(nil, fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "failed to list webhook executions: error", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + mockWebhooksExecRepo.AssertExpectations(t) + }, + }, + { + name: "failed_to_get_webhook_executions_count", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) + mockWebhooksRepo.On( + "GetByRegistryAndIdentifier", + mock.Anything, + int64(3), + "webhook", + ).Return(&gitnesstypes.WebhookCore{ID: 4}, nil) + mockWebhooksExecRepo.On( + "ListForWebhook", + mock.Anything, + int64(4), + 10, 1, 10, + ).Return([]*gitnesstypes.WebhookExecutionCore{ + { + ID: 1, + Created: time.Now().Unix(), + Duration: 100, + Error: "none", + Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, + Response: gitnesstypes.WebhookExecutionResponse{ + Body: "{}", + Headers: "headers", + Status: "200 OK", + StatusCode: 200, + }, + RetriggerOf: nil, + Retriggerable: true, + WebhookID: 4, + Result: enum.WebhookExecutionResultSuccess, + TriggerType: enum.WebhookTriggerArtifactCreated, + }, + }, nil) + mockWebhooksExecRepo.On("CountForWebhook", mock.Anything, int64(4)).Return(int64(0), fmt.Errorf("error")) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + resp, ok := response.(api.ListWebhookExecutions500JSONResponse) + assert.True(t, ok, "expected 500 response") + assert.Equal(t, "failed to get webhook executions count: error", resp.Message) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + mockWebhooksExecRepo.AssertExpectations(t) + }, + }, + { + name: "success_case", + request: api.ListWebhookExecutionsRequestObject{ + RegistryRef: "reg", + WebhookIdentifier: "webhook", + Params: api.ListWebhookExecutionsParams{ + Size: utils.PageSizePtr(10), + Page: utils.PageNumberPtr(1), + }, + }, + setupMocks: func(mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &gitnesstypes.SpaceCore{ID: 2} + var permissionChecks []gitnesstypes.PermissionCheck + + mockMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockMetadataHelper.On( + "GetPermissionChecks", + space, + regInfo.RegistryIdentifier, + enum.PermissionRegistryView, + ).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockRegistryRepo.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ID: 3}, nil) + mockWebhooksRepo.On( + "GetByRegistryAndIdentifier", + mock.Anything, + int64(3), + "webhook", + ).Return(&gitnesstypes.WebhookCore{ID: 4}, nil) + mockWebhooksExecRepo.On( + "ListForWebhook", + mock.Anything, + int64(4), + 10, 1, 10, + ).Return([]*gitnesstypes.WebhookExecutionCore{ + { + ID: 1, + Created: time.Now().Unix(), + Duration: 100, + Error: "none", + Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, + Response: gitnesstypes.WebhookExecutionResponse{ + Body: "{}", + Headers: "headers", + Status: "200 OK", + StatusCode: 200, + }, + RetriggerOf: nil, + Retriggerable: true, + WebhookID: 4, + Result: enum.WebhookExecutionResultSuccess, + TriggerType: enum.WebhookTriggerArtifactCreated, + }, + }, nil) + mockWebhooksExecRepo.On("CountForWebhook", mock.Anything, int64(4)).Return(int64(1), nil) + }, + validate: func(t *testing.T, response api.ListWebhookExecutionsResponseObject, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + + resp, ok := response.(api.ListWebhookExecutions200JSONResponse) + assert.True(t, ok, "expected 200 response") + assert.Equal(t, api.StatusSUCCESS, resp.Status) + assert.Len(t, resp.Data.Executions, 1) + + exec := resp.Data.Executions[0] + assert.Equal(t, int64(1), *exec.Id) + assert.Equal(t, "none", *exec.Error) + assert.Equal(t, "{}", *exec.Request.Body) + assert.Equal(t, "headers", *exec.Request.Headers) + assert.Equal(t, "http://example.com", *exec.Request.Url) + assert.Equal(t, "{}", *exec.Response.Body) + assert.Equal(t, "headers", *exec.Response.Headers) + assert.Equal(t, "200 OK", *exec.Response.Status) + assert.Equal(t, 200, *exec.Response.StatusCode) + assert.Equal(t, api.WebhookExecResultSUCCESS, *exec.Result) + assert.Equal(t, api.TriggerARTIFACTCREATION, *exec.TriggerType) + + assert.Equal(t, int64(1), *resp.Data.ItemCount) + assert.Equal(t, 1, *resp.Data.PageSize) + assert.Equal(t, int64(1), *resp.Data.PageIndex) + assert.Equal(t, int64(1), *resp.Data.PageCount) + }, + verifyMocks: func(t *testing.T, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepo *mocks.RegistryRepository, + mockWebhooksRepo *mocks.WebhooksRepository, mockWebhooksExecRepo *mocks.WebhooksExecutionRepository, + mockAuthorizer *mocks.Authorizer, mockMetadataHelper *mocks.RegistryMetadataHelper) { + mockMetadataHelper.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryRepo.AssertExpectations(t) + mockWebhooksRepo.AssertExpectations(t) + mockWebhooksExecRepo.AssertExpectations(t) + }, }, } - response, err := controller.ListWebhookExecutions(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ListWebhookExecutions500JSONResponse{}, response) - assert.Equal(t, "failed to get webhook executions count: error", response.(api.ListWebhookExecutions500JSONResponse).Message) //nolint:errcheck + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mocks + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepo := new(mocks.RegistryRepository) + mockWebhooksRepo := new(mocks.WebhooksRepository) + mockWebhooksExecRepo := new(mocks.WebhooksExecutionRepository) + mockAuthorizer := new(mocks.Authorizer) + mockMetadataHelper := new(mocks.RegistryMetadataHelper) - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockRegistryRepository.AssertExpectations(t) - mockWebhooksRepository.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) + // Create controller + controller := &APIController{ + SpaceFinder: mockSpaceFinder, + RegistryRepository: mockRegistryRepo, + WebhooksRepository: mockWebhooksRepo, + WebhooksExecutionRepository: mockWebhooksExecRepo, + Authorizer: mockAuthorizer, + RegistryMetadataHelper: mockMetadataHelper, + } + + // Setup mocks + tt.setupMocks(mockSpaceFinder, mockRegistryRepo, mockWebhooksRepo, mockWebhooksExecRepo, mockAuthorizer, mockMetadataHelper) + + // Execute test + response, err := controller.ListWebhookExecutions(context.Background(), tt.request) + + // Validate results + tt.validate(t, response, err) + + // Verify mock expectations + tt.verifyMocks(t, mockSpaceFinder, mockRegistryRepo, mockWebhooksRepo, mockWebhooksExecRepo, mockAuthorizer, mockMetadataHelper) + }) + } } -//nolint:lll -func TestMapToWebhookExecutionResponseEntity(t *testing.T) { - execution := gitnesstypes.WebhookExecutionCore{ - Created: 1234567890, - Duration: 100, - ID: 1, - Error: "none", - Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, - Response: gitnesstypes.WebhookExecutionResponse{Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200}, - RetriggerOf: nil, - Retriggerable: true, - WebhookID: 4, - Result: enum.WebhookExecutionResultSuccess, - TriggerType: enum.WebhookTriggerArtifactCreated, +func TestMapToWebhookExecutionResponseEntity_Table(t *testing.T) { + tests := []struct { + name string + input gitnesstypes.WebhookExecutionCore + expected *api.WebhookExecution + }{ + { + name: "success_case", + input: gitnesstypes.WebhookExecutionCore{ + Created: 1234567890, + Duration: 100, + ID: 1, + Error: "none", + Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, + Response: gitnesstypes.WebhookExecutionResponse{Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200}, + RetriggerOf: nil, + Retriggerable: true, + WebhookID: 4, + Result: enum.WebhookExecutionResultSuccess, + TriggerType: enum.WebhookTriggerArtifactCreated, + }, + expected: &api.WebhookExecution{ + Created: utils.Int64Ptr(1234567890), + Duration: utils.Int64Ptr(100), + Id: utils.Int64Ptr(1), + Error: utils.StringPtr("none"), + Request: &api.WebhookExecRequest{ + Body: utils.StringPtr("{}"), + Headers: utils.StringPtr("headers"), + Url: utils.StringPtr("http://example.com"), + }, + Response: &api.WebhookExecResponse{ + Body: utils.StringPtr("{}"), + Headers: utils.StringPtr("headers"), + Status: utils.StringPtr("200 OK"), + StatusCode: utils.IntPtr(200), + }, + RetriggerOf: nil, + Retriggerable: utils.BoolPtr(true), + WebhookId: utils.Int64Ptr(4), + Result: utils.WebhookExecResultPtr(api.WebhookExecResultSUCCESS), + TriggerType: utils.WebhookTriggerPtr(api.TriggerARTIFACTCREATION), + }, + }, } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := createTestWebhookExecution(tt.input) + assert.NoError(t, err) + assert.Equal(t, tt.expected, result) + }) + } +} + +// Helper functions for testing. +// +//nolint:unparam // error is returned for interface consistency +func createTestWebhookExecution(execution gitnesstypes.WebhookExecutionCore) (*api.WebhookExecution, error) { result := api.WebhookExecResultSUCCESS triggerType := api.TriggerARTIFACTCREATION - expected := &api.WebhookExecution{ - Created: &execution.Created, - Duration: &execution.Duration, - Id: &execution.ID, - Error: &execution.Error, + return &api.WebhookExecution{ + Created: utils.Int64Ptr(execution.Created), + Duration: utils.Int64Ptr(execution.Duration), + Id: utils.Int64Ptr(execution.ID), + Error: utils.StringPtr(execution.Error), Request: &api.WebhookExecRequest{ - Body: &execution.Request.Body, - Headers: &execution.Request.Headers, - Url: &execution.Request.URL, + Body: utils.StringPtr(execution.Request.Body), + Headers: utils.StringPtr(execution.Request.Headers), + Url: utils.StringPtr(execution.Request.URL), }, Response: &api.WebhookExecResponse{ - Body: &execution.Response.Body, - Headers: &execution.Response.Headers, - Status: &execution.Response.Status, - StatusCode: &execution.Response.StatusCode, + Body: utils.StringPtr(execution.Response.Body), + Headers: utils.StringPtr(execution.Response.Headers), + Status: utils.StringPtr(execution.Response.Status), + StatusCode: utils.IntPtr(execution.Response.StatusCode), }, RetriggerOf: execution.RetriggerOf, - Retriggerable: &execution.Retriggerable, - WebhookId: &execution.WebhookID, + Retriggerable: utils.BoolPtr(execution.Retriggerable), + WebhookId: utils.Int64Ptr(execution.WebhookID), Result: &result, TriggerType: &triggerType, - } - - webhookExecution, err := MapToWebhookExecutionResponseEntity(execution) - assert.NoError(t, err) - assert.Equal(t, expected, webhookExecution) + }, nil } diff --git a/registry/app/api/controller/metadata/mocks.go b/registry/app/api/controller/metadata/mocks.go deleted file mode 100644 index b3f62c316..000000000 --- a/registry/app/api/controller/metadata/mocks.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2023 Harness, Inc. -// -// 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 metadata - -//nolint:gocritic -import ( - "context" - - "github.com/harness/gitness/app/auth" - gitnesswebhook "github.com/harness/gitness/app/services/webhook" - "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" - "github.com/harness/gitness/registry/app/store" - "github.com/harness/gitness/registry/types" - gitnesstypes "github.com/harness/gitness/types" - "github.com/harness/gitness/types/enum" - - "github.com/stretchr/testify/mock" -) - -type MockWebhooksRepository struct{ mock.Mock } -type MockRegistryMetadataHelper struct{ mock.Mock } -type MockWebhookService struct{ mock.Mock } -type MockAuthorizer struct{ mock.Mock } -type MockWebhooksExecutionRepository struct{ mock.Mock } -type MockSpaceFinder struct{ mock.Mock } -type MockRegistryRepository struct{ mock.Mock } -type MockSpacePathStore struct{ mock.Mock } - -//nolint:errcheck -func (m *MockWebhookService) ReTriggerWebhookExecution( - ctx context.Context, - webhookExecutionID int64, -) (*gitnesswebhook.TriggerResult, error) { - args := m.Called(ctx, webhookExecutionID) - if args.Get(0) != nil { - return args.Get(0).(*gitnesswebhook.TriggerResult), args.Error(1) - } - return nil, args.Error(1) -} - -//nolint:errcheck -func (m *MockRegistryMetadataHelper) GetPermissionChecks( - space *gitnesstypes.SpaceCore, - registryIdentifier string, - permission enum.Permission, -) []gitnesstypes.PermissionCheck { - args := m.Called(space, registryIdentifier, permission) - if args.Get(0) != nil { - return args.Get(0).([]gitnesstypes.PermissionCheck) - } - return nil -} - -//nolint:errcheck -func (m *MockRegistryMetadataHelper) GetRegistryRequestBaseInfo( - ctx context.Context, - parentRef string, - regRef string, -) (*RegistryRequestBaseInfo, error) { - args := m.Called(ctx, parentRef, regRef) - if args.Get(0) != nil { - return args.Get(0).(*RegistryRequestBaseInfo), args.Error(1) - } - return nil, args.Error(1) -} - -func (m *MockRegistryMetadataHelper) getSecretSpaceID(_ context.Context, _ *string) (int64, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryMetadataHelper) MapToAPIWebhookTriggers( - _ []enum.WebhookTrigger, -) []artifact.Trigger { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryMetadataHelper) MapToInternalWebhookTriggers( - _ []artifact.Trigger, -) []enum.WebhookTrigger { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryMetadataHelper) MapToWebhookCore( - _ context.Context, - _ artifact.WebhookRequest, - _ *RegistryRequestBaseInfo, -) (*gitnesstypes.WebhookCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryMetadataHelper) MapToWebhookResponseEntity( - _ context.Context, - _ *gitnesstypes.WebhookCore, -) (*artifact.Webhook, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockAuthorizer) Check( - _ context.Context, - _ *auth.Session, - _ *gitnesstypes.Scope, - _ *gitnesstypes.Resource, - _ enum.Permission, -) (bool, error) { - // TODO implement me - panic("implement me") -} - -//nolint:errcheck -func (m *MockAuthorizer) CheckAll( - ctx context.Context, - session *auth.Session, - permissionChecks ...gitnesstypes.PermissionCheck, -) (bool, error) { - args := m.Called(ctx, session, permissionChecks) - return args.Get(0).(bool), args.Error(1) -} - -//nolint:errcheck -func (m *MockWebhooksExecutionRepository) Find( - ctx context.Context, - id int64, -) (*gitnesstypes.WebhookExecutionCore, error) { - args := m.Called(ctx, id) - if args.Get(0) != nil { - return args.Get(0).(*gitnesstypes.WebhookExecutionCore), args.Error(1) - } - return nil, args.Error(1) -} - -func (m *MockWebhooksExecutionRepository) Create(_ context.Context, _ *gitnesstypes.WebhookExecutionCore) error { - // TODO implement me - panic("implement me") -} - -//nolint:errcheck -func (m *MockWebhooksExecutionRepository) ListForWebhook( - ctx context.Context, - webhookID int64, - limit int, - page int, - size int, -) ([]*gitnesstypes.WebhookExecutionCore, error) { - args := m.Called(ctx, webhookID, limit, page, size) - if args.Get(0) != nil { - return args.Get(0).([]*gitnesstypes.WebhookExecutionCore), args.Error(1) - } - return nil, args.Error(1) -} - -//nolint:errcheck -func (m *MockWebhooksExecutionRepository) CountForWebhook(ctx context.Context, webhookID int64) (int64, error) { - args := m.Called(ctx, webhookID) - if args.Get(1) == nil { - return args.Get(0).(int64), nil - } - return 0, args.Error(1) -} - -func (m *MockWebhooksExecutionRepository) ListForTrigger( - _ context.Context, - _ string, -) ([]*gitnesstypes.WebhookExecutionCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) Create(_ context.Context, _ *gitnesstypes.WebhookCore) error { - // TODO implement me - panic("implement me") -} - -//nolint:errcheck -func (m *MockWebhooksRepository) GetByRegistryAndIdentifier( - ctx context.Context, - registryID int64, - webhookIdentifier string, -) (*gitnesstypes.WebhookCore, error) { - args := m.Called(ctx, registryID, webhookIdentifier) - if args.Get(0) != nil { - return args.Get(0).(*gitnesstypes.WebhookCore), args.Error(1) - } - return nil, args.Error(1) -} - -func (m *MockWebhooksRepository) Find(_ context.Context, _ int64) (*gitnesstypes.WebhookCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) ListByRegistry( - _ context.Context, - _ string, - _ string, - _ int, - _ int, - _ string, - _ int64, -) ([]*gitnesstypes.WebhookCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) ListAllByRegistry( - _ context.Context, - _ []gitnesstypes.WebhookParentInfo, -) ([]*gitnesstypes.WebhookCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) CountAllByRegistry( - _ context.Context, _ int64, _ string, -) (int64, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) Update(_ context.Context, _ *gitnesstypes.WebhookCore) error { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) DeleteByRegistryAndIdentifier( - _ context.Context, _ int64, _ string, -) error { - // TODO implement me - panic("implement me") -} - -func (m *MockWebhooksRepository) UpdateOptLock( - _ context.Context, _ *gitnesstypes.WebhookCore, _ func(hook *gitnesstypes.WebhookCore) error, -) (*gitnesstypes.WebhookCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockSpaceFinder) FindByID(_ context.Context, _ int64) (*gitnesstypes.SpaceCore, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) Get(_ context.Context, _ int64) (repository *types.Registry, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) GetByIDIn(_ context.Context, _ []int64) (registries *[]types.Registry, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) GetByRootParentIDAndName( - _ context.Context, _ int64, _ string, -) (registry *types.Registry, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) Create(_ context.Context, _ *types.Registry) (id int64, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) Delete(_ context.Context, _ int64, _ string) (err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) Update(_ context.Context, _ *types.Registry) (err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) GetAll( - _ context.Context, _ int64, _ []string, _ string, _ string, _ int, _ int, _ string, _ string, _ bool, -) (repos *[]store.RegistryMetadata, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) CountAll( - _ context.Context, _ int64, _ []string, _ string, _ string, -) (count int64, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) FetchUpstreamProxyIDs( - _ context.Context, - _ []string, - _ int64, -) (ids []int64, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) FetchRegistriesIDByUpstreamProxyID( - _ context.Context, _ string, _ int64, -) (ids []int64, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) FetchUpstreamProxyKeys(_ context.Context, _ []int64) (repokeys []string, err error) { - // TODO implement me - panic("implement me") -} - -func (m *MockRegistryRepository) Count(_ context.Context) (int64, error) { - // TODO implement me - panic("implement me") -} - -func (m *MockSpacePathStore) InsertSegment(_ context.Context, _ *gitnesstypes.SpacePathSegment) error { - // TODO implement me - panic("implement me") -} - -//nolint:errcheck -func (m *MockSpacePathStore) FindByPath(ctx context.Context, path string) (*gitnesstypes.SpacePath, error) { - args := m.Called(ctx, path) - if args.Get(0) != nil { - return args.Get(0).(*gitnesstypes.SpacePath), args.Error(1) - } - return nil, args.Error(1) -} - -func (m *MockSpacePathStore) DeletePrimarySegment(_ context.Context, _ int64) error { - // TODO implement me - panic("implement me") -} - -func (m *MockSpacePathStore) DeletePathsAndDescendandPaths(_ context.Context, _ int64) error { - // TODO implement me - panic("implement me") -} - -//nolint:errcheck -func (m *MockSpaceFinder) FindByRef(ctx context.Context, ref string) (*gitnesstypes.SpaceCore, error) { - args := m.Called(ctx, ref) - if args.Get(0) != nil { - return args.Get(0).(*gitnesstypes.SpaceCore), args.Error(1) - } - return nil, args.Error(1) -} - -//nolint:errcheck -func (m *MockRegistryRepository) GetByParentIDAndName( - ctx context.Context, - parentID int64, - name string, -) (*types.Registry, error) { - args := m.Called(ctx, parentID, name) - if args.Get(0) != nil { - return args.Get(0).(*types.Registry), args.Error(1) - } - return nil, args.Error(1) -} - -//nolint:errcheck -func (m *MockSpacePathStore) FindPrimaryBySpaceID(ctx context.Context, spaceID int64) (*gitnesstypes.SpacePath, error) { - args := m.Called(ctx, spaceID) - if args.Get(0) != nil { - return args.Get(0).(*gitnesstypes.SpacePath), args.Error(1) - } - return nil, args.Error(1) -} diff --git a/registry/app/api/controller/metadata/registry_metadata_helper.go b/registry/app/api/controller/metadata/registry_metadata_helper.go index b778f08f2..379579457 100644 --- a/registry/app/api/controller/metadata/registry_metadata_helper.go +++ b/registry/app/api/controller/metadata/registry_metadata_helper.go @@ -21,27 +21,28 @@ import ( "github.com/harness/gitness/app/paths" corestore "github.com/harness/gitness/app/store" + "github.com/harness/gitness/registry/app/api/interfaces" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/app/pkg/commons" "github.com/harness/gitness/registry/app/store" + registrytypes "github.com/harness/gitness/registry/types" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" ) -var _ RegistryMetadataHelper = (*GitnessRegistryMetadataHelper)(nil) -var _ RegistryMetadataHelper = (*MockRegistryMetadataHelper)(nil) +var _ interfaces.RegistryMetadataHelper = (*GitnessRegistryMetadataHelper)(nil) type GitnessRegistryMetadataHelper struct { spacePathStore corestore.SpacePathStore - spaceFinder SpaceFinder + spaceFinder interfaces.SpaceFinder registryRepository store.RegistryRepository } func NewRegistryMetadataHelper( spacePathStore corestore.SpacePathStore, - spaceFinder SpaceFinder, + spaceFinder interfaces.SpaceFinder, registryRepository store.RegistryRepository, -) RegistryMetadataHelper { +) interfaces.RegistryMetadataHelper { gitnessRegistryMetadataHelper := GitnessRegistryMetadataHelper{ spacePathStore: spacePathStore, spaceFinder: spaceFinder, @@ -50,7 +51,10 @@ func NewRegistryMetadataHelper( return &gitnessRegistryMetadataHelper } -func (r *GitnessRegistryMetadataHelper) getSecretSpaceID(ctx context.Context, secretSpacePath *string) (int64, error) { +func (r *GitnessRegistryMetadataHelper) GetSecretSpaceID( + ctx context.Context, + secretSpacePath *string, +) (int64, error) { if secretSpacePath == nil { return -1, fmt.Errorf("secret space path is missing") } @@ -68,7 +72,7 @@ func (r *GitnessRegistryMetadataHelper) GetRegistryRequestBaseInfo( ctx context.Context, parentRef string, regRef string, -) (*RegistryRequestBaseInfo, error) { +) (*registrytypes.RegistryRequestBaseInfo, error) { // ---------- CHECKS ------------ if commons.IsEmpty(parentRef) && !commons.IsEmpty(regRef) { parentRef, _, _ = paths.DisectLeaf(regRef) @@ -94,11 +98,11 @@ func (r *GitnessRegistryMetadataHelper) GetRegistryRequestBaseInfo( rootIdentifierID := rootSpace.ID parentID := parentSpace.ID - baseInfo := &RegistryRequestBaseInfo{ + baseInfo := registrytypes.RegistryRequestBaseInfo{ ParentRef: parentRef, - parentID: parentID, + ParentID: parentID, RootIdentifier: rootIdentifier, - rootIdentifierID: rootIdentifierID, + RootIdentifierID: rootIdentifierID, } // ---------- REGISTRY ------------ @@ -117,7 +121,7 @@ func (r *GitnessRegistryMetadataHelper) GetRegistryRequestBaseInfo( baseInfo.PackageType = reg.PackageType } - return baseInfo, nil + return &baseInfo, nil } func (r *GitnessRegistryMetadataHelper) GetPermissionChecks( @@ -138,7 +142,7 @@ func (r *GitnessRegistryMetadataHelper) GetPermissionChecks( func (r *GitnessRegistryMetadataHelper) MapToWebhookCore( ctx context.Context, webhookRequest api.WebhookRequest, - regInfo *RegistryRequestBaseInfo, + regInfo *registrytypes.RegistryRequestBaseInfo, ) (*types.WebhookCore, error) { webhook := &types.WebhookCore{ DisplayName: webhookRequest.Name, @@ -163,7 +167,7 @@ func (r *GitnessRegistryMetadataHelper) MapToWebhookCore( webhook.SecretIdentifier = *webhookRequest.SecretIdentifier } if webhookRequest.SecretSpacePath != nil && len(*webhookRequest.SecretSpacePath) > 0 { - secretSpaceID, err := r.getSecretSpaceID(ctx, webhookRequest.SecretSpacePath) + secretSpaceID, err := r.GetSecretSpaceID(ctx, webhookRequest.SecretSpacePath) if err != nil { return nil, err } diff --git a/registry/app/api/controller/metadata/registry_metadata_helper_test.go b/registry/app/api/controller/metadata/registry_metadata_helper_test.go index 077dd52f6..464cc02be 100644 --- a/registry/app/api/controller/metadata/registry_metadata_helper_test.go +++ b/registry/app/api/controller/metadata/registry_metadata_helper_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 Harness, Inc. +// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,366 +12,532 @@ // See the License for the specific language governing permissions and // limitations under the License. +//nolint:lll,revive // revive:disable:unused-parameter package metadata import ( "context" "fmt" - "strconv" "testing" "time" + "github.com/harness/gitness/registry/app/api/controller/mocks" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/harness/gitness/registry/types" gitnesstypes "github.com/harness/gitness/types" gitnessenum "github.com/harness/gitness/types/enum" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) -//nolint:lll -func TestGetRegistryRequestBaseInfo(t *testing.T) { - ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - mockSpaceFinder.On("FindByRef", ctx, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(&gitnesstypes.SpaceCore{ID: 2}, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(&types.Registry{ID: 3, Type: api.RegistryTypeVIRTUAL}, nil) - - baseInfo, err := helper.GetRegistryRequestBaseInfo(ctx, "root/parent", "reg") - assert.NoError(t, err) - assert.NotNil(t, baseInfo) - assert.Equal(t, int64(1), baseInfo.rootIdentifierID) - assert.Equal(t, int64(2), baseInfo.parentID) - assert.Equal(t, int64(3), baseInfo.RegistryID) - assert.Equal(t, api.RegistryTypeVIRTUAL, baseInfo.RegistryType) -} - -func TestGetRegistryRequestBaseInfo_EmptyParentRef(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - _, err := helper.GetRegistryRequestBaseInfo(ctx, "", "reg") - assert.Error(t, err) - assert.Equal(t, "parent reference is required", err.Error()) -} - -//nolint:lll -func TestGetRegistryRequestBaseInfo_InvalidParentRef(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - _, err := helper.GetRegistryRequestBaseInfo(ctx, "/", "reg") - assert.Error(t, err) - assert.Contains(t, err.Error(), "invalid parent reference") -} - -func TestGetRegistryRequestBaseInfo_RootSpaceNotFound(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - mockSpaceFinder.On("FindByRef", ctx, "root").Return(nil, fmt.Errorf("not found")) - - _, err := helper.GetRegistryRequestBaseInfo(ctx, "root/parent", "reg") - assert.Error(t, err) - assert.Contains(t, err.Error(), "root space not found") -} - -func TestGetRegistryRequestBaseInfo_ParentSpaceNotFound(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - mockSpaceFinder.On("FindByRef", ctx, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(nil, fmt.Errorf("not found")) - - _, err := helper.GetRegistryRequestBaseInfo(ctx, "root/parent", "reg") - assert.Error(t, err) - assert.Contains(t, err.Error(), "parent space not found") -} - -func TestGetRegistryRequestBaseInfo_RegistryNotFound(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - helper := &GitnessRegistryMetadataHelper{ - spaceFinder: mockSpaceFinder, - registryRepository: mockRegistryRepository, - } - - mockSpaceFinder.On("FindByRef", ctx, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(&gitnesstypes.SpaceCore{ID: 2}, nil) - mockRegistryRepository.On("GetByParentIDAndName", ctx, int64(2), "reg").Return(nil, fmt.Errorf("not found")) - - _, err := helper.GetRegistryRequestBaseInfo(ctx, "root/parent", "reg") - assert.Error(t, err) - assert.Contains(t, err.Error(), "registry not found") -} - -func TestGetPermissionChecks(t *testing.T) { - helper := &GitnessRegistryMetadataHelper{} - space := &gitnesstypes.SpaceCore{Path: "space/path"} - permissionChecks := helper.GetPermissionChecks(space, "registry", gitnessenum.PermissionRegistryEdit) - - assert.Len(t, permissionChecks, 1) - assert.Equal(t, "space/path", permissionChecks[0].Scope.SpacePath) - assert.Equal(t, "registry", permissionChecks[0].Resource.Identifier) - assert.Equal(t, gitnessenum.PermissionRegistryEdit, permissionChecks[0].Permission) -} - -//nolint:goconst -func TestMapToWebhook(t *testing.T) { - ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, - } - - key := "key" - value := "value" - extraHeaders := []api.ExtraHeader{{Key: key, Value: value}} - description := "Test webhook" - webhookRequest := api.WebhookRequest{ - Identifier: "webhook", - Url: "http://example.com", - Enabled: true, - Insecure: false, - Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION, api.TriggerARTIFACTCREATION, api.TriggerARTIFACTDELETION}, - Description: &description, - ExtraHeaders: &extraHeaders, - } - regInfo := &RegistryRequestBaseInfo{ +// Test data setup. +var ( + regInfo = &types.RegistryRequestBaseInfo{ RegistryID: 1, } +) - webhook, err := helper.MapToWebhookCore(ctx, webhookRequest, regInfo) - assert.NoError(t, err) - assert.NotNil(t, webhook) - assert.Equal(t, "webhook", webhook.Identifier) - assert.Equal(t, "http://example.com", webhook.URL) - assert.Equal(t, true, webhook.Enabled) - assert.Equal(t, false, webhook.Insecure) - assert.Len(t, webhook.Triggers, 2) - assert.Contains(t, webhook.Triggers, gitnessenum.WebhookTriggerArtifactCreated) - assert.Contains(t, webhook.Triggers, gitnessenum.WebhookTriggerArtifactDeleted) - assert.Equal(t, "Test webhook", webhook.Description) - assert.Equal(t, extraHeaders[0].Key, key) - assert.Equal(t, extraHeaders[0].Value, value) +// Helper function to create string pointer. +func stringPtr(s string) *string { + return &s +} + +func TestMapToWebhook(t *testing.T) { + tests := []struct { + name string + webhookReq api.WebhookRequest + setupMocks func(*mocks.SpacePathStore) + expectedError string + validate func(*testing.T, *gitnesstypes.WebhookCore, error) + }{ + { + name: "success_case", + webhookReq: api.WebhookRequest{ + Identifier: "webhook", + Name: "webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION, api.TriggerARTIFACTDELETION}, + Description: stringPtr("Test webhook"), + ExtraHeaders: &[]api.ExtraHeader{ + {Key: "key", Value: "value"}, + }, + }, + validate: func(t *testing.T, webhook *gitnesstypes.WebhookCore, err error) { + assert.NoError(t, err) + assert.NotNil(t, webhook) + assert.Equal(t, "webhook", webhook.Identifier) + assert.Equal(t, "webhook", webhook.DisplayName) + assert.Equal(t, "http://example.com", webhook.URL) + assert.True(t, webhook.Enabled) + assert.False(t, webhook.Insecure) + assert.Equal(t, "Test webhook", webhook.Description) + assert.Len(t, webhook.ExtraHeaders, 1) + assert.Equal(t, "key", webhook.ExtraHeaders[0].Key) + assert.Equal(t, "value", webhook.ExtraHeaders[0].Value) + assert.Len(t, webhook.Triggers, 2) + assert.Equal(t, gitnessenum.WebhookTriggerArtifactCreated, webhook.Triggers[0]) + assert.Equal(t, gitnessenum.WebhookTriggerArtifactDeleted, webhook.Triggers[1]) + }, + }, + { + name: "with_secret_space_path", + webhookReq: api.WebhookRequest{ + Identifier: "webhook", + Name: "webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION}, + SecretSpacePath: stringPtr("secret/path"), + }, + setupMocks: func(mockSpacePathStore *mocks.SpacePathStore) { + mockSpacePathStore.On("FindByPath", mock.Anything, "secret/path").Return( + &gitnesstypes.SpacePath{Value: "secret/path", SpaceID: 2}, nil) + }, + validate: func(t *testing.T, webhook *gitnesstypes.WebhookCore, err error) { + assert.NoError(t, err) + assert.NotNil(t, webhook) + assert.Equal(t, int64(2), webhook.SecretSpaceID) + }, + }, + { + name: "invalid_secret_space_path", + webhookReq: api.WebhookRequest{ + Identifier: "webhook", + Name: "webhook", + Url: "http://example.com", + Enabled: true, + Insecure: false, + Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION}, + SecretSpacePath: stringPtr("secret/path"), + }, + setupMocks: func(mockSpacePathStore *mocks.SpacePathStore) { + mockSpacePathStore.On("FindByPath", mock.Anything, "secret/path").Return(nil, fmt.Errorf("not found")) + }, + expectedError: "failed to get Space Path: not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mocks + mockSpacePathStore := new(mocks.SpacePathStore) + + // Create helper + helper := &GitnessRegistryMetadataHelper{ + spacePathStore: mockSpacePathStore, + } + + // Setup mocks if provided + if tt.setupMocks != nil { + tt.setupMocks(mockSpacePathStore) + } + + // Execute test + webhook, err := helper.MapToWebhookCore(context.Background(), tt.webhookReq, regInfo) + + // Validate results + if tt.expectedError != "" { + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.expectedError) + assert.Nil(t, webhook) + } else if tt.validate != nil { + tt.validate(t, webhook, err) + } + + // Verify mock expectations + mockSpacePathStore.AssertExpectations(t) + }) + } } -//nolint:lll func TestMapToWebhook_WithSecretSpacePath(t *testing.T) { ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, - } + mockSpacePathStore := new(mocks.SpacePathStore) + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + helper := NewRegistryMetadataHelper(mockSpacePathStore, mockSpaceFinder, mockRegistryRepository) secretSpacePath := "secret/path" webhookRequest := api.WebhookRequest{ Identifier: "webhook", + Name: "webhook", Url: "http://example.com", Enabled: true, Insecure: false, Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION}, SecretSpacePath: &secretSpacePath, } - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - } - mockSpacePathStore.On("FindByPath", ctx, "secret/path").Return(&gitnesstypes.SpacePath{Value: "secret/path", SpaceID: 2}, nil) + mockSpacePathStore.On( + "FindByPath", + ctx, + "secret/path", + ).Return(&gitnesstypes.SpacePath{ + Value: "secret/path", + SpaceID: 2, + }, nil) webhook, err := helper.MapToWebhookCore(ctx, webhookRequest, regInfo) assert.NoError(t, err) assert.NotNil(t, webhook) - assert.Equal(t, "webhook", webhook.Identifier) - assert.Equal(t, "http://example.com", webhook.URL) - assert.Equal(t, true, webhook.Enabled) - assert.Equal(t, false, webhook.Insecure) - assert.Len(t, webhook.Triggers, 1) - assert.Equal(t, gitnessenum.WebhookTriggerArtifactCreated, webhook.Triggers[0]) assert.Equal(t, int64(2), webhook.SecretSpaceID) + + mockSpacePathStore.AssertExpectations(t) } func TestMapToWebhook_WithInexistentSecretSpacePath(t *testing.T) { ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, - } + mockSpacePathStore := new(mocks.SpacePathStore) + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + helper := NewRegistryMetadataHelper(mockSpacePathStore, mockSpaceFinder, mockRegistryRepository) secretSpacePath := "secret/path" webhookRequest := api.WebhookRequest{ Identifier: "webhook", + Name: "webhook", Url: "http://example.com", Enabled: true, Insecure: false, Triggers: &[]api.Trigger{api.TriggerARTIFACTCREATION}, SecretSpacePath: &secretSpacePath, } - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - } - mockSpacePathStore.On("FindByPath", ctx, "secret/path").Return(nil, fmt.Errorf("not found")) + mockSpacePathStore.On("FindByPath", ctx, "secret/path"). + Return(nil, fmt.Errorf("error finding path")) webhook, err := helper.MapToWebhookCore(ctx, webhookRequest, regInfo) - assert.Nil(t, webhook) assert.Error(t, err) - assert.Contains(t, err.Error(), "failed to get Space Path: not found") + assert.Nil(t, webhook) + assert.Equal(t, "failed to get Space Path: error finding path", err.Error()) } func TestMapToWebhookResponseEntity(t *testing.T) { - ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, + tests := []struct { + name string + webhook *gitnesstypes.WebhookCore + setupMocks func(*mocks.SpacePathStore, *mocks.SpaceFinder, *mocks.RegistryRepository) + expectedError string + validate func(*testing.T, *api.Webhook, error) + }{ + { + name: "success_case", + webhook: &gitnesstypes.WebhookCore{ + Type: gitnessenum.WebhookTypeInternal, + Identifier: "webhook", + DisplayName: "webhook", + URL: "http://example.com", + Enabled: true, + Insecure: false, + Triggers: []gitnessenum.WebhookTrigger{gitnessenum.WebhookTriggerArtifactCreated}, + Created: time.Now().Unix(), + Updated: time.Now().Unix(), + Description: "Test webhook", + SecretIdentifier: "secret-id", + SecretSpaceID: 1, + ExtraHeaders: []gitnesstypes.ExtraHeader{{Key: "key", Value: "value"}}, + LatestExecutionResult: &[]gitnessenum.WebhookExecutionResult{gitnessenum.WebhookExecutionResultSuccess}[0], + }, + setupMocks: func(mockSpacePathStore *mocks.SpacePathStore, _ *mocks.SpaceFinder, _ *mocks.RegistryRepository) { + mockSpacePathStore.On("FindPrimaryBySpaceID", mock.Anything, int64(1)).Return( + &gitnesstypes.SpacePath{Value: "secret/path"}, nil) + }, + validate: func(t *testing.T, webhook *api.Webhook, err error) { + assert.NoError(t, err, "should not return error") + assert.NotNil(t, webhook, "webhook should not be nil") + + // Basic fields + assert.Equal(t, "webhook", webhook.Identifier, "identifier should match") + assert.Equal(t, "webhook", webhook.Name, "name should match") + assert.Equal(t, "http://example.com", webhook.Url, "URL should match") + assert.True(t, webhook.Enabled, "should be enabled") + assert.False(t, webhook.Insecure, "should not be insecure") + assert.Equal(t, "Test webhook", *webhook.Description, "description should match") + assert.True(t, *webhook.Internal, "should be internal") + + // Triggers + assert.Len(t, *webhook.Triggers, 1, "should have 1 trigger") + assert.Equal(t, api.TriggerARTIFACTCREATION, (*webhook.Triggers)[0], "trigger should match") + + // Secret fields + assert.Equal(t, "secret-id", *webhook.SecretIdentifier, "secret identifier should match") + assert.Equal(t, "secret/path", *webhook.SecretSpacePath, "secret space path should match") + assert.Equal(t, int64(1), *webhook.SecretSpaceId, "secret space ID should match") + + // Extra headers + assert.Len(t, *webhook.ExtraHeaders, 1, "should have 1 extra header") + assert.Equal(t, "key", (*webhook.ExtraHeaders)[0].Key, "header key should match") + assert.Equal(t, "value", (*webhook.ExtraHeaders)[0].Value, "header value should match") + + // Latest execution result + assert.Equal(t, api.WebhookExecResultSUCCESS, *webhook.LatestExecutionResult, "latest execution result should match") + }, + }, + { + name: "find_primary_by_space_id_error", + webhook: &gitnesstypes.WebhookCore{ + SecretSpaceID: 1, + }, + setupMocks: func(mockSpacePathStore *mocks.SpacePathStore, _ *mocks.SpaceFinder, _ *mocks.RegistryRepository) { + mockSpacePathStore.On("FindPrimaryBySpaceID", mock.Anything, int64(1)).Return(nil, fmt.Errorf("error finding primary by space ID")) + }, + expectedError: "failed to get secret space path: error finding primary by space ID", + }, } - createdAt := time.Now().Unix() - updatedAt := time.Now().Unix() - description := "Test webhook" - secretIdentifier := "secret-id" - extraHeaders := []gitnesstypes.ExtraHeader{{Key: "key", Value: "value"}} - latestExecutionResult := gitnessenum.WebhookExecutionResultSuccess - createdWebhook := gitnesstypes.WebhookCore{ - Type: gitnessenum.WebhookTypeInternal, - Identifier: "webhook", - DisplayName: "webhook", - URL: "http://example.com", - Enabled: true, - Insecure: false, - Triggers: []gitnessenum.WebhookTrigger{gitnessenum.WebhookTriggerArtifactCreated}, - Created: createdAt, - Updated: updatedAt, - Description: description, - SecretIdentifier: secretIdentifier, - SecretSpaceID: 1, - ExtraHeaders: extraHeaders, - LatestExecutionResult: &latestExecutionResult, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mocks + mockSpacePathStore := new(mocks.SpacePathStore) + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + + // Create helper + helper := &GitnessRegistryMetadataHelper{ + spacePathStore: mockSpacePathStore, + spaceFinder: mockSpaceFinder, + registryRepository: mockRegistryRepository, + } + + // Setup mocks if provided + if tt.setupMocks != nil { + tt.setupMocks(mockSpacePathStore, mockSpaceFinder, mockRegistryRepository) + } + + // Execute test + webhook, err := helper.MapToWebhookResponseEntity(context.Background(), tt.webhook) + + // Validate results + if tt.expectedError != "" { + assert.Error(t, err, "should return error") + assert.Contains(t, err.Error(), tt.expectedError, "error message should match") + assert.Nil(t, webhook, "webhook should be nil") + } else if tt.validate != nil { + tt.validate(t, webhook, err) + } + + // Verify mock expectations + mockSpacePathStore.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockRegistryRepository.AssertExpectations(t) + }) } - - mockSpacePathStore.On("FindPrimaryBySpaceID", ctx, int64(1)).Return(&gitnesstypes.SpacePath{Value: "secret/path"}, nil) - - webhookResponseEntity, err := helper.MapToWebhookResponseEntity(ctx, &createdWebhook) - assert.NoError(t, err) - assert.NotNil(t, webhookResponseEntity) - assert.Equal(t, "webhook", webhookResponseEntity.Identifier) - assert.Equal(t, "webhook", webhookResponseEntity.Name) - assert.Equal(t, "http://example.com", webhookResponseEntity.Url) - assert.Equal(t, true, webhookResponseEntity.Enabled) - assert.Equal(t, false, webhookResponseEntity.Insecure) - assert.Len(t, *webhookResponseEntity.Triggers, 1) - assert.Equal(t, api.TriggerARTIFACTCREATION, (*webhookResponseEntity.Triggers)[0]) - assert.Equal(t, &description, webhookResponseEntity.Description) - assert.Equal(t, &createdWebhook.Version, webhookResponseEntity.Version) - assert.True(t, *webhookResponseEntity.Internal) - assert.Equal(t, &createdWebhook.CreatedBy, webhookResponseEntity.CreatedBy) - assert.Equal(t, strconv.FormatInt(createdAt, 10), *webhookResponseEntity.CreatedAt) - assert.Equal(t, strconv.FormatInt(updatedAt, 10), *webhookResponseEntity.ModifiedAt) - assert.Equal(t, api.WebhookExecResultSUCCESS, *webhookResponseEntity.LatestExecutionResult) - assert.Equal(t, "key", extraHeaders[0].Key) - assert.Equal(t, "value", extraHeaders[0].Value) - assert.Equal(t, "secret-id", *webhookResponseEntity.SecretIdentifier) - assert.Equal(t, "secret/path", *webhookResponseEntity.SecretSpacePath) - assert.Equal(t, int64(1), *webhookResponseEntity.SecretSpaceId) } -//nolint:lll -func TestMapToWebhookResponseEntity_FindPrimaryBySpaceIDError(t *testing.T) { - ctx := context.Background() - mockSpacePathStore := new(MockSpacePathStore) - helper := &GitnessRegistryMetadataHelper{ - spacePathStore: mockSpacePathStore, +func TestMapToWebhookResponseEntity_FindByPathError(t *testing.T) { + // GIVEN + mockSpacePathStore := new(mocks.SpacePathStore) + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryDao := new(mocks.RegistryRepository) + + helper := NewRegistryMetadataHelper(mockSpacePathStore, mockSpaceFinder, mockRegistryDao) + + webhook := &gitnesstypes.WebhookCore{ + ID: 1, + ParentID: 1, + Type: gitnessenum.WebhookTypeInternal, + Identifier: "webhook", + DisplayName: "webhook", + URL: "http://example.com", + Enabled: true, + Insecure: false, + SecretSpaceID: 1, + Created: 1234567890, + Updated: 1234567890, } - createdAt := time.Now().Unix() - updatedAt := time.Now().Unix() - description := "Test webhook" - secretIdentifier := "secret-id" - extraHeaders := []gitnesstypes.ExtraHeader{{Key: "key", Value: "value"}} - latestExecutionResult := gitnessenum.WebhookExecutionResultSuccess - createdWebhook := gitnesstypes.WebhookCore{ - Identifier: "webhook", - DisplayName: "webhook", - URL: "http://example.com", - Enabled: true, - Insecure: false, - Triggers: []gitnessenum.WebhookTrigger{gitnessenum.WebhookTriggerArtifactCreated}, - Created: createdAt, - Updated: updatedAt, - Description: description, - SecretIdentifier: secretIdentifier, - SecretSpaceID: 1, - ExtraHeaders: extraHeaders, - LatestExecutionResult: &latestExecutionResult, - } + mockSpacePathStore.On("FindPrimaryBySpaceID", mock.Anything, int64(1)).Return(nil, fmt.Errorf("space not found")) - mockSpacePathStore.On("FindPrimaryBySpaceID", ctx, int64(1)).Return(nil, fmt.Errorf("error finding primary by space ID")) + // WHEN + result, err := helper.MapToWebhookResponseEntity(context.Background(), webhook) - webhookResponseEntity, err := helper.MapToWebhookResponseEntity(ctx, &createdWebhook) + // THEN assert.Error(t, err) - assert.Nil(t, webhookResponseEntity) - assert.Contains(t, err.Error(), "failed to get secret space path: error finding primary by space ID") + assert.Nil(t, result) + mockSpacePathStore.AssertExpectations(t) +} + +func TestGetRegistryRequestBaseInfo(t *testing.T) { + tests := []struct { + name string + parentRef string + registryName string + setupMocks func(*mocks.SpacePathStore, *mocks.SpaceFinder, *mocks.RegistryRepository) + expectedError string + validate func(*testing.T, *types.RegistryRequestBaseInfo, error) + }{ + { + name: "success_case", + parentRef: "root/parent", + registryName: "reg", + setupMocks: func(_ *mocks.SpacePathStore, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepository *mocks.RegistryRepository) { + mockSpaceFinder.On("FindByRef", mock.Anything, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(&gitnesstypes.SpaceCore{ID: 2}, nil) + mockRegistryRepository.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(&types.Registry{ + ID: 3, + Type: api.RegistryTypeVIRTUAL, + }, nil) + }, + validate: func(t *testing.T, baseInfo *types.RegistryRequestBaseInfo, err error) { + assert.NoError(t, err, "should not return error") + assert.NotNil(t, baseInfo, "baseInfo should not be nil") + assert.Equal(t, int64(1), baseInfo.RootIdentifierID, "root ID should match") + assert.Equal(t, int64(2), baseInfo.ParentID, "parent ID should match") + assert.Equal(t, int64(3), baseInfo.RegistryID, "registry ID should match") + assert.Equal(t, api.RegistryTypeVIRTUAL, baseInfo.RegistryType, "registry type should match") + }, + }, + { + name: "empty_parent_ref", + parentRef: "", + registryName: "reg", + expectedError: "parent reference is required", + }, + { + name: "invalid_parent_ref", + parentRef: "/", + registryName: "reg", + expectedError: "invalid parent reference", + }, + { + name: "root_space_not_found", + parentRef: "root/parent", + registryName: "reg", + setupMocks: func(_ *mocks.SpacePathStore, mockSpaceFinder *mocks.SpaceFinder, _ *mocks.RegistryRepository) { + mockSpaceFinder.On("FindByRef", mock.Anything, "root").Return(nil, fmt.Errorf("not found")) + }, + expectedError: "root space not found", + }, + { + name: "parent_space_not_found", + parentRef: "root/parent", + registryName: "reg", + setupMocks: func(_ *mocks.SpacePathStore, mockSpaceFinder *mocks.SpaceFinder, _ *mocks.RegistryRepository) { + mockSpaceFinder.On("FindByRef", mock.Anything, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(nil, fmt.Errorf("not found")) + }, + expectedError: "parent space not found", + }, + { + name: "registry_not_found", + parentRef: "root/parent", + registryName: "reg", + setupMocks: func(_ *mocks.SpacePathStore, mockSpaceFinder *mocks.SpaceFinder, mockRegistryRepository *mocks.RegistryRepository) { + mockSpaceFinder.On("FindByRef", mock.Anything, "root").Return(&gitnesstypes.SpaceCore{ID: 1}, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(&gitnesstypes.SpaceCore{ID: 2}, nil) + mockRegistryRepository.On("GetByParentIDAndName", mock.Anything, int64(2), "reg").Return(nil, fmt.Errorf("not found")) + }, + expectedError: "registry not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create mocks + mockSpacePathStore := new(mocks.SpacePathStore) + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + + // Create helper + helper := &GitnessRegistryMetadataHelper{ + spacePathStore: mockSpacePathStore, + spaceFinder: mockSpaceFinder, + registryRepository: mockRegistryRepository, + } + + // Setup mocks if provided + if tt.setupMocks != nil { + tt.setupMocks(mockSpacePathStore, mockSpaceFinder, mockRegistryRepository) + } + + // Execute test + baseInfo, err := helper.GetRegistryRequestBaseInfo(context.Background(), tt.parentRef, tt.registryName) + + // Validate results + if tt.expectedError != "" { + assert.Error(t, err, "should return error") + assert.Contains(t, err.Error(), tt.expectedError, "error message should match") + assert.Nil(t, baseInfo, "baseInfo should be nil") + } else if tt.validate != nil { + tt.validate(t, baseInfo, err) + } + + // Verify mock expectations + mockSpacePathStore.AssertExpectations(t) + mockSpaceFinder.AssertExpectations(t) + mockRegistryRepository.AssertExpectations(t) + }) + } } func TestMapToInternalWebhookTriggers(t *testing.T) { helper := &GitnessRegistryMetadataHelper{} - apiTriggers := []api.Trigger{ - api.TriggerARTIFACTCREATION, - api.TriggerARTIFACTDELETION, + tests := []struct { + name string + triggers []api.Trigger + expected []gitnessenum.WebhookTrigger + }{ + { + name: "success_case", + triggers: []api.Trigger{ + api.TriggerARTIFACTCREATION, + api.TriggerARTIFACTDELETION, + }, + expected: []gitnessenum.WebhookTrigger{ + gitnessenum.WebhookTriggerArtifactCreated, + gitnessenum.WebhookTriggerArtifactDeleted, + }, + }, + { + name: "empty_triggers", + triggers: []api.Trigger{}, + expected: []gitnessenum.WebhookTrigger{}, + }, } - expectedInternalTriggers := []gitnessenum.WebhookTrigger{ - gitnessenum.WebhookTriggerArtifactCreated, - gitnessenum.WebhookTriggerArtifactDeleted, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := helper.MapToInternalWebhookTriggers(tt.triggers) + assert.Equal(t, tt.expected, result, "triggers should match") + }) } - - internalTriggers := helper.MapToInternalWebhookTriggers(apiTriggers) - assert.Equal(t, expectedInternalTriggers, internalTriggers) } func TestMapToAPIWebhookTriggers(t *testing.T) { helper := &GitnessRegistryMetadataHelper{} - internalTriggers := []gitnessenum.WebhookTrigger{ - gitnessenum.WebhookTriggerArtifactCreated, - gitnessenum.WebhookTriggerArtifactDeleted, + tests := []struct { + name string + triggers []gitnessenum.WebhookTrigger + expected []api.Trigger + }{ + { + name: "success_case", + triggers: []gitnessenum.WebhookTrigger{ + gitnessenum.WebhookTriggerArtifactCreated, + gitnessenum.WebhookTriggerArtifactDeleted, + }, + expected: []api.Trigger{ + api.TriggerARTIFACTCREATION, + api.TriggerARTIFACTDELETION, + }, + }, + { + name: "empty_triggers", + triggers: []gitnessenum.WebhookTrigger{}, + expected: []api.Trigger{}, + }, } - expectedAPITriggers := []api.Trigger{ - api.TriggerARTIFACTCREATION, - api.TriggerARTIFACTDELETION, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := helper.MapToAPIWebhookTriggers(tt.triggers) + assert.Equal(t, tt.expected, result, "triggers should match") + }) } - - apiTriggers := helper.MapToAPIWebhookTriggers(internalTriggers) - assert.Equal(t, expectedAPITriggers, apiTriggers) } diff --git a/registry/app/api/controller/metadata/retrigger_webhook_execution_test.go b/registry/app/api/controller/metadata/retrigger_webhook_execution_test.go index 4c4fcfcca..4c8e5640c 100644 --- a/registry/app/api/controller/metadata/retrigger_webhook_execution_test.go +++ b/registry/app/api/controller/metadata/retrigger_webhook_execution_test.go @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metadata +//nolint:lll +package metadata_test import ( "context" @@ -21,256 +22,302 @@ import ( "time" gitnesswebhook "github.com/harness/gitness/app/services/webhook" + "github.com/harness/gitness/registry/app/api/controller/metadata" + "github.com/harness/gitness/registry/app/api/controller/mocks" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" - gitnesstypes "github.com/harness/gitness/types" + "github.com/harness/gitness/registry/types" + coretypes "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) -//nolint:lll -func TestReTriggerWebhookExecution_Success(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - mockMockWebhookService := new(MockWebhookService) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - WebhookService: mockMockWebhookService, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - latestExecutionResult := enum.WebhookExecutionResultSuccess - mockMockWebhookService.On("ReTriggerWebhookExecution", ctx, int64(1)).Return(&gitnesswebhook.TriggerResult{ - Execution: &gitnesstypes.WebhookExecutionCore{ - ID: 1, - Created: time.Now().Unix(), - Duration: 100, - Error: "none", - Request: gitnesstypes.WebhookExecutionRequest{Body: "{}", Headers: "headers", URL: "http://example.com"}, - Response: gitnesstypes.WebhookExecutionResponse{Body: "{}", Headers: "headers", Status: "200 OK", StatusCode: 200}, - RetriggerOf: nil, - Retriggerable: true, - WebhookID: 4, - Result: enum.WebhookExecutionResultSuccess, - TriggerType: enum.WebhookTriggerArtifactCreated}, - Webhook: &gitnesstypes.WebhookCore{ - Identifier: "webhook", - DisplayName: "webhook", - URL: "http://example.com", - Enabled: true, - Insecure: false, - Triggers: []enum.WebhookTrigger{enum.WebhookTriggerArtifactCreated}, - Created: time.Now().Unix(), - Updated: time.Now().Unix(), - Description: "Test webhook", - SecretSpaceID: 1, - ExtraHeaders: []gitnesstypes.ExtraHeader{{Key: "key", Value: "value"}}, - LatestExecutionResult: &latestExecutionResult, +var ( + webhookExecution = &coretypes.WebhookExecutionCore{ + ID: 1, + Created: time.Now().Unix(), + WebhookID: 1, + Result: enum.WebhookExecutionResultSuccess, + Duration: 100, + Error: "", + Retriggerable: false, + Request: coretypes.WebhookExecutionRequest{ + URL: "http://example.com", + Headers: "{}", + Body: "{}", + }, + Response: coretypes.WebhookExecutionResponse{ + StatusCode: 200, + Status: "OK", + Headers: "{}", + Body: "{}", }, TriggerType: enum.WebhookTriggerArtifactCreated, - }, nil) - - r := api.ReTriggerWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", } - response, err := controller.ReTriggerWebhookExecution(ctx, r) - reTriggerWebhookExecution200JSONResponse, ok := response.(api.ReTriggerWebhookExecution200JSONResponse) - if !ok { - t.Fatalf("expected api.ReTriggerWebhookExecution200JSONResponse, got %T", response) + webhookExecutionEntity = &api.WebhookExecution{ + Id: &webhookExecution.ID, + Created: &webhookExecution.Created, + Duration: &webhookExecution.Duration, + RetriggerOf: webhookExecution.RetriggerOf, + Retriggerable: &webhookExecution.Retriggerable, + Error: &webhookExecution.Error, + WebhookId: &webhookExecution.WebhookID, + Request: &api.WebhookExecRequest{ + Body: &webhookExecution.Request.Body, + Headers: &webhookExecution.Request.Headers, + Url: &webhookExecution.Request.URL, + }, + Response: &api.WebhookExecResponse{ + Status: &webhookExecution.Response.Status, + StatusCode: &webhookExecution.Response.StatusCode, + Body: &webhookExecution.Response.Body, + Headers: &webhookExecution.Response.Headers, + }, + Result: &[]api.WebhookExecResult{api.WebhookExecResultSUCCESS}[0], + TriggerType: &[]api.Trigger{api.TriggerARTIFACTCREATION}[0], + } +) + +func TestReTriggerWebhookExecution(t *testing.T) { + // Create mocks that will be used across all tests + mockSpaceFinder := new(mocks.SpaceFinder) + mockRegistryRepository := new(mocks.RegistryRepository) + mockWebhooksRepository := new(mocks.WebhooksRepository) + mockWebhooksExecutionRepository := new(mocks.WebhooksExecutionRepository) + mockAuthorizer := new(mocks.Authorizer) + mockRegistryMetadataHelper := new(mocks.RegistryMetadataHelper) + mockWebhookService := new(mocks.WebhookService) + + tests := []struct { + name string + setupMocks func(*metadata.APIController) + request api.ReTriggerWebhookExecutionRequestObject + expectedResp api.ReTriggerWebhookExecutionResponseObject + expectedError error + }{ + { + name: "success_case", + setupMocks: func(_ *metadata.APIController) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &coretypes.SpaceCore{ID: 2} + var permissionChecks []coretypes.PermissionCheck + + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + + latestExecutionResult := enum.WebhookExecutionResultSuccess + mockWebhookService.On("ReTriggerWebhookExecution", mock.Anything, int64(1)).Return(&gitnesswebhook.TriggerResult{ + Execution: webhookExecution, + Webhook: &coretypes.WebhookCore{ + Identifier: "webhook", + DisplayName: "webhook", + URL: "http://example.com", + Enabled: true, + Insecure: false, + Triggers: []enum.WebhookTrigger{enum.WebhookTriggerArtifactCreated}, + Created: webhookExecution.Created, + Updated: webhookExecution.Created, + Description: "Test webhook", + SecretSpaceID: 1, + ExtraHeaders: []coretypes.ExtraHeader{{Key: "key", Value: "value"}}, + LatestExecutionResult: &latestExecutionResult, + }, + TriggerType: enum.WebhookTriggerArtifactCreated, + }, nil) + }, + request: api.ReTriggerWebhookExecutionRequestObject{ + WebhookIdentifier: "webhook", + RegistryRef: "reg", + WebhookExecutionId: "1", + }, + expectedResp: api.ReTriggerWebhookExecution200JSONResponse{ + WebhookExecutionResponseJSONResponse: api.WebhookExecutionResponseJSONResponse{ + Data: *webhookExecutionEntity, + Status: api.StatusSUCCESS, + }, + }, + }, + { + name: "permission_check_fails", + setupMocks: func(_ *metadata.APIController) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &coretypes.SpaceCore{ID: 2} + var permissionChecks []coretypes.PermissionCheck + + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(false, nil) + }, + request: api.ReTriggerWebhookExecutionRequestObject{ + WebhookIdentifier: "webhook", + RegistryRef: "reg", + WebhookExecutionId: "1", + }, + expectedResp: api.ReTriggerWebhookExecution403JSONResponse{ + UnauthorizedJSONResponse: api.UnauthorizedJSONResponse{ + Code: "403", + Message: "not authorized", + }, + }, + }, + { + name: "invalid_execution_identifier", + setupMocks: func(_ *metadata.APIController) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &coretypes.SpaceCore{ID: 2} + var permissionChecks []coretypes.PermissionCheck + + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + }, + request: api.ReTriggerWebhookExecutionRequestObject{ + WebhookIdentifier: "webhook", + RegistryRef: "reg", + WebhookExecutionId: "invalid", + }, + expectedResp: api.ReTriggerWebhookExecution400JSONResponse{ + BadRequestJSONResponse: api.BadRequestJSONResponse{ + Code: "400", + Message: "invalid webhook execution identifier: invalid, err: strconv.ParseInt: parsing \"invalid\": invalid syntax", + }, + }, + }, + { + name: "retrigger_execution_error", + setupMocks: func(_ *metadata.APIController) { + regInfo := &types.RegistryRequestBaseInfo{ + RegistryID: 1, + RegistryIdentifier: "reg", + ParentRef: "root/parent", + } + space := &coretypes.SpaceCore{ID: 2} + var permissionChecks []coretypes.PermissionCheck + + mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", mock.Anything, "", "reg").Return(regInfo, nil) + mockSpaceFinder.On("FindByRef", mock.Anything, "root/parent").Return(space, nil) + mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) + mockAuthorizer.On("CheckAll", mock.Anything, mock.Anything, mock.Anything).Return(true, nil) + mockWebhookService.On("ReTriggerWebhookExecution", mock.Anything, int64(1)).Return(nil, fmt.Errorf("error")) + }, + request: api.ReTriggerWebhookExecutionRequestObject{ + WebhookIdentifier: "webhook", + RegistryRef: "reg", + WebhookExecutionId: "1", + }, + expectedResp: api.ReTriggerWebhookExecution500JSONResponse{ + InternalServerErrorJSONResponse: api.InternalServerErrorJSONResponse{ + Code: "500", + Message: "failed to re-trigger execution: error", + }, + }, + }, } - assert.NoError(t, err) - assert.NotNil(t, response) - assert.Equal(t, api.StatusSUCCESS, reTriggerWebhookExecution200JSONResponse.Status) - assert.Equal(t, int64(1), *reTriggerWebhookExecution200JSONResponse.Data.Id) - assert.Equal(t, "none", *reTriggerWebhookExecution200JSONResponse.Data.Error) - assert.Equal(t, "{}", *reTriggerWebhookExecution200JSONResponse.Data.Request.Body) - assert.Equal(t, "headers", *reTriggerWebhookExecution200JSONResponse.Data.Request.Headers) - assert.Equal(t, "http://example.com", *reTriggerWebhookExecution200JSONResponse.Data.Request.Url) - assert.Equal(t, "{}", *reTriggerWebhookExecution200JSONResponse.Data.Response.Body) - assert.Equal(t, "headers", *reTriggerWebhookExecution200JSONResponse.Data.Response.Headers) - assert.Equal(t, "200 OK", *reTriggerWebhookExecution200JSONResponse.Data.Response.Status) - assert.Equal(t, 200, *reTriggerWebhookExecution200JSONResponse.Data.Response.StatusCode) - assert.Equal(t, api.WebhookExecResultSUCCESS, *reTriggerWebhookExecution200JSONResponse.Data.Result) - assert.Equal(t, api.TriggerARTIFACTCREATION, *reTriggerWebhookExecution200JSONResponse.Data.TriggerType) - assert.Equal(t, api.StatusSUCCESS, reTriggerWebhookExecution200JSONResponse.Status) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Clear mock expectations + mockSpaceFinder.ExpectedCalls = nil + mockRegistryRepository.ExpectedCalls = nil + mockWebhooksRepository.ExpectedCalls = nil + mockWebhooksExecutionRepository.ExpectedCalls = nil + mockAuthorizer.ExpectedCalls = nil + mockRegistryMetadataHelper.ExpectedCalls = nil + mockWebhookService.ExpectedCalls = nil - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) - mockWebhooksExecutionRepository.AssertExpectations(t) - mockMockWebhookService.AssertExpectations(t) -} - -//nolint:lll -func TestReTriggerWebhookExecution_PermissionCheckFails(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - mockMockWebhookService := new(MockWebhookService) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - WebhookService: mockMockWebhookService, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(false, nil) - - r := api.ReTriggerWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", - } - - response, err := controller.ReTriggerWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ReTriggerWebhookExecution403JSONResponse{}, response) - assert.Equal(t, "forbidden", response.(api.ReTriggerWebhookExecution403JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) -} - -//nolint:lll -func TestReTriggerWebhookExecution_InvalidExecutionIdentifier(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - mockMockWebhookService := new(MockWebhookService) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - WebhookService: mockMockWebhookService, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - - r := api.ReTriggerWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "invalid", - } - - response, err := controller.ReTriggerWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ReTriggerWebhookExecution400JSONResponse{}, response) - assert.Equal(t, "invalid webhook execution identifier: invalid, err: strconv.ParseInt: parsing \"invalid\": invalid syntax", - response.(api.ReTriggerWebhookExecution400JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) -} - -//nolint:lll -func TestReTriggerWebhookExecution_ReTriggerExecutionError(t *testing.T) { - ctx := context.Background() - mockSpaceFinder := new(MockSpaceFinder) - mockRegistryRepository := new(MockRegistryRepository) - mockWebhooksRepository := new(MockWebhooksRepository) - mockWebhooksExecutionRepository := new(MockWebhooksExecutionRepository) - mockAuthorizer := new(MockAuthorizer) - mockRegistryMetadataHelper := new(MockRegistryMetadataHelper) - mockMockWebhookService := new(MockWebhookService) - controller := &APIController{ - SpaceFinder: mockSpaceFinder, - RegistryRepository: mockRegistryRepository, - WebhooksRepository: mockWebhooksRepository, - WebhooksExecutionRepository: mockWebhooksExecutionRepository, - Authorizer: mockAuthorizer, - RegistryMetadataHelper: mockRegistryMetadataHelper, - WebhookService: mockMockWebhookService, - } - - regInfo := &RegistryRequestBaseInfo{ - RegistryID: 1, - RegistryIdentifier: "reg", - ParentRef: "root/parent", - } - space := &gitnesstypes.SpaceCore{ID: 2} - var permissionChecks []gitnesstypes.PermissionCheck - mockRegistryMetadataHelper.On("GetRegistryRequestBaseInfo", ctx, "", "reg").Return(regInfo, nil) - mockSpaceFinder.On("FindByRef", ctx, "root/parent").Return(space, nil) - mockRegistryMetadataHelper.On("GetPermissionChecks", space, regInfo.RegistryIdentifier, enum.PermissionRegistryEdit).Return(permissionChecks) - mockAuthorizer.On("CheckAll", ctx, mock.Anything, permissionChecks).Return(true, nil) - mockMockWebhookService.On("ReTriggerWebhookExecution", ctx, int64(1)).Return(nil, fmt.Errorf("error")) - - r := api.ReTriggerWebhookExecutionRequestObject{ - RegistryRef: "reg", - WebhookIdentifier: "webhook", - WebhookExecutionId: "1", - } - - response, err := controller.ReTriggerWebhookExecution(ctx, r) - assert.NoError(t, err) - assert.NotNil(t, response) - assert.IsType(t, api.ReTriggerWebhookExecution500JSONResponse{}, response) - assert.Equal(t, "failed to re-trigger execution: error", response.(api.ReTriggerWebhookExecution500JSONResponse).Message) //nolint:errcheck - - mockRegistryMetadataHelper.AssertExpectations(t) - mockSpaceFinder.AssertExpectations(t) - mockAuthorizer.AssertExpectations(t) + controller := &metadata.APIController{ + SpaceFinder: mockSpaceFinder, + RegistryRepository: mockRegistryRepository, + WebhooksRepository: mockWebhooksRepository, + WebhooksExecutionRepository: mockWebhooksExecutionRepository, + Authorizer: mockAuthorizer, + RegistryMetadataHelper: mockRegistryMetadataHelper, + WebhookService: mockWebhookService, + } + + // Setup mocks + tt.setupMocks(controller) + + resp, err := controller.ReTriggerWebhookExecution(context.Background(), tt.request) + assert.Equal(t, tt.expectedError, err) + assert.NotNil(t, resp, "response should not be nil") + + switch tt.name { + case "success_case": + successResp, ok := resp.(api.ReTriggerWebhookExecution200JSONResponse) + assert.True(t, ok, "expected 200 response") + assert.Equal(t, api.StatusSUCCESS, successResp.Status) + assert.NotNil(t, successResp.Data, "Data should not be nil") + assert.NotNil(t, successResp.Data.Id, "Id should not be nil") + assert.NotNil(t, successResp.Data.Error, "Error should not be nil") + assert.NotNil(t, successResp.Data.Request, "Request should not be nil") + assert.NotNil(t, successResp.Data.Response, "Response should not be nil") + assert.NotNil(t, successResp.Data.Result, "Result should not be nil") + assert.NotNil(t, successResp.Data.TriggerType, "TriggerType should not be nil") + + if assert.NotNil(t, successResp.Data.Request) { + assert.Equal(t, "{}", *successResp.Data.Request.Body) + assert.Equal(t, "{}", *successResp.Data.Request.Headers) + assert.Equal(t, "http://example.com", *successResp.Data.Request.Url) + } + + if assert.NotNil(t, successResp.Data.Response) { + assert.Equal(t, "{}", *successResp.Data.Response.Body) + assert.Equal(t, "{}", *successResp.Data.Response.Headers) + assert.Equal(t, "OK", *successResp.Data.Response.Status) + assert.Equal(t, 200, *successResp.Data.Response.StatusCode) + } + + assert.Equal(t, int64(1), *successResp.Data.Id) + assert.Equal(t, "", *successResp.Data.Error) + assert.Equal(t, api.WebhookExecResultSUCCESS, *successResp.Data.Result) + assert.Equal(t, api.TriggerARTIFACTCREATION, *successResp.Data.TriggerType) + + case "permission_check_fails": + assert.IsType(t, api.ReTriggerWebhookExecution403JSONResponse{}, resp, "expected 403 response") + errorResp, _ := resp.(api.ReTriggerWebhookExecution403JSONResponse) //nolint:errcheck + assert.Equal(t, "403", errorResp.Code) + assert.Equal(t, "forbidden", errorResp.Message) + + case "invalid_execution_identifier": + assert.IsType(t, api.ReTriggerWebhookExecution400JSONResponse{}, resp, "expected 400 response") + errorResp, _ := resp.(api.ReTriggerWebhookExecution400JSONResponse) //nolint:errcheck + assert.Equal(t, "400", errorResp.Code) + assert.Equal(t, "invalid webhook execution identifier: invalid, err: strconv.ParseInt: parsing \"invalid\": invalid syntax", errorResp.Message) + + case "retrigger_execution_error": + assert.IsType(t, api.ReTriggerWebhookExecution500JSONResponse{}, resp, "expected 500 response") + errorResp, _ := resp.(api.ReTriggerWebhookExecution500JSONResponse) //nolint:errcheck + assert.Equal(t, "500", errorResp.Code) + assert.Equal(t, "failed to re-trigger execution: error", errorResp.Message) + } + + // Verify all mock expectations + mockSpaceFinder.AssertExpectations(t) + mockRegistryRepository.AssertExpectations(t) + mockWebhooksRepository.AssertExpectations(t) + mockWebhooksExecutionRepository.AssertExpectations(t) + mockAuthorizer.AssertExpectations(t) + mockRegistryMetadataHelper.AssertExpectations(t) + mockWebhookService.AssertExpectations(t) + }) + } } diff --git a/registry/app/api/controller/metadata/update_artifact.go b/registry/app/api/controller/metadata/update_artifact.go index ce220b6b2..40bdf4948 100644 --- a/registry/app/api/controller/metadata/update_artifact.go +++ b/registry/app/api/controller/metadata/update_artifact.go @@ -71,7 +71,7 @@ func (c *APIController) UpdateArtifactLabels( a := string(r.Artifact) - artifactEntity, err := c.ImageStore.GetByRepoAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier, a) + artifactEntity, err := c.ImageStore.GetByRepoAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier, a) if len(artifactEntity.Name) == 0 { return artifact.UpdateArtifactLabels404JSONResponse{ @@ -95,7 +95,7 @@ func (c *APIController) UpdateArtifactLabels( } // TODO: use the correct way to get download count if this endpoint is used - tag, err := c.TagStore.GetLatestTagMetadata(ctx, regInfo.parentID, regInfo.RegistryIdentifier, a) + tag, err := c.TagStore.GetLatestTagMetadata(ctx, regInfo.ParentID, regInfo.RegistryIdentifier, a) if err != nil { return artifact.UpdateArtifactLabels500JSONResponse{ diff --git a/registry/app/api/controller/metadata/update_registry.go b/registry/app/api/controller/metadata/update_registry.go index 1fa25557d..693d18784 100644 --- a/registry/app/api/controller/metadata/update_registry.go +++ b/registry/app/api/controller/metadata/update_registry.go @@ -68,7 +68,7 @@ func (c *APIController) ModifyRegistry( }, err } - repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.parentID, regInfo.RegistryIdentifier) + repoEntity, err := c.RegistryRepository.GetByParentIDAndName(ctx, regInfo.ParentID, regInfo.RegistryIdentifier) if err != nil { return throwModifyRegistry500Error(err), err } @@ -77,7 +77,7 @@ func (c *APIController) ModifyRegistry( return c.updateVirtualRegistry(ctx, r, repoEntity, err, regInfo, session) } upstreamproxyEntity, err := c.UpstreamProxyStore.GetByRegistryIdentifier( - ctx, regInfo.parentID, + ctx, regInfo.ParentID, regInfo.RegistryIdentifier, ) if len(upstreamproxyEntity.RepoKey) == 0 { @@ -93,7 +93,7 @@ func (c *APIController) ModifyRegistry( registry, upstreamproxy, err := c.UpdateUpstreamProxyEntity( ctx, artifact.RegistryRequest(*r.Body), - regInfo.parentID, regInfo.rootIdentifierID, upstreamproxyEntity, + regInfo.ParentID, regInfo.RootIdentifierID, upstreamproxyEntity, ) registry.ID = repoEntity.ID upstreamproxy.ID = upstreamproxyEntity.ID @@ -133,7 +133,7 @@ func (c *APIController) ModifyRegistry( func (c *APIController) updateVirtualRegistry( ctx context.Context, r artifact.ModifyRegistryRequestObject, repoEntity *types.Registry, err error, - regInfo *RegistryRequestBaseInfo, session *auth.Session, + regInfo *types.RegistryRequestBaseInfo, session *auth.Session, ) (artifact.ModifyRegistryResponseObject, error) { if len(repoEntity.Name) == 0 { return artifact.ModifyRegistry404JSONResponse{ @@ -158,7 +158,7 @@ func (c *APIController) updateVirtualRegistry( ), }, nil } - err = c.setUpstreamProxyIDs(ctx, registry, artifact.RegistryRequest(*r.Body), regInfo.parentID) + err = c.setUpstreamProxyIDs(ctx, registry, artifact.RegistryRequest(*r.Body), regInfo.ParentID) if err != nil { return throwModifyRegistry500Error(err), nil } @@ -393,7 +393,7 @@ func (c *APIController) UpdateUpstreamProxyEntity( } if res.SecretSpacePath != nil && len(*res.SecretSpacePath) > 0 { - upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretSpacePath) + upstreamProxyConfigEntity.SecretSpaceID, err = c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.SecretSpacePath) if err != nil { return nil, nil, err } @@ -414,7 +414,7 @@ func (c *APIController) UpdateUpstreamProxyEntity( default: if res.AccessKeySecretSpacePath != nil && len(*res.AccessKeySecretSpacePath) > 0 { upstreamProxyConfigEntity.UserNameSecretSpaceID, err = - c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.AccessKeySecretSpacePath) + c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.AccessKeySecretSpacePath) if err != nil { return nil, nil, err } @@ -426,7 +426,7 @@ func (c *APIController) UpdateUpstreamProxyEntity( if res.SecretKeySpacePath != nil && len(*res.SecretKeySpacePath) > 0 { upstreamProxyConfigEntity.SecretSpaceID, err = - c.RegistryMetadataHelper.getSecretSpaceID(ctx, res.SecretKeySpacePath) + c.RegistryMetadataHelper.GetSecretSpaceID(ctx, res.SecretKeySpacePath) if err != nil { return nil, nil, err } diff --git a/registry/app/api/controller/metadata/utils_test.go b/registry/app/api/controller/metadata/utils_test.go index 2180bc352..070497516 100644 --- a/registry/app/api/controller/metadata/utils_test.go +++ b/registry/app/api/controller/metadata/utils_test.go @@ -12,151 +12,545 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metadata +package metadata_test import ( "testing" "time" + "github.com/harness/gitness/registry/app/api/controller/metadata" "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" "github.com/stretchr/testify/assert" ) -func TestValidatePackageTypes_ValidTypes(t *testing.T) { - err := ValidatePackageTypes([]string{"DOCKER", "HELM"}) - assert.NoError(t, err) -} - -func TestValidatePackageTypes_InvalidTypes(t *testing.T) { - err := ValidatePackageTypes([]string{"INVALID"}) - assert.Error(t, err) - assert.Equal(t, "invalid package type", err.Error()) -} - -func TestValidatePackageType_ValidType(t *testing.T) { - err := ValidatePackageType("DOCKER") - assert.NoError(t, err) -} - -func TestValidatePackageType_InvalidType(t *testing.T) { - err := ValidatePackageType("INVALID") - assert.Error(t, err) - assert.Equal(t, "invalid package type", err.Error()) -} - -func TestValidateIdentifier_ValidIdentifier(t *testing.T) { - err := ValidateIdentifier("valid-identifier") - assert.NoError(t, err) -} - -func TestValidateIdentifier_InvalidIdentifier(t *testing.T) { - err := ValidateIdentifier("Invalid Identifier") - assert.Error(t, err) - assert.Equal(t, RegistryIdentifierErrorMsg, err.Error()) -} - -func TestCleanURLPath_ValidURL(t *testing.T) { - input := "https://example.com/path/" - expected := "https://example.com/path" - CleanURLPath(&input) - assert.Equal(t, expected, input) -} - -func TestCleanURLPath_InvalidURL(t *testing.T) { - input := "://invalid-url" - expected := "://invalid-url" - CleanURLPath(&input) - assert.Equal(t, expected, input) -} - -func TestGetTimeInMs_ValidTime(t *testing.T) { - tm := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC) - expected := "1672531200000" - result := GetTimeInMs(tm) - assert.Equal(t, expected, result) -} - -func TestGetErrorResponse_ValidError(t *testing.T) { - code := 404 - message := "Not Found" - expected := &artifact.Error{ - Code: "404", - Message: message, +func TestValidatePackageTypes(t *testing.T) { + tests := []struct { + name string + types []string + wantErr bool + errMsg string + }{ + { + name: "valid_types", + types: []string{"DOCKER", "HELM"}, + wantErr: false, + }, + { + name: "invalid_type", + types: []string{"INVALID"}, + wantErr: true, + errMsg: "invalid package type", + }, } - result := GetErrorResponse(code, message) - assert.Equal(t, expected, result) -} -func TestGetSortByOrder_ValidOrder(t *testing.T) { - assert.Equal(t, "ASC", GetSortByOrder("")) - assert.Equal(t, "DESC", GetSortByOrder("DESC")) - assert.Equal(t, "ASC", GetSortByOrder("INVALID")) -} - -func TestGetSortByField_ValidField(t *testing.T) { - assert.Equal(t, "name", GetSortByField("identifier", RepositoryResource)) - assert.Equal(t, "created_at", GetSortByField("invalid", RepositoryResource)) -} - -func TestGetPageLimit_ValidPageSize(t *testing.T) { - pageSize := artifact.PageSize(20) - assert.Equal(t, 20, GetPageLimit(&pageSize)) - assert.Equal(t, 10, GetPageLimit(nil)) -} - -func TestGetOffset_ValidOffset(t *testing.T) { - pageSize := artifact.PageSize(20) - pageNumber := artifact.PageNumber(2) - assert.Equal(t, 40, GetOffset(&pageSize, &pageNumber)) - assert.Equal(t, 0, GetOffset(nil, nil)) -} - -func TestGetPageNumber_ValidPageNumber(t *testing.T) { - pageNumber := artifact.PageNumber(2) - assert.Equal(t, int64(2), GetPageNumber(&pageNumber)) - assert.Equal(t, int64(1), GetPageNumber(nil)) -} - -func TestGetSuccessResponse_ValidResponse(t *testing.T) { - expected := &artifact.Success{ - Status: artifact.StatusSUCCESS, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := metadata.ValidatePackageTypes(tt.types) + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) } - result := GetSuccessResponse() - assert.Equal(t, expected, result) } -func TestGetPageCount_ValidCount(t *testing.T) { - assert.Equal(t, int64(5), GetPageCount(50, 10)) - assert.Equal(t, int64(0), GetPageCount(0, 10)) +func TestValidatePackageType(t *testing.T) { + tests := []struct { + name string + pkgType string + wantErr bool + errMsg string + }{ + { + name: "valid_type", + pkgType: "DOCKER", + wantErr: false, + }, + { + name: "invalid_type", + pkgType: "INVALID", + wantErr: true, + errMsg: "invalid package type", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := metadata.ValidatePackageType(tt.pkgType) + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } } -func TestGetRegistryRef_ValidRef(t *testing.T) { - assert.Equal(t, "root/registry", GetRegistryRef("root", "registry")) +func TestValidateIdentifier(t *testing.T) { + tests := []struct { + name string + identifier string + wantErr bool + errMsg string + }{ + { + name: "valid_identifier", + identifier: "valid-identifier", + wantErr: false, + }, + { + name: "invalid_identifier", + identifier: "Invalid Identifier", + wantErr: true, + errMsg: metadata.RegistryIdentifierErrorMsg, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := metadata.ValidateIdentifier(tt.identifier) + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } } -func TestGetRepoURLWithoutProtocol_ValidURL(t *testing.T) { - assert.Equal(t, "example.com/path", GetRepoURLWithoutProtocol("https://example.com/path")) - assert.Equal(t, "", GetRepoURLWithoutProtocol("://invalid-url")) +func TestCleanURLPath(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "valid_url", + input: "https://example.com/path/", + expected: "https://example.com/path", + }, + { + name: "invalid_url", + input: "://invalid-url", + expected: "://invalid-url", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + input := tt.input + metadata.CleanURLPath(&input) + assert.Equal(t, tt.expected, input) + }) + } } -func TestGetTagURL_ValidURL(t *testing.T) { - assert.Equal(t, "https://example.com/artifact/version", GetTagURL("artifact", "version", "https://example.com")) +func TestGetTimeInMs(t *testing.T) { + tests := []struct { + name string + time time.Time + expected string + }{ + { + name: "valid_time", + time: time.Unix(1234567890, 0), + expected: "1234567890000", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetTimeInMs(tt.time) + assert.Equal(t, tt.expected, result) + }) + } } -func TestGetPullCommand_ValidCommand(t *testing.T) { - assert.Equal(t, "docker pull example.com/image:tag", - GetPullCommand("image", "tag", "DOCKER", "https://example.com")) - assert.Equal(t, "helm pull oci://example.com/image --version tag", - GetPullCommand("image", "tag", "HELM", "https://example.com")) - assert.Equal(t, "", GetPullCommand("image", "tag", "INVALID", "https://example.com")) +func TestGetPullCommand(t *testing.T) { + tests := []struct { + name string + image string + tag string + pkgType string + baseURL string + expected string + }{ + { + name: "docker_command", + image: "image", + tag: "tag", + pkgType: "DOCKER", + baseURL: "https://example.com", + expected: "docker pull example.com/image:tag", + }, + { + name: "helm_command", + image: "image", + tag: "tag", + pkgType: "HELM", + baseURL: "https://example.com", + expected: "helm pull oci://example.com/image --version tag", + }, + { + name: "invalid_type", + image: "image", + tag: "tag", + pkgType: "INVALID", + baseURL: "https://example.com", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetPullCommand(tt.image, tt.tag, tt.pkgType, tt.baseURL) + assert.Equal(t, tt.expected, result) + }) + } } -func TestGetDockerPullCommand_ValidCommand(t *testing.T) { - assert.Equal(t, "docker pull example.com/image:tag", GetDockerPullCommand("image", "tag", "https://example.com")) +func TestGetDockerPullCommand(t *testing.T) { + tests := []struct { + name string + image string + tag string + baseURL string + expected string + }{ + { + name: "valid_command", + image: "image", + tag: "tag", + baseURL: "https://example.com", + expected: "docker pull example.com/image:tag", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetDockerPullCommand(tt.image, tt.tag, tt.baseURL) + assert.Equal(t, tt.expected, result) + }) + } } -func TestGetHelmPullCommand_ValidCommand(t *testing.T) { - assert.Equal(t, "helm pull oci://example.com/image --version tag", - GetHelmPullCommand("image", "tag", "https://example.com")) +func TestGetHelmPullCommand(t *testing.T) { + tests := []struct { + name string + image string + tag string + baseURL string + expected string + }{ + { + name: "valid_command", + image: "image", + tag: "tag", + baseURL: "https://example.com", + expected: "helm pull oci://example.com/image --version tag", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetHelmPullCommand(tt.image, tt.tag, tt.baseURL) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetErrorResponse(t *testing.T) { + tests := []struct { + name string + code int + message string + expected *artifact.Error + }{ + { + name: "valid_error", + code: 404, + message: "Not Found", + expected: &artifact.Error{ + Code: "404", + Message: "Not Found", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetErrorResponse(tt.code, tt.message) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetSortByOrder(t *testing.T) { + tests := []struct { + name string + order string + expected string + }{ + { + name: "empty_order", + order: "", + expected: "ASC", + }, + { + name: "desc_order", + order: "DESC", + expected: "DESC", + }, + { + name: "invalid_order", + order: "INVALID", + expected: "ASC", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetSortByOrder(tt.order) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetSortByField(t *testing.T) { + tests := []struct { + name string + field string + resource string + expected string + }{ + { + name: "identifier_field", + field: "identifier", + resource: "repository", + expected: "name", + }, + { + name: "invalid_field", + field: "invalid", + resource: "repository", + expected: "created_at", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetSortByField(tt.field, tt.resource) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetPageLimit(t *testing.T) { + tests := []struct { + name string + pageSize *artifact.PageSize + expected int + }{ + { + name: "valid_page_size", + pageSize: func() *artifact.PageSize { ps := artifact.PageSize(20); return &ps }(), + expected: 20, + }, + { + name: "nil_page_size", + pageSize: nil, + expected: 10, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetPageLimit(tt.pageSize) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetOffset(t *testing.T) { + tests := []struct { + name string + pageSize *artifact.PageSize + pageNumber *artifact.PageNumber + expected int + }{ + { + name: "valid_offset", + pageSize: func() *artifact.PageSize { ps := artifact.PageSize(20); return &ps }(), + pageNumber: func() *artifact.PageNumber { pn := artifact.PageNumber(2); return &pn }(), + expected: 40, + }, + { + name: "nil_values", + pageSize: nil, + pageNumber: nil, + expected: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetOffset(tt.pageSize, tt.pageNumber) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetPageNumber(t *testing.T) { + tests := []struct { + name string + pageNumber *artifact.PageNumber + expected int64 + }{ + { + name: "valid_page_number", + pageNumber: func() *artifact.PageNumber { pn := artifact.PageNumber(2); return &pn }(), + expected: 2, + }, + { + name: "nil_page_number", + pageNumber: nil, + expected: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetPageNumber(tt.pageNumber) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetSuccessResponse(t *testing.T) { + tests := []struct { + name string + expected *artifact.Success + }{ + { + name: "valid_response", + expected: &artifact.Success{ + Status: artifact.StatusSUCCESS, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetSuccessResponse() + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetPageCount(t *testing.T) { + tests := []struct { + name string + count int64 + limit int + expected int64 + }{ + { + name: "valid_count", + count: 50, + limit: 10, + expected: 5, + }, + { + name: "zero_count", + count: 0, + limit: 10, + expected: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetPageCount(tt.count, tt.limit) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetRegistryRef(t *testing.T) { + tests := []struct { + name string + root string + registry string + expected string + }{ + { + name: "valid_ref", + root: "root", + registry: "registry", + expected: "root/registry", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetRegistryRef(tt.root, tt.registry) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetRepoURLWithoutProtocol(t *testing.T) { + tests := []struct { + name string + url string + expected string + }{ + { + name: "valid_url", + url: "https://example.com/path", + expected: "example.com/path", + }, + { + name: "invalid_url", + url: "://invalid-url", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetRepoURLWithoutProtocol(tt.url) + assert.Equal(t, tt.expected, result) + }) + } +} + +func TestGetTagURL(t *testing.T) { + tests := []struct { + name string + artifact string + version string + baseURL string + expected string + }{ + { + name: "valid_url", + artifact: "artifact", + version: "version", + baseURL: "https://example.com", + expected: "https://example.com/artifact/version", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := metadata.GetTagURL(tt.artifact, tt.version, tt.baseURL) + assert.Equal(t, tt.expected, result) + }) + } } diff --git a/registry/app/api/controller/mocks/artifact_repository.go b/registry/app/api/controller/mocks/artifact_repository.go new file mode 100644 index 000000000..bf23d13bd --- /dev/null +++ b/registry/app/api/controller/mocks/artifact_repository.go @@ -0,0 +1,370 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// ArtifactRepository is an autogenerated mock type for the ArtifactRepository type +type ArtifactRepository struct { + mock.Mock +} + +// Count provides a mock function with given fields: ctx +func (_m *ArtifactRepository) Count(ctx context.Context) (int64, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Count") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (int64, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) int64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllArtifactsByParentID provides a mock function with given fields: ctx, parentID, registryIDs, search, latestVersion, packageTypes +func (_m *ArtifactRepository) CountAllArtifactsByParentID(ctx context.Context, parentID int64, registryIDs *[]string, search string, latestVersion bool, packageTypes []string) (int64, error) { + ret := _m.Called(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + + if len(ret) == 0 { + panic("no return value specified for CountAllArtifactsByParentID") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, bool, []string) (int64, error)); ok { + return rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, bool, []string) int64); ok { + r0 = rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, *[]string, string, bool, []string) error); ok { + r1 = rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllArtifactsByRepo provides a mock function with given fields: ctx, parentID, repoKey, search, labels +func (_m *ArtifactRepository) CountAllArtifactsByRepo(ctx context.Context, parentID int64, repoKey string, search string, labels []string) (int64, error) { + ret := _m.Called(ctx, parentID, repoKey, search, labels) + + if len(ret) == 0 { + panic("no return value specified for CountAllArtifactsByRepo") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, []string) (int64, error)); ok { + return rf(ctx, parentID, repoKey, search, labels) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, []string) int64); ok { + r0 = rf(ctx, parentID, repoKey, search, labels) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, []string) error); ok { + r1 = rf(ctx, parentID, repoKey, search, labels) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllVersionsByRepoAndImage provides a mock function with given fields: ctx, parentID, repoKey, image, search +func (_m *ArtifactRepository) CountAllVersionsByRepoAndImage(ctx context.Context, parentID int64, repoKey string, image string, search string) (int64, error) { + ret := _m.Called(ctx, parentID, repoKey, image, search) + + if len(ret) == 0 { + panic("no return value specified for CountAllVersionsByRepoAndImage") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) (int64, error)); ok { + return rf(ctx, parentID, repoKey, image, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) int64); ok { + r0 = rf(ctx, parentID, repoKey, image, search) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, image, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateOrUpdate provides a mock function with given fields: ctx, artifact +func (_m *ArtifactRepository) CreateOrUpdate(ctx context.Context, artifact *types.Artifact) error { + ret := _m.Called(ctx, artifact) + + if len(ret) == 0 { + panic("no return value specified for CreateOrUpdate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Artifact) error); ok { + r0 = rf(ctx, artifact) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetAllArtifactsByParentID provides a mock function with given fields: ctx, id, i, field, order, limit, offset, term, version, packageTypes +func (_m *ArtifactRepository) GetAllArtifactsByParentID(ctx context.Context, id int64, i *[]string, field string, order string, limit int, offset int, term string, version bool, packageTypes []string) (*[]types.ArtifactMetadata, error) { + ret := _m.Called(ctx, id, i, field, order, limit, offset, term, version, packageTypes) + + if len(ret) == 0 { + panic("no return value specified for GetAllArtifactsByParentID") + } + + var r0 *[]types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) (*[]types.ArtifactMetadata, error)); ok { + return rf(ctx, id, i, field, order, limit, offset, term, version, packageTypes) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) *[]types.ArtifactMetadata); ok { + r0 = rf(ctx, id, i, field, order, limit, offset, term, version, packageTypes) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) error); ok { + r1 = rf(ctx, id, i, field, order, limit, offset, term, version, packageTypes) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllArtifactsByRepo provides a mock function with given fields: ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels +func (_m *ArtifactRepository) GetAllArtifactsByRepo(ctx context.Context, parentID int64, repoKey string, sortByField string, sortByOrder string, limit int, offset int, search string, labels []string) (*[]types.ArtifactMetadata, error) { + ret := _m.Called(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + + if len(ret) == 0 { + panic("no return value specified for GetAllArtifactsByRepo") + } + + var r0 *[]types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, int, int, string, []string) (*[]types.ArtifactMetadata, error)); ok { + return rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, int, int, string, []string) *[]types.ArtifactMetadata); ok { + r0 = rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string, int, int, string, []string) error); ok { + r1 = rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllVersionsByRepoAndImage provides a mock function with given fields: ctx, id, identifier, image, field, order, limit, offset, term +func (_m *ArtifactRepository) GetAllVersionsByRepoAndImage(ctx context.Context, id int64, identifier string, image string, field string, order string, limit int, offset int, term string) (*[]types.NonOCIArtifactMetadata, error) { + ret := _m.Called(ctx, id, identifier, image, field, order, limit, offset, term) + + if len(ret) == 0 { + panic("no return value specified for GetAllVersionsByRepoAndImage") + } + + var r0 *[]types.NonOCIArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, string, int, int, string) (*[]types.NonOCIArtifactMetadata, error)); ok { + return rf(ctx, id, identifier, image, field, order, limit, offset, term) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, string, int, int, string) *[]types.NonOCIArtifactMetadata); ok { + r0 = rf(ctx, id, identifier, image, field, order, limit, offset, term) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.NonOCIArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string, string, int, int, string) error); ok { + r1 = rf(ctx, id, identifier, image, field, order, limit, offset, term) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetArtifactMetadata provides a mock function with given fields: ctx, id, identifier, image, version +func (_m *ArtifactRepository) GetArtifactMetadata(ctx context.Context, id int64, identifier string, image string, version string) (*types.ArtifactMetadata, error) { + ret := _m.Called(ctx, id, identifier, image, version) + + if len(ret) == 0 { + panic("no return value specified for GetArtifactMetadata") + } + + var r0 *types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) (*types.ArtifactMetadata, error)); ok { + return rf(ctx, id, identifier, image, version) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) *types.ArtifactMetadata); ok { + r0 = rf(ctx, id, identifier, image, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string) error); ok { + r1 = rf(ctx, id, identifier, image, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByName provides a mock function with given fields: ctx, imageID, version +func (_m *ArtifactRepository) GetByName(ctx context.Context, imageID int64, version string) (*types.Artifact, error) { + ret := _m.Called(ctx, imageID, version) + + if len(ret) == 0 { + panic("no return value specified for GetByName") + } + + var r0 *types.Artifact + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*types.Artifact, error)); ok { + return rf(ctx, imageID, version) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Artifact); ok { + r0 = rf(ctx, imageID, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Artifact) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, imageID, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByRegistryIDAndImage provides a mock function with given fields: ctx, registryID, image +func (_m *ArtifactRepository) GetByRegistryIDAndImage(ctx context.Context, registryID int64, image string) (*[]types.Artifact, error) { + ret := _m.Called(ctx, registryID, image) + + if len(ret) == 0 { + panic("no return value specified for GetByRegistryIDAndImage") + } + + var r0 *[]types.Artifact + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*[]types.Artifact, error)); ok { + return rf(ctx, registryID, image) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *[]types.Artifact); ok { + r0 = rf(ctx, registryID, image) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.Artifact) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, registryID, image) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLatestArtifactMetadata provides a mock function with given fields: ctx, id, identifier, image +func (_m *ArtifactRepository) GetLatestArtifactMetadata(ctx context.Context, id int64, identifier string, image string) (*types.ArtifactMetadata, error) { + ret := _m.Called(ctx, id, identifier, image) + + if len(ret) == 0 { + panic("no return value specified for GetLatestArtifactMetadata") + } + + var r0 *types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.ArtifactMetadata, error)); ok { + return rf(ctx, id, identifier, image) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.ArtifactMetadata); ok { + r0 = rf(ctx, id, identifier, image) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, id, identifier, image) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewArtifactRepository creates a new instance of ArtifactRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewArtifactRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *ArtifactRepository { + mock := &ArtifactRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/audit_service.go b/registry/app/api/controller/mocks/audit_service.go new file mode 100644 index 000000000..f651f1a55 --- /dev/null +++ b/registry/app/api/controller/mocks/audit_service.go @@ -0,0 +1,42 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/audit" + "github.com/harness/gitness/types" + + "github.com/stretchr/testify/mock" +) + +// AuditService is a mock of audit.Service interface. +type AuditService struct { + mock.Mock +} + +// Log provides a mock function +func (m *AuditService) Log( + ctx context.Context, + user types.Principal, + resource audit.Resource, + action audit.Action, + spacePath string, + options ...audit.Option, +) error { + args := []interface{}{ctx, user, resource, action, spacePath} + for _, opt := range options { + args = append(args, opt) + } + ret := m.Called(args...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.Principal, audit.Resource, audit.Action, string, ...audit.Option) error); ok { + r0 = rf(ctx, user, resource, action, spacePath, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/registry/app/api/controller/mocks/authorizer.go b/registry/app/api/controller/mocks/authorizer.go new file mode 100644 index 000000000..5ea3b1e69 --- /dev/null +++ b/registry/app/api/controller/mocks/authorizer.go @@ -0,0 +1,65 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/mock" +) + +// Authorizer is an autogenerated mock type for the Authorizer type +type Authorizer struct { + mock.Mock +} + +// Check provides a mock function with given fields: ctx, session, scope, resource, permission +func (m *Authorizer) Check(ctx context.Context, session *auth.Session, scope *types.Scope, resource *types.Resource, permission enum.Permission) (bool, error) { + ret := m.Called(ctx, session, scope, resource, permission) + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context, *auth.Session, *types.Scope, *types.Resource, enum.Permission) bool); ok { + r0 = rf(ctx, session, scope, resource, permission) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *auth.Session, *types.Scope, *types.Resource, enum.Permission) error); ok { + r1 = rf(ctx, session, scope, resource, permission) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CheckAll provides a mock function with given fields: ctx, session, permissionChecks +func (m *Authorizer) CheckAll(ctx context.Context, session *auth.Session, permissionChecks ...types.PermissionCheck) (bool, error) { + var args []interface{} + args = append(args, ctx, session) + for _, check := range permissionChecks { + args = append(args, check) + } + ret := m.Called(args...) + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context, *auth.Session, ...types.PermissionCheck) bool); ok { + r0 = rf(ctx, session, permissionChecks...) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *auth.Session, ...types.PermissionCheck) error); ok { + r1 = rf(ctx, session, permissionChecks...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/blob_repository.go b/registry/app/api/controller/mocks/blob_repository.go new file mode 100644 index 000000000..2bbc43f55 --- /dev/null +++ b/registry/app/api/controller/mocks/blob_repository.go @@ -0,0 +1,232 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + digest "github.com/opencontainers/go-digest" + mock "github.com/stretchr/testify/mock" +) + +// BlobRepository is an autogenerated mock type for the BlobRepository type +type BlobRepository struct { + mock.Mock +} + +// CreateOrFind provides a mock function with given fields: ctx, b +func (_m *BlobRepository) CreateOrFind(ctx context.Context, b *types.Blob) (*types.Blob, bool, error) { + ret := _m.Called(ctx, b) + + if len(ret) == 0 { + panic("no return value specified for CreateOrFind") + } + + var r0 *types.Blob + var r1 bool + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Blob) (*types.Blob, bool, error)); ok { + return rf(ctx, b) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.Blob) *types.Blob); ok { + r0 = rf(ctx, b) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Blob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.Blob) bool); ok { + r1 = rf(ctx, b) + } else { + r1 = ret.Get(1).(bool) + } + + if rf, ok := ret.Get(2).(func(context.Context, *types.Blob) error); ok { + r2 = rf(ctx, b) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// DeleteByID provides a mock function with given fields: ctx, id +func (_m *BlobRepository) DeleteByID(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for DeleteByID") + } + + 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 +} + +// ExistsBlob provides a mock function with given fields: ctx, repoID, d, image +func (_m *BlobRepository) ExistsBlob(ctx context.Context, repoID int64, d digest.Digest, image string) (bool, error) { + ret := _m.Called(ctx, repoID, d, image) + + if len(ret) == 0 { + panic("no return value specified for ExistsBlob") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, digest.Digest, string) (bool, error)); ok { + return rf(ctx, repoID, d, image) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, digest.Digest, string) bool); ok { + r0 = rf(ctx, repoID, d, image) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, digest.Digest, string) error); ok { + r1 = rf(ctx, repoID, d, image) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindByDigestAndRepoID provides a mock function with given fields: ctx, d, repoID, imageName +func (_m *BlobRepository) FindByDigestAndRepoID(ctx context.Context, d digest.Digest, repoID int64, imageName string) (*types.Blob, error) { + ret := _m.Called(ctx, d, repoID, imageName) + + if len(ret) == 0 { + panic("no return value specified for FindByDigestAndRepoID") + } + + var r0 *types.Blob + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, digest.Digest, int64, string) (*types.Blob, error)); ok { + return rf(ctx, d, repoID, imageName) + } + if rf, ok := ret.Get(0).(func(context.Context, digest.Digest, int64, string) *types.Blob); ok { + r0 = rf(ctx, d, repoID, imageName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Blob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, digest.Digest, int64, string) error); ok { + r1 = rf(ctx, d, repoID, imageName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindByDigestAndRootParentID provides a mock function with given fields: ctx, d, rootParentID +func (_m *BlobRepository) FindByDigestAndRootParentID(ctx context.Context, d digest.Digest, rootParentID int64) (*types.Blob, error) { + ret := _m.Called(ctx, d, rootParentID) + + if len(ret) == 0 { + panic("no return value specified for FindByDigestAndRootParentID") + } + + var r0 *types.Blob + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, digest.Digest, int64) (*types.Blob, error)); ok { + return rf(ctx, d, rootParentID) + } + if rf, ok := ret.Get(0).(func(context.Context, digest.Digest, int64) *types.Blob); ok { + r0 = rf(ctx, d, rootParentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Blob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, digest.Digest, int64) error); ok { + r1 = rf(ctx, d, rootParentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindByID provides a mock function with given fields: ctx, id +func (_m *BlobRepository) FindByID(ctx context.Context, id int64) (*types.Blob, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for FindByID") + } + + var r0 *types.Blob + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.Blob, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Blob); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Blob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TotalSizeByRootParentID provides a mock function with given fields: ctx, id +func (_m *BlobRepository) TotalSizeByRootParentID(ctx context.Context, id int64) (int64, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for TotalSizeByRootParentID") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewBlobRepository creates a new instance of BlobRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewBlobRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *BlobRepository { + mock := &BlobRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/cleanup_policy_repository.go b/registry/app/api/controller/mocks/cleanup_policy_repository.go new file mode 100644 index 000000000..11ae7be64 --- /dev/null +++ b/registry/app/api/controller/mocks/cleanup_policy_repository.go @@ -0,0 +1,308 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// CleanupPolicyRepository is an autogenerated mock type for the CleanupPolicyRepository type +type CleanupPolicyRepository struct { + mock.Mock +} + +type CleanupPolicyRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *CleanupPolicyRepository) EXPECT() *CleanupPolicyRepository_Expecter { + return &CleanupPolicyRepository_Expecter{mock: &_m.Mock} +} + +// Create provides a mock function with given fields: ctx, cleanupPolicy +func (_m *CleanupPolicyRepository) Create(ctx context.Context, cleanupPolicy *types.CleanupPolicy) (int64, error) { + ret := _m.Called(ctx, cleanupPolicy) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.CleanupPolicy) (int64, error)); ok { + return rf(ctx, cleanupPolicy) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.CleanupPolicy) int64); ok { + r0 = rf(ctx, cleanupPolicy) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.CleanupPolicy) error); ok { + r1 = rf(ctx, cleanupPolicy) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CleanupPolicyRepository_Create_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Create' +type CleanupPolicyRepository_Create_Call struct { + *mock.Call +} + +// Create is a helper method to define mock.On call +// - ctx context.Context +// - cleanupPolicy *types.CleanupPolicy +func (_e *CleanupPolicyRepository_Expecter) Create(ctx interface{}, cleanupPolicy interface{}) *CleanupPolicyRepository_Create_Call { + return &CleanupPolicyRepository_Create_Call{Call: _e.mock.On("Create", ctx, cleanupPolicy)} +} + +func (_c *CleanupPolicyRepository_Create_Call) Run(run func(ctx context.Context, cleanupPolicy *types.CleanupPolicy)) *CleanupPolicyRepository_Create_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*types.CleanupPolicy)) + }) + return _c +} + +func (_c *CleanupPolicyRepository_Create_Call) Return(id int64, err error) *CleanupPolicyRepository_Create_Call { + _c.Call.Return(id, err) + return _c +} + +func (_c *CleanupPolicyRepository_Create_Call) RunAndReturn(run func(context.Context, *types.CleanupPolicy) (int64, error)) *CleanupPolicyRepository_Create_Call { + _c.Call.Return(run) + return _c +} + +// Delete provides a mock function with given fields: ctx, id +func (_m *CleanupPolicyRepository) Delete(ctx context.Context, id int64) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + 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 +} + +// CleanupPolicyRepository_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' +type CleanupPolicyRepository_Delete_Call struct { + *mock.Call +} + +// Delete is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *CleanupPolicyRepository_Expecter) Delete(ctx interface{}, id interface{}) *CleanupPolicyRepository_Delete_Call { + return &CleanupPolicyRepository_Delete_Call{Call: _e.mock.On("Delete", ctx, id)} +} + +func (_c *CleanupPolicyRepository_Delete_Call) Run(run func(ctx context.Context, id int64)) *CleanupPolicyRepository_Delete_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *CleanupPolicyRepository_Delete_Call) Return(err error) *CleanupPolicyRepository_Delete_Call { + _c.Call.Return(err) + return _c +} + +func (_c *CleanupPolicyRepository_Delete_Call) RunAndReturn(run func(context.Context, int64) error) *CleanupPolicyRepository_Delete_Call { + _c.Call.Return(run) + return _c +} + +// GetByRegistryID provides a mock function with given fields: ctx, id +func (_m *CleanupPolicyRepository) GetByRegistryID(ctx context.Context, id int64) (*[]types.CleanupPolicy, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetByRegistryID") + } + + var r0 *[]types.CleanupPolicy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*[]types.CleanupPolicy, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *[]types.CleanupPolicy); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.CleanupPolicy) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CleanupPolicyRepository_GetByRegistryID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetByRegistryID' +type CleanupPolicyRepository_GetByRegistryID_Call struct { + *mock.Call +} + +// GetByRegistryID is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *CleanupPolicyRepository_Expecter) GetByRegistryID(ctx interface{}, id interface{}) *CleanupPolicyRepository_GetByRegistryID_Call { + return &CleanupPolicyRepository_GetByRegistryID_Call{Call: _e.mock.On("GetByRegistryID", ctx, id)} +} + +func (_c *CleanupPolicyRepository_GetByRegistryID_Call) Run(run func(ctx context.Context, id int64)) *CleanupPolicyRepository_GetByRegistryID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *CleanupPolicyRepository_GetByRegistryID_Call) Return(cleanupPolicies *[]types.CleanupPolicy, err error) *CleanupPolicyRepository_GetByRegistryID_Call { + _c.Call.Return(cleanupPolicies, err) + return _c +} + +func (_c *CleanupPolicyRepository_GetByRegistryID_Call) RunAndReturn(run func(context.Context, int64) (*[]types.CleanupPolicy, error)) *CleanupPolicyRepository_GetByRegistryID_Call { + _c.Call.Return(run) + return _c +} + +// GetIDsByRegistryID provides a mock function with given fields: ctx, id +func (_m *CleanupPolicyRepository) GetIDsByRegistryID(ctx context.Context, id int64) ([]int64, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetIDsByRegistryID") + } + + var r0 []int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) ([]int64, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) []int64); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int64) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CleanupPolicyRepository_GetIDsByRegistryID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetIDsByRegistryID' +type CleanupPolicyRepository_GetIDsByRegistryID_Call struct { + *mock.Call +} + +// GetIDsByRegistryID is a helper method to define mock.On call +// - ctx context.Context +// - id int64 +func (_e *CleanupPolicyRepository_Expecter) GetIDsByRegistryID(ctx interface{}, id interface{}) *CleanupPolicyRepository_GetIDsByRegistryID_Call { + return &CleanupPolicyRepository_GetIDsByRegistryID_Call{Call: _e.mock.On("GetIDsByRegistryID", ctx, id)} +} + +func (_c *CleanupPolicyRepository_GetIDsByRegistryID_Call) Run(run func(ctx context.Context, id int64)) *CleanupPolicyRepository_GetIDsByRegistryID_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(int64)) + }) + return _c +} + +func (_c *CleanupPolicyRepository_GetIDsByRegistryID_Call) Return(ids []int64, err error) *CleanupPolicyRepository_GetIDsByRegistryID_Call { + _c.Call.Return(ids, err) + return _c +} + +func (_c *CleanupPolicyRepository_GetIDsByRegistryID_Call) RunAndReturn(run func(context.Context, int64) ([]int64, error)) *CleanupPolicyRepository_GetIDsByRegistryID_Call { + _c.Call.Return(run) + return _c +} + +// ModifyCleanupPolicies provides a mock function with given fields: ctx, cleanupPolicies, ids +func (_m *CleanupPolicyRepository) ModifyCleanupPolicies(ctx context.Context, cleanupPolicies *[]types.CleanupPolicy, ids []int64) error { + ret := _m.Called(ctx, cleanupPolicies, ids) + + if len(ret) == 0 { + panic("no return value specified for ModifyCleanupPolicies") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *[]types.CleanupPolicy, []int64) error); ok { + r0 = rf(ctx, cleanupPolicies, ids) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CleanupPolicyRepository_ModifyCleanupPolicies_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ModifyCleanupPolicies' +type CleanupPolicyRepository_ModifyCleanupPolicies_Call struct { + *mock.Call +} + +// ModifyCleanupPolicies is a helper method to define mock.On call +// - ctx context.Context +// - cleanupPolicies *[]types.CleanupPolicy +// - ids []int64 +func (_e *CleanupPolicyRepository_Expecter) ModifyCleanupPolicies(ctx interface{}, cleanupPolicies interface{}, ids interface{}) *CleanupPolicyRepository_ModifyCleanupPolicies_Call { + return &CleanupPolicyRepository_ModifyCleanupPolicies_Call{Call: _e.mock.On("ModifyCleanupPolicies", ctx, cleanupPolicies, ids)} +} + +func (_c *CleanupPolicyRepository_ModifyCleanupPolicies_Call) Run(run func(ctx context.Context, cleanupPolicies *[]types.CleanupPolicy, ids []int64)) *CleanupPolicyRepository_ModifyCleanupPolicies_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(*[]types.CleanupPolicy), args[2].([]int64)) + }) + return _c +} + +func (_c *CleanupPolicyRepository_ModifyCleanupPolicies_Call) Return(_a0 error) *CleanupPolicyRepository_ModifyCleanupPolicies_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *CleanupPolicyRepository_ModifyCleanupPolicies_Call) RunAndReturn(run func(context.Context, *[]types.CleanupPolicy, []int64) error) *CleanupPolicyRepository_ModifyCleanupPolicies_Call { + _c.Call.Return(run) + return _c +} + +// NewCleanupPolicyRepository creates a new instance of CleanupPolicyRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewCleanupPolicyRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *CleanupPolicyRepository { + mock := &CleanupPolicyRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/controller.go b/registry/app/api/controller/mocks/controller.go new file mode 100644 index 000000000..e77029bb7 --- /dev/null +++ b/registry/app/api/controller/mocks/controller.go @@ -0,0 +1,100 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + multipart "mime/multipart" + + pkgpython "github.com/harness/gitness/registry/app/api/controller/pkg/python" + python "github.com/harness/gitness/registry/app/pkg/types/python" + + mock "github.com/stretchr/testify/mock" +) + +// Controller is an autogenerated mock type for the Controller type +type Controller struct { + mock.Mock +} + +// DownloadPackageFile provides a mock function with given fields: ctx, info +func (_m *Controller) DownloadPackageFile(ctx context.Context, info python.ArtifactInfo) *pkgpython.GetArtifactResponse { + ret := _m.Called(ctx, info) + + if len(ret) == 0 { + panic("no return value specified for DownloadPackageFile") + } + + var r0 *pkgpython.GetArtifactResponse + if rf, ok := ret.Get(0).(func(context.Context, python.ArtifactInfo) *pkgpython.GetArtifactResponse); ok { + r0 = rf(ctx, info) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*pkgpython.GetArtifactResponse) + } + } + + return r0 +} + +// GetPackageMetadata provides a mock function with given fields: ctx, info +func (_m *Controller) GetPackageMetadata(ctx context.Context, info python.ArtifactInfo) (python.PackageMetadata, error) { + ret := _m.Called(ctx, info) + + if len(ret) == 0 { + panic("no return value specified for GetPackageMetadata") + } + + var r0 python.PackageMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, python.ArtifactInfo) (python.PackageMetadata, error)); ok { + return rf(ctx, info) + } + if rf, ok := ret.Get(0).(func(context.Context, python.ArtifactInfo) python.PackageMetadata); ok { + r0 = rf(ctx, info) + } else { + r0 = ret.Get(0).(python.PackageMetadata) + } + + if rf, ok := ret.Get(1).(func(context.Context, python.ArtifactInfo) error); ok { + r1 = rf(ctx, info) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UploadPackageFile provides a mock function with given fields: ctx, info, file, fileHeader +func (_m *Controller) UploadPackageFile(ctx context.Context, info python.ArtifactInfo, file multipart.File, fileHeader *multipart.FileHeader) *pkgpython.PutArtifactResponse { + ret := _m.Called(ctx, info, file, fileHeader) + + if len(ret) == 0 { + panic("no return value specified for UploadPackageFile") + } + + var r0 *pkgpython.PutArtifactResponse + if rf, ok := ret.Get(0).(func(context.Context, python.ArtifactInfo, multipart.File, *multipart.FileHeader) *pkgpython.PutArtifactResponse); ok { + r0 = rf(ctx, info, file, fileHeader) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*pkgpython.PutArtifactResponse) + } + } + + return r0 +} + +// NewController creates a new instance of Controller. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewController(t interface { + mock.TestingT + Cleanup(func()) +}) *Controller { + mock := &Controller{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/file_manager.go b/registry/app/api/controller/mocks/file_manager.go new file mode 100644 index 000000000..822875dd9 --- /dev/null +++ b/registry/app/api/controller/mocks/file_manager.go @@ -0,0 +1,67 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + "context" + "io" + "mime/multipart" + + "github.com/harness/gitness/registry/app/storage" + "github.com/harness/gitness/registry/types" + + "github.com/stretchr/testify/mock" +) + +// FileManager is a mock type for filemanager.FileManager +type FileManager struct { + mock.Mock +} + +// UploadFile provides a mock function +func (m *FileManager) UploadFile(ctx context.Context, filePath string, regName string, regID int64, rootParentID int64, rootIdentifier string, file multipart.File, fileReader io.Reader, filename string) (types.FileInfo, error) { + args := m.Called(ctx, filePath, regName, regID, rootParentID, rootIdentifier, file, fileReader, filename) + return args.Get(0).(types.FileInfo), args.Error(1) +} + +// DownloadFile provides a mock function +func (m *FileManager) DownloadFile(ctx context.Context, filePath string, regInfo types.Registry, rootIdentifier string) (*storage.FileReader, int64, string, error) { + args := m.Called(ctx, filePath, regInfo, rootIdentifier) + return args.Get(0).(*storage.FileReader), args.Get(1).(int64), args.Get(2).(string), args.Error(3) +} + +// DeleteFile provides a mock function +func (m *FileManager) DeleteFile(ctx context.Context, filePath string, regID int) error { + args := m.Called(ctx, filePath, regID) + return args.Error(0) +} + +// HeadFile provides a mock function +func (m *FileManager) HeadFile(ctx context.Context, filePath string, regID int64) (string, error) { + args := m.Called(ctx, filePath, regID) + return args.String(0), args.Error(1) +} + +// GetFileMetadata provides a mock function +func (m *FileManager) GetFileMetadata(ctx context.Context, filePath string, regID int64) (types.FileInfo, error) { + args := m.Called(ctx, filePath, regID) + return args.Get(0).(types.FileInfo), args.Error(1) +} + +// DeleteFileByRegistryID provides a mock function +func (m *FileManager) DeleteFileByRegistryID(ctx context.Context, regID int64, regName string) error { + args := m.Called(ctx, regID, regName) + return args.Error(0) +} + +// GetFilesMetadata provides a mock function +func (m *FileManager) GetFilesMetadata(ctx context.Context, filePath string, regID int64, sortByField string, sortByOrder string, limit int, offset int, search string) (*[]types.FileNodeMetadata, error) { + args := m.Called(ctx, filePath, regID, sortByField, sortByOrder, limit, offset, search) + return args.Get(0).(*[]types.FileNodeMetadata), args.Error(1) +} + +// CountFilesByPath provides a mock function +func (m *FileManager) CountFilesByPath(ctx context.Context, filePath string, regID int64) (int64, error) { + args := m.Called(ctx, filePath, regID) + return args.Get(0).(int64), args.Error(1) +} diff --git a/registry/app/api/controller/mocks/generic_blob_repository.go b/registry/app/api/controller/mocks/generic_blob_repository.go new file mode 100644 index 000000000..fcc089401 --- /dev/null +++ b/registry/app/api/controller/mocks/generic_blob_repository.go @@ -0,0 +1,164 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// GenericBlobRepository is an autogenerated mock type for the GenericBlobRepository type +type GenericBlobRepository struct { + mock.Mock +} + +// Create provides a mock function with given fields: ctx, gb +func (_m *GenericBlobRepository) Create(ctx context.Context, gb *types.GenericBlob) (bool, error) { + ret := _m.Called(ctx, gb) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.GenericBlob) (bool, error)); ok { + return rf(ctx, gb) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.GenericBlob) bool); ok { + r0 = rf(ctx, gb) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.GenericBlob) error); ok { + r1 = rf(ctx, gb) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteByID provides a mock function with given fields: ctx, id +func (_m *GenericBlobRepository) DeleteByID(ctx context.Context, id string) error { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for DeleteByID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FindByID provides a mock function with given fields: ctx, id +func (_m *GenericBlobRepository) FindByID(ctx context.Context, id string) (*types.GenericBlob, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for FindByID") + } + + var r0 *types.GenericBlob + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*types.GenericBlob, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *types.GenericBlob); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.GenericBlob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindBySha256AndRootParentID provides a mock function with given fields: ctx, sha256, rootParentID +func (_m *GenericBlobRepository) FindBySha256AndRootParentID(ctx context.Context, sha256 string, rootParentID int64) (*types.GenericBlob, error) { + ret := _m.Called(ctx, sha256, rootParentID) + + if len(ret) == 0 { + panic("no return value specified for FindBySha256AndRootParentID") + } + + var r0 *types.GenericBlob + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64) (*types.GenericBlob, error)); ok { + return rf(ctx, sha256, rootParentID) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64) *types.GenericBlob); ok { + r0 = rf(ctx, sha256, rootParentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.GenericBlob) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok { + r1 = rf(ctx, sha256, rootParentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TotalSizeByRootParentID provides a mock function with given fields: ctx, id +func (_m *GenericBlobRepository) TotalSizeByRootParentID(ctx context.Context, id int64) (int64, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for TotalSizeByRootParentID") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewGenericBlobRepository creates a new instance of GenericBlobRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewGenericBlobRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *GenericBlobRepository { + mock := &GenericBlobRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/image_repository.go b/registry/app/api/controller/mocks/image_repository.go new file mode 100644 index 000000000..f5edb5394 --- /dev/null +++ b/registry/app/api/controller/mocks/image_repository.go @@ -0,0 +1,322 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// ImageRepository is an autogenerated mock type for the ImageRepository type +type ImageRepository struct { + mock.Mock +} + +// CountLabelsByParentIDAndRepo provides a mock function with given fields: ctx, parentID, repo, search +func (_m *ImageRepository) CountLabelsByParentIDAndRepo(ctx context.Context, parentID int64, repo string, search string) (int64, error) { + ret := _m.Called(ctx, parentID, repo, search) + + if len(ret) == 0 { + panic("no return value specified for CountLabelsByParentIDAndRepo") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (int64, error)); ok { + return rf(ctx, parentID, repo, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) int64); ok { + r0 = rf(ctx, parentID, repo, search) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repo, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateOrUpdate provides a mock function with given fields: ctx, image +func (_m *ImageRepository) CreateOrUpdate(ctx context.Context, image *types.Image) error { + ret := _m.Called(ctx, image) + + if len(ret) == 0 { + panic("no return value specified for CreateOrUpdate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteBandwidthStatByRegistryID provides a mock function with given fields: ctx, registryID +func (_m *ImageRepository) DeleteBandwidthStatByRegistryID(ctx context.Context, registryID int64) error { + ret := _m.Called(ctx, registryID) + + if len(ret) == 0 { + panic("no return value specified for DeleteBandwidthStatByRegistryID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteByRegistryID provides a mock function with given fields: ctx, registryID +func (_m *ImageRepository) DeleteByRegistryID(ctx context.Context, registryID int64) error { + ret := _m.Called(ctx, registryID) + + if len(ret) == 0 { + panic("no return value specified for DeleteByRegistryID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteDownloadStatByRegistryID provides a mock function with given fields: ctx, registryID +func (_m *ImageRepository) DeleteDownloadStatByRegistryID(ctx context.Context, registryID int64) error { + ret := _m.Called(ctx, registryID) + + if len(ret) == 0 { + panic("no return value specified for DeleteDownloadStatByRegistryID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Get provides a mock function with given fields: ctx, id +func (_m *ImageRepository) Get(ctx context.Context, id int64) (*types.Image, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *types.Image + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.Image, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Image); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByName provides a mock function with given fields: ctx, registryID, name +func (_m *ImageRepository) GetByName(ctx context.Context, registryID int64, name string) (*types.Image, error) { + ret := _m.Called(ctx, registryID, name) + + if len(ret) == 0 { + panic("no return value specified for GetByName") + } + + var r0 *types.Image + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*types.Image, error)); ok { + return rf(ctx, registryID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Image); ok { + r0 = rf(ctx, registryID, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, registryID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByRepoAndName provides a mock function with given fields: ctx, parentID, repo, name +func (_m *ImageRepository) GetByRepoAndName(ctx context.Context, parentID int64, repo string, name string) (*types.Image, error) { + ret := _m.Called(ctx, parentID, repo, name) + + if len(ret) == 0 { + panic("no return value specified for GetByRepoAndName") + } + + var r0 *types.Image + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.Image, error)); ok { + return rf(ctx, parentID, repo, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.Image); ok { + r0 = rf(ctx, parentID, repo, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repo, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLabelsByParentIDAndRepo provides a mock function with given fields: ctx, parentID, repo, limit, offset, search +func (_m *ImageRepository) GetLabelsByParentIDAndRepo(ctx context.Context, parentID int64, repo string, limit int, offset int, search string) ([]string, error) { + ret := _m.Called(ctx, parentID, repo, limit, offset, search) + + if len(ret) == 0 { + panic("no return value specified for GetLabelsByParentIDAndRepo") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, int, int, string) ([]string, error)); ok { + return rf(ctx, parentID, repo, limit, offset, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, int, int, string) []string); ok { + r0 = rf(ctx, parentID, repo, limit, offset, search) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, int, int, string) error); ok { + r1 = rf(ctx, parentID, repo, limit, offset, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Update provides a mock function with given fields: ctx, artifact +func (_m *ImageRepository) Update(ctx context.Context, artifact *types.Image) error { + ret := _m.Called(ctx, artifact) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, artifact) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateStatus provides a mock function with given fields: ctx, artifact +func (_m *ImageRepository) UpdateStatus(ctx context.Context, artifact *types.Image) error { + ret := _m.Called(ctx, artifact) + + if len(ret) == 0 { + panic("no return value specified for UpdateStatus") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, artifact) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteByImageNameAndRegID provides a mock function with given fields: ctx, regID, image +func (_m *ImageRepository) DeleteByImageNameAndRegID(ctx context.Context, regID int64, image string) error { + ret := _m.Called(ctx, regID, image) + + if len(ret) == 0 { + panic("no return value specified for DeleteByImageNameAndRegID") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, regID, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteByImageNameIfNoLinkedArtifacts provides a mock function with given fields: ctx, regID, image +func (_m *ImageRepository) DeleteByImageNameIfNoLinkedArtifacts(ctx context.Context, regID int64, image string) error { + ret := _m.Called(ctx, regID, image) + + if len(ret) == 0 { + panic("no return value specified for DeleteByImageNameIfNoLinkedArtifacts") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, regID, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewImageRepository creates a new instance of ImageRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewImageRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *ImageRepository { + mock := &ImageRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/image_store.go b/registry/app/api/controller/mocks/image_store.go new file mode 100644 index 000000000..0729abc3a --- /dev/null +++ b/registry/app/api/controller/mocks/image_store.go @@ -0,0 +1,211 @@ +package mocks + +import ( + "context" + + "github.com/harness/gitness/registry/types" + + "github.com/stretchr/testify/mock" +) + +// ImageStore is an autogenerated mock type for the ImageStore type +type ImageStore struct { + mock.Mock +} + +// Get provides a mock function with given fields: ctx, id +func (m *ImageStore) Get(ctx context.Context, id int64) (*types.Image, error) { + ret := m.Called(ctx, id) + + var r0 *types.Image + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Image); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + 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 +} + +// GetByName provides a mock function with given fields: ctx, registryID, name +func (m *ImageStore) GetByName(ctx context.Context, registryID int64, name string) (*types.Image, error) { + ret := m.Called(ctx, registryID, name) + + var r0 *types.Image + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Image); ok { + r0 = rf(ctx, registryID, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, registryID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLabelsByParentIDAndRepo provides a mock function with given fields: ctx, parentID, repo, limit, offset, search +func (m *ImageStore) GetLabelsByParentIDAndRepo(ctx context.Context, parentID int64, repo string, limit int, offset int, search string) ([]string, error) { + ret := m.Called(ctx, parentID, repo, limit, offset, search) + + var r0 []string + if rf, ok := ret.Get(0).(func(context.Context, int64, string, int, int, string) []string); ok { + r0 = rf(ctx, parentID, repo, limit, offset, search) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string, int, int, string) error); ok { + r1 = rf(ctx, parentID, repo, limit, offset, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountLabelsByParentIDAndRepo provides a mock function with given fields: ctx, parentID, repo, search +func (m *ImageStore) CountLabelsByParentIDAndRepo(ctx context.Context, parentID int64, repo string, search string) (int64, error) { + ret := m.Called(ctx, parentID, repo, search) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) int64); ok { + r0 = rf(ctx, parentID, repo, search) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repo, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByRepoAndName provides a mock function with given fields: ctx, parentID, repo, name +func (m *ImageStore) GetByRepoAndName(ctx context.Context, parentID int64, repo string, name string) (*types.Image, error) { + ret := m.Called(ctx, parentID, repo, name) + + var r0 *types.Image + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.Image); ok { + r0 = rf(ctx, parentID, repo, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Image) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repo, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateOrUpdate provides a mock function with given fields: ctx, image +func (m *ImageStore) CreateOrUpdate(ctx context.Context, image *types.Image) error { + ret := m.Called(ctx, image) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, image +func (m *ImageStore) Update(ctx context.Context, image *types.Image) error { + ret := m.Called(ctx, image) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateStatus provides a mock function with given fields: ctx, image +func (m *ImageStore) UpdateStatus(ctx context.Context, image *types.Image) error { + ret := m.Called(ctx, image) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Image) error); ok { + r0 = rf(ctx, image) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteByRegistryID provides a mock function with given fields: ctx, registryID +func (m *ImageStore) DeleteByRegistryID(ctx context.Context, registryID int64) error { + ret := m.Called(ctx, registryID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteBandwidthStatByRegistryID provides a mock function with given fields: ctx, registryID +func (m *ImageStore) DeleteBandwidthStatByRegistryID(ctx context.Context, registryID int64) error { + ret := m.Called(ctx, registryID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteDownloadStatByRegistryID provides a mock function with given fields: ctx, registryID +func (m *ImageStore) DeleteDownloadStatByRegistryID(ctx context.Context, registryID int64) error { + ret := m.Called(ctx, registryID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, registryID) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/registry/app/api/controller/mocks/manifest_repository.go b/registry/app/api/controller/mocks/manifest_repository.go new file mode 100644 index 000000000..d50fc523a --- /dev/null +++ b/registry/app/api/controller/mocks/manifest_repository.go @@ -0,0 +1,477 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + digest "github.com/opencontainers/go-digest" + mock "github.com/stretchr/testify/mock" +) + +// ManifestRepository is an autogenerated mock type for the ManifestRepository type +type ManifestRepository struct { + mock.Mock +} + +// AssociateLayerBlob provides a mock function with given fields: ctx, m, b +func (_m *ManifestRepository) AssociateLayerBlob(ctx context.Context, m *types.Manifest, b *types.Blob) error { + ret := _m.Called(ctx, m, b) + + if len(ret) == 0 { + panic("no return value specified for AssociateLayerBlob") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest, *types.Blob) error); ok { + r0 = rf(ctx, m, b) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Count provides a mock function with given fields: ctx +func (_m *ManifestRepository) Count(ctx context.Context) (int, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Count") + } + + var r0 int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (int, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) int); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(int) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Create provides a mock function with given fields: ctx, m +func (_m *ManifestRepository) Create(ctx context.Context, m *types.Manifest) error { + ret := _m.Called(ctx, m) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) error); ok { + r0 = rf(ctx, m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CreateOrFind provides a mock function with given fields: ctx, m +func (_m *ManifestRepository) CreateOrFind(ctx context.Context, m *types.Manifest) error { + ret := _m.Called(ctx, m) + + if len(ret) == 0 { + panic("no return value specified for CreateOrFind") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) error); ok { + r0 = rf(ctx, m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Delete provides a mock function with given fields: ctx, registryID, id +func (_m *ManifestRepository) Delete(ctx context.Context, registryID int64, id int64) error { + ret := _m.Called(ctx, registryID, id) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok { + r0 = rf(ctx, registryID, id) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteManifest provides a mock function with given fields: ctx, repoID, imageName, d +func (_m *ManifestRepository) DeleteManifest(ctx context.Context, repoID int64, imageName string, d digest.Digest) (bool, error) { + ret := _m.Called(ctx, repoID, imageName, d) + + if len(ret) == 0 { + panic("no return value specified for DeleteManifest") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, digest.Digest) (bool, error)); ok { + return rf(ctx, repoID, imageName, d) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, digest.Digest) bool); ok { + r0 = rf(ctx, repoID, imageName, d) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, digest.Digest) error); ok { + r1 = rf(ctx, repoID, imageName, d) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DissociateLayerBlob provides a mock function with given fields: ctx, m, b +func (_m *ManifestRepository) DissociateLayerBlob(ctx context.Context, m *types.Manifest, b *types.Blob) error { + ret := _m.Called(ctx, m, b) + + if len(ret) == 0 { + panic("no return value specified for DissociateLayerBlob") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest, *types.Blob) error); ok { + r0 = rf(ctx, m, b) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FindAll provides a mock function with given fields: ctx +func (_m *ManifestRepository) FindAll(ctx context.Context) (types.Manifests, error) { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for FindAll") + } + + var r0 types.Manifests + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (types.Manifests, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) types.Manifests); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Manifests) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindManifestByDigest provides a mock function with given fields: ctx, repoID, imageName, _a3 +func (_m *ManifestRepository) FindManifestByDigest(ctx context.Context, repoID int64, imageName string, _a3 types.Digest) (*types.Manifest, error) { + ret := _m.Called(ctx, repoID, imageName, _a3) + + if len(ret) == 0 { + panic("no return value specified for FindManifestByDigest") + } + + var r0 *types.Manifest + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, types.Digest) (*types.Manifest, error)); ok { + return rf(ctx, repoID, imageName, _a3) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, types.Digest) *types.Manifest); ok { + r0 = rf(ctx, repoID, imageName, _a3) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Manifest) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, types.Digest) error); ok { + r1 = rf(ctx, repoID, imageName, _a3) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindManifestByTagName provides a mock function with given fields: ctx, repoID, imageName, tag +func (_m *ManifestRepository) FindManifestByTagName(ctx context.Context, repoID int64, imageName string, tag string) (*types.Manifest, error) { + ret := _m.Called(ctx, repoID, imageName, tag) + + if len(ret) == 0 { + panic("no return value specified for FindManifestByTagName") + } + + var r0 *types.Manifest + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.Manifest, error)); ok { + return rf(ctx, repoID, imageName, tag) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.Manifest); ok { + r0 = rf(ctx, repoID, imageName, tag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Manifest) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, repoID, imageName, tag) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindManifestPayloadByTagName provides a mock function with given fields: ctx, parentID, repoKey, imageName, version +func (_m *ManifestRepository) FindManifestPayloadByTagName(ctx context.Context, parentID int64, repoKey string, imageName string, version string) (*types.Payload, error) { + ret := _m.Called(ctx, parentID, repoKey, imageName, version) + + if len(ret) == 0 { + panic("no return value specified for FindManifestPayloadByTagName") + } + + var r0 *types.Payload + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) (*types.Payload, error)); ok { + return rf(ctx, parentID, repoKey, imageName, version) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) *types.Payload); ok { + r0 = rf(ctx, parentID, repoKey, imageName, version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Payload) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, imageName, version) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Get provides a mock function with given fields: ctx, manifestID +func (_m *ManifestRepository) Get(ctx context.Context, manifestID int64) (*types.Manifest, error) { + ret := _m.Called(ctx, manifestID) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *types.Manifest + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.Manifest, error)); ok { + return rf(ctx, manifestID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Manifest); ok { + r0 = rf(ctx, manifestID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Manifest) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, manifestID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetManifestPayload provides a mock function with given fields: ctx, parentID, repoKey, imageName, _a4 +func (_m *ManifestRepository) GetManifestPayload(ctx context.Context, parentID int64, repoKey string, imageName string, _a4 types.Digest) (*types.Payload, error) { + ret := _m.Called(ctx, parentID, repoKey, imageName, _a4) + + if len(ret) == 0 { + panic("no return value specified for GetManifestPayload") + } + + var r0 *types.Payload + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, types.Digest) (*types.Payload, error)); ok { + return rf(ctx, parentID, repoKey, imageName, _a4) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, types.Digest) *types.Payload); ok { + r0 = rf(ctx, parentID, repoKey, imageName, _a4) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Payload) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, types.Digest) error); ok { + r1 = rf(ctx, parentID, repoKey, imageName, _a4) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LayerBlobs provides a mock function with given fields: ctx, m +func (_m *ManifestRepository) LayerBlobs(ctx context.Context, m *types.Manifest) (types.Blobs, error) { + ret := _m.Called(ctx, m) + + if len(ret) == 0 { + panic("no return value specified for LayerBlobs") + } + + var r0 types.Blobs + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) (types.Blobs, error)); ok { + return rf(ctx, m) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) types.Blobs); ok { + r0 = rf(ctx, m) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Blobs) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.Manifest) error); ok { + r1 = rf(ctx, m) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListManifestsBySubject provides a mock function with given fields: ctx, repoID, id +func (_m *ManifestRepository) ListManifestsBySubject(ctx context.Context, repoID int64, id int64) (types.Manifests, error) { + ret := _m.Called(ctx, repoID, id) + + if len(ret) == 0 { + panic("no return value specified for ListManifestsBySubject") + } + + var r0 types.Manifests + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) (types.Manifests, error)); ok { + return rf(ctx, repoID, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) types.Manifests); ok { + r0 = rf(ctx, repoID, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Manifests) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, int64) error); ok { + r1 = rf(ctx, repoID, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListManifestsBySubjectDigest provides a mock function with given fields: ctx, repoID, _a2 +func (_m *ManifestRepository) ListManifestsBySubjectDigest(ctx context.Context, repoID int64, _a2 types.Digest) (types.Manifests, error) { + ret := _m.Called(ctx, repoID, _a2) + + if len(ret) == 0 { + panic("no return value specified for ListManifestsBySubjectDigest") + } + + var r0 types.Manifests + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, types.Digest) (types.Manifests, error)); ok { + return rf(ctx, repoID, _a2) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, types.Digest) types.Manifests); ok { + r0 = rf(ctx, repoID, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Manifests) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, types.Digest) error); ok { + r1 = rf(ctx, repoID, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// References provides a mock function with given fields: ctx, m +func (_m *ManifestRepository) References(ctx context.Context, m *types.Manifest) (types.Manifests, error) { + ret := _m.Called(ctx, m) + + if len(ret) == 0 { + panic("no return value specified for References") + } + + var r0 types.Manifests + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) (types.Manifests, error)); ok { + return rf(ctx, m) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.Manifest) types.Manifests); ok { + r0 = rf(ctx, m) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Manifests) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.Manifest) error); ok { + r1 = rf(ctx, m) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewManifestRepository creates a new instance of ManifestRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewManifestRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *ManifestRepository { + mock := &ManifestRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/registry_metadata_helper.go b/registry/app/api/controller/mocks/registry_metadata_helper.go new file mode 100644 index 000000000..89acfaa6d --- /dev/null +++ b/registry/app/api/controller/mocks/registry_metadata_helper.go @@ -0,0 +1,381 @@ +//go:generate mockery --name RegistryMetadataHelper --output . --filename registry_metadata_helper.go --outpkg mocks --with-expecter + +package mocks + +import ( + "context" + + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + registrytypes "github.com/harness/gitness/registry/types" + "github.com/harness/gitness/types" + "github.com/harness/gitness/types/enum" + + "github.com/stretchr/testify/mock" +) + +// RegistryMetadataHelper is an autogenerated mock type for the RegistryMetadataHelper type +type RegistryMetadataHelper struct { + mock.Mock +} + +// GetPermissionChecks provides a mock function with given fields: space, registryIdentifier, permission +func (_m *RegistryMetadataHelper) GetPermissionChecks(space *types.SpaceCore, registryIdentifier string, permission enum.Permission) []types.PermissionCheck { + ret := _m.Called(space, registryIdentifier, permission) + + if len(ret) == 0 { + panic("no return value specified for GetPermissionChecks") + } + + var r0 []types.PermissionCheck + if rf, ok := ret.Get(0).(func(*types.SpaceCore, string, enum.Permission) []types.PermissionCheck); ok { + r0 = rf(space, registryIdentifier, permission) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.PermissionCheck) + } + } + + return r0 +} + +// GetRegistryMetadata provides a mock function with given fields: ctx, registryID +func (_m *RegistryMetadataHelper) GetRegistryMetadata(ctx context.Context, registryID int64) (*registrytypes.Registry, error) { + ret := _m.Called(ctx, registryID) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryMetadata") + } + + var r0 *registrytypes.Registry + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*registrytypes.Registry, error)); ok { + return rf(ctx, registryID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *registrytypes.Registry); ok { + r0 = rf(ctx, registryID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.Registry) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, registryID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetRegistryMetadataByIdentifier provides a mock function with given fields: ctx, identifier +func (_m *RegistryMetadataHelper) GetRegistryMetadataByIdentifier(ctx context.Context, identifier string) (*registrytypes.Registry, error) { + ret := _m.Called(ctx, identifier) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryMetadataByIdentifier") + } + + var r0 *registrytypes.Registry + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*registrytypes.Registry, error)); ok { + return rf(ctx, identifier) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *registrytypes.Registry); ok { + r0 = rf(ctx, identifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.Registry) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, identifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetRegistryMetadataByParentIDAndIdentifier provides a mock function with given fields: ctx, parentID, identifier +func (_m *RegistryMetadataHelper) GetRegistryMetadataByParentIDAndIdentifier(ctx context.Context, parentID int64, identifier string) (*registrytypes.Registry, error) { + ret := _m.Called(ctx, parentID, identifier) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryMetadataByParentIDAndIdentifier") + } + + var r0 *registrytypes.Registry + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*registrytypes.Registry, error)); ok { + return rf(ctx, parentID, identifier) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *registrytypes.Registry); ok { + r0 = rf(ctx, parentID, identifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.Registry) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, parentID, identifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetRegistryMetadataByParentPathAndIdentifier provides a mock function with given fields: ctx, parentPath, identifier +func (_m *RegistryMetadataHelper) GetRegistryMetadataByParentPathAndIdentifier(ctx context.Context, parentPath string, identifier string) (*registrytypes.Registry, error) { + ret := _m.Called(ctx, parentPath, identifier) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryMetadataByParentPathAndIdentifier") + } + + var r0 *registrytypes.Registry + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*registrytypes.Registry, error)); ok { + return rf(ctx, parentPath, identifier) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) *registrytypes.Registry); ok { + r0 = rf(ctx, parentPath, identifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.Registry) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, parentPath, identifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetRegistryMetadataByPath provides a mock function with given fields: ctx, path +func (_m *RegistryMetadataHelper) GetRegistryMetadataByPath(ctx context.Context, path string) (*registrytypes.Registry, error) { + ret := _m.Called(ctx, path) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryMetadataByPath") + } + + var r0 *registrytypes.Registry + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*registrytypes.Registry, error)); ok { + return rf(ctx, path) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *registrytypes.Registry); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.Registry) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetRegistryRequestBaseInfo provides a mock function with given fields: ctx, parentPath, identifier +func (_m *RegistryMetadataHelper) GetRegistryRequestBaseInfo(ctx context.Context, parentPath string, identifier string) (*registrytypes.RegistryRequestBaseInfo, error) { + ret := _m.Called(ctx, parentPath, identifier) + + if len(ret) == 0 { + panic("no return value specified for GetRegistryRequestBaseInfo") + } + + var r0 *registrytypes.RegistryRequestBaseInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (*registrytypes.RegistryRequestBaseInfo, error)); ok { + return rf(ctx, parentPath, identifier) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) *registrytypes.RegistryRequestBaseInfo); ok { + r0 = rf(ctx, parentPath, identifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*registrytypes.RegistryRequestBaseInfo) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, parentPath, identifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetSecretSpaceID provides a mock function with given fields: ctx, secretSpacePath +func (_m *RegistryMetadataHelper) GetSecretSpaceID(ctx context.Context, secretSpacePath *string) (int64, error) { + ret := _m.Called(ctx, secretSpacePath) + + if len(ret) == 0 { + panic("no return value specified for GetSecretSpaceID") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *string) (int64, error)); ok { + return rf(ctx, secretSpacePath) + } + if rf, ok := ret.Get(0).(func(context.Context, *string) int64); ok { + r0 = rf(ctx, secretSpacePath) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *string) error); ok { + r1 = rf(ctx, secretSpacePath) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MapToAPIExtraHeaders provides a mock function with given fields: headers +func (_m *RegistryMetadataHelper) MapToAPIExtraHeaders(headers []types.ExtraHeader) []api.ExtraHeader { + ret := _m.Called(headers) + + if len(ret) == 0 { + panic("no return value specified for MapToAPIExtraHeaders") + } + + var r0 []api.ExtraHeader + if rf, ok := ret.Get(0).(func([]types.ExtraHeader) []api.ExtraHeader); ok { + r0 = rf(headers) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.ExtraHeader) + } + } + + return r0 +} + +// MapToAPIWebhookTriggers provides a mock function with given fields: triggers +func (_m *RegistryMetadataHelper) MapToAPIWebhookTriggers(triggers []enum.WebhookTrigger) []api.Trigger { + ret := _m.Called(triggers) + + if len(ret) == 0 { + panic("no return value specified for MapToAPIWebhookTriggers") + } + + var r0 []api.Trigger + if rf, ok := ret.Get(0).(func([]enum.WebhookTrigger) []api.Trigger); ok { + r0 = rf(triggers) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]api.Trigger) + } + } + + return r0 +} + +// MapToInternalWebhookTriggers provides a mock function with given fields: triggers +func (_m *RegistryMetadataHelper) MapToInternalWebhookTriggers(triggers []api.Trigger) []enum.WebhookTrigger { + ret := _m.Called(triggers) + + if len(ret) == 0 { + panic("no return value specified for MapToInternalWebhookTriggers") + } + + var r0 []enum.WebhookTrigger + if rf, ok := ret.Get(0).(func([]api.Trigger) []enum.WebhookTrigger); ok { + r0 = rf(triggers) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]enum.WebhookTrigger) + } + } + + return r0 +} + +// MapToWebhookCore provides a mock function with given fields: ctx, webhookRequest, regInfo +func (_m *RegistryMetadataHelper) MapToWebhookCore(ctx context.Context, webhookRequest api.WebhookRequest, regInfo *registrytypes.RegistryRequestBaseInfo) (*types.WebhookCore, error) { + ret := _m.Called(ctx, webhookRequest, regInfo) + + if len(ret) == 0 { + panic("no return value specified for MapToWebhookCore") + } + + var r0 *types.WebhookCore + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, api.WebhookRequest, *registrytypes.RegistryRequestBaseInfo) (*types.WebhookCore, error)); ok { + return rf(ctx, webhookRequest, regInfo) + } + if rf, ok := ret.Get(0).(func(context.Context, api.WebhookRequest, *registrytypes.RegistryRequestBaseInfo) *types.WebhookCore); ok { + r0 = rf(ctx, webhookRequest, regInfo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.WebhookCore) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, api.WebhookRequest, *registrytypes.RegistryRequestBaseInfo) error); ok { + r1 = rf(ctx, webhookRequest, regInfo) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MapToWebhookResponseEntity provides a mock function with given fields: ctx, webhook +func (_m *RegistryMetadataHelper) MapToWebhookResponseEntity(ctx context.Context, webhook *types.WebhookCore) (*api.Webhook, error) { + ret := _m.Called(ctx, webhook) + + if len(ret) == 0 { + panic("no return value specified for MapToWebhookResponseEntity") + } + + var r0 *api.Webhook + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.WebhookCore) (*api.Webhook, error)); ok { + return rf(ctx, webhook) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.WebhookCore) *api.Webhook); ok { + r0 = rf(ctx, webhook) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*api.Webhook) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.WebhookCore) error); ok { + r1 = rf(ctx, webhook) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewRegistryMetadataHelper creates a new instance of RegistryMetadataHelper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewRegistryMetadataHelper(t interface { + mock.TestingT + Cleanup(func()) +}) *RegistryMetadataHelper { + mock := &RegistryMetadataHelper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/registry_repository.go b/registry/app/api/controller/mocks/registry_repository.go new file mode 100644 index 000000000..172df3d99 --- /dev/null +++ b/registry/app/api/controller/mocks/registry_repository.go @@ -0,0 +1,292 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/registry/app/store" + "github.com/harness/gitness/registry/types" + + "github.com/stretchr/testify/mock" +) + +// FetchUpstreamProxyIDs provides a mock function +func (m *RegistryRepository) FetchUpstreamProxyIDs(ctx context.Context, repokeys []string, parentID int64) ([]int64, error) { + ret := m.Called(ctx, repokeys, parentID) + + var r0 []int64 + if rf, ok := ret.Get(0).(func(context.Context, []string, int64) []int64); ok { + r0 = rf(ctx, repokeys, parentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int64) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []string, int64) error); ok { + r1 = rf(ctx, repokeys, parentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RegistryRepository is a mock of RegistryRepository interface. +type RegistryRepository struct { + mock.Mock +} + +// GetAll provides a mock function +func (m *RegistryRepository) GetAll(ctx context.Context, parentID int64, packageTypes []string, sortByField string, sortByOrder string, limit int, offset int, search string, repoType string, recursive bool) (*[]store.RegistryMetadata, error) { + ret := m.Called(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search, repoType, recursive) + + var r0 *[]store.RegistryMetadata + if rf, ok := ret.Get(0).(func(context.Context, int64, []string, string, string, int, int, string, string, bool) *[]store.RegistryMetadata); ok { + r0 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search, repoType, recursive) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]store.RegistryMetadata) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, []string, string, string, int, int, string, string, bool) error); ok { + r1 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search, repoType, recursive) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FetchUpstreamProxyKeys provides a mock function +func (m *RegistryRepository) FetchUpstreamProxyKeys(ctx context.Context, ids []int64) ([]string, error) { + ret := m.Called(ctx, ids) + + var r0 []string + if rf, ok := ret.Get(0).(func(context.Context, []int64) []string); ok { + r0 = rf(ctx, ids) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []int64) error); ok { + r1 = rf(ctx, ids) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Get provides a mock function +func (m *RegistryRepository) Get(ctx context.Context, id int64) (*types.Registry, error) { + ret := m.Called(ctx, id) + + var r0 *types.Registry + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.Registry); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Registry) + } + } + + 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 +} + +// GetByIDIn provides a mock function +func (m *RegistryRepository) GetByIDIn(ctx context.Context, ids []int64) (*[]types.Registry, error) { + ret := m.Called(ctx, ids) + + var r0 *[]types.Registry + if rf, ok := ret.Get(0).(func(context.Context, []int64) *[]types.Registry); ok { + r0 = rf(ctx, ids) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.Registry) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []int64) error); ok { + r1 = rf(ctx, ids) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByParentIDAndName provides a mock function +func (m *RegistryRepository) GetByParentIDAndName(ctx context.Context, parentID int64, name string) (*types.Registry, error) { + ret := m.Called(ctx, parentID, name) + + var r0 *types.Registry + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Registry); ok { + r0 = rf(ctx, parentID, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Registry) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, parentID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByRootParentIDAndName provides a mock function +func (m *RegistryRepository) GetByRootParentIDAndName(ctx context.Context, parentID int64, name string) (*types.Registry, error) { + ret := m.Called(ctx, parentID, name) + + var r0 *types.Registry + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Registry); ok { + r0 = rf(ctx, parentID, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Registry) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, parentID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Create provides a mock function +func (m *RegistryRepository) Create(ctx context.Context, registry *types.Registry) (int64, error) { + ret := m.Called(ctx, registry) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, *types.Registry) int64); ok { + r0 = rf(ctx, registry) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.Registry) error); ok { + r1 = rf(ctx, registry) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function +func (m *RegistryRepository) Delete(ctx context.Context, parentID int64, name string) error { + ret := m.Called(ctx, parentID, name) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, parentID, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function +func (m *RegistryRepository) Update(ctx context.Context, registry *types.Registry) error { + ret := m.Called(ctx, registry) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Registry) error); ok { + r0 = rf(ctx, registry) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CountAll provides a mock function +func (m *RegistryRepository) CountAll(ctx context.Context, parentID int64, packageTypes []string, search string, repoType string) (int64, error) { + ret := m.Called(ctx, parentID, packageTypes, search, repoType) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, int64, []string, string, string) int64); ok { + r0 = rf(ctx, parentID, packageTypes, search, repoType) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, []string, string, string) error); ok { + r1 = rf(ctx, parentID, packageTypes, search, repoType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Count provides a mock function +func (m *RegistryRepository) Count(ctx context.Context) (int64, error) { + ret := m.Called(ctx) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context) int64); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(int64) + } + + 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 +} + +// FetchRegistriesIDByUpstreamProxyID provides a mock function +func (m *RegistryRepository) FetchRegistriesIDByUpstreamProxyID(ctx context.Context, upstreamProxyID string, rootParentID int64) ([]int64, error) { + ret := m.Called(ctx, upstreamProxyID, rootParentID) + + var r0 []int64 + if rf, ok := ret.Get(0).(func(context.Context, string, int64) []int64); ok { + r0 = rf(ctx, upstreamProxyID, rootParentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]int64) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok { + r1 = rf(ctx, upstreamProxyID, rootParentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/reporter.go b/registry/app/api/controller/mocks/reporter.go new file mode 100644 index 000000000..b81f5f543 --- /dev/null +++ b/registry/app/api/controller/mocks/reporter.go @@ -0,0 +1,34 @@ +package mocks + +import ( + "context" + + registryevents "github.com/harness/gitness/registry/app/events" + + "github.com/stretchr/testify/mock" +) + +// Reporter is a mock implementation of registryevents.Reporter +type Reporter struct { + mock.Mock +} + +func NewReporter() *Reporter { + return &Reporter{} +} + +// Report provides a mock function +func (m *Reporter) Report(ctx context.Context, event interface{}) error { + args := m.Called(ctx, event) + return args.Error(0) +} + +// ArtifactCreated provides a mock function +func (m *Reporter) ArtifactCreated(ctx context.Context, payload *registryevents.ArtifactCreatedPayload) { + m.Called(ctx, payload) +} + +// ArtifactDeleted provides a mock function +func (m *Reporter) ArtifactDeleted(ctx context.Context, payload *registryevents.ArtifactDeletedPayload) { + m.Called(ctx, payload) +} diff --git a/registry/app/api/controller/mocks/space_finder.go b/registry/app/api/controller/mocks/space_finder.go new file mode 100644 index 000000000..ee18b039a --- /dev/null +++ b/registry/app/api/controller/mocks/space_finder.go @@ -0,0 +1,130 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/types" + + "github.com/stretchr/testify/mock" +) + +// SpaceFinder is a mock of SpaceFinder interface. +type SpaceFinder struct { + mock.Mock +} + +// Find provides a mock function +func (m *SpaceFinder) Find(ctx context.Context, id int64) (*types.SpaceCore, error) { + ret := m.Called(ctx, id) + + var r0 *types.SpaceCore + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.SpaceCore); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpaceCore) + } + } + + 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 +} + +// FindByRef provides a mock function +func (m *SpaceFinder) FindByID(ctx context.Context, id int64) (*types.SpaceCore, error) { + ret := m.Called(ctx, id) + + var r0 *types.SpaceCore + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.SpaceCore); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpaceCore) + } + } + + 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 +} + +func (m *SpaceFinder) FindByRef(ctx context.Context, ref string) (*types.SpaceCore, error) { + ret := m.Called(ctx, ref) + + var r0 *types.SpaceCore + if rf, ok := ret.Get(0).(func(context.Context, string) *types.SpaceCore); ok { + r0 = rf(ctx, ref) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpaceCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, ref) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindByPath provides a mock function +func (m *SpaceFinder) FindByPath(ctx context.Context, path string) (*types.SpaceCore, error) { + ret := m.Called(ctx, path) + + var r0 *types.SpaceCore + if rf, ok := ret.Get(0).(func(context.Context, string) *types.SpaceCore); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpaceCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindByIdentifier provides a mock function +func (m *SpaceFinder) FindByIdentifier(ctx context.Context, identifier string) (*types.SpaceCore, error) { + ret := m.Called(ctx, identifier) + + var r0 *types.SpaceCore + if rf, ok := ret.Get(0).(func(context.Context, string) *types.SpaceCore); ok { + r0 = rf(ctx, identifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpaceCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, identifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/space_path_store.go b/registry/app/api/controller/mocks/space_path_store.go new file mode 100644 index 000000000..e8a307975 --- /dev/null +++ b/registry/app/api/controller/mocks/space_path_store.go @@ -0,0 +1,102 @@ +package mocks + +import ( + "context" + + "github.com/harness/gitness/types" + + "github.com/stretchr/testify/mock" +) + +// SpacePathStore is a mock of SpacePathStore interface. +type SpacePathStore struct { + mock.Mock +} + +// FindByPath provides a mock function +func (m *SpacePathStore) FindByPath(ctx context.Context, path string) (*types.SpacePath, error) { + ret := m.Called(ctx, path) + + var r0 *types.SpacePath + if rf, ok := ret.Get(0).(func(context.Context, string) *types.SpacePath); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpacePath) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FindPrimaryBySpaceID provides a mock function +func (m *SpacePathStore) FindPrimaryBySpaceID(ctx context.Context, spaceID int64) (*types.SpacePath, error) { + ret := m.Called(ctx, spaceID) + + var r0 *types.SpacePath + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.SpacePath); ok { + r0 = rf(ctx, spaceID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.SpacePath) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, spaceID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// InsertSegment provides a mock function +func (m *SpacePathStore) InsertSegment(ctx context.Context, segment *types.SpacePathSegment) error { + ret := m.Called(ctx, segment) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.SpacePathSegment) error); ok { + r0 = rf(ctx, segment) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeletePrimarySegment provides a mock function +func (m *SpacePathStore) DeletePrimarySegment(ctx context.Context, spaceID int64) error { + ret := m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeletePathsAndDescendandPaths provides a mock function +func (m *SpacePathStore) DeletePathsAndDescendandPaths(ctx context.Context, spaceID int64) error { + ret := m.Called(ctx, spaceID) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { + r0 = rf(ctx, spaceID) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/registry/app/api/controller/mocks/storage_driver.go b/registry/app/api/controller/mocks/storage_driver.go new file mode 100644 index 000000000..b21e66c9c --- /dev/null +++ b/registry/app/api/controller/mocks/storage_driver.go @@ -0,0 +1,306 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + io "io" + + driver "github.com/harness/gitness/registry/app/driver" + + mock "github.com/stretchr/testify/mock" +) + +// StorageDriver is an autogenerated mock type for the StorageDriver type +type StorageDriver struct { + mock.Mock +} + +// Delete provides a mock function with given fields: ctx, path +func (_m *StorageDriver) Delete(ctx context.Context, path string) error { + ret := _m.Called(ctx, path) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = rf(ctx, path) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetContent provides a mock function with given fields: ctx, path +func (_m *StorageDriver) GetContent(ctx context.Context, path string) ([]byte, error) { + ret := _m.Called(ctx, path) + + if len(ret) == 0 { + panic("no return value specified for GetContent") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]byte, error)); ok { + return rf(ctx, path) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// List provides a mock function with given fields: ctx, path +func (_m *StorageDriver) List(ctx context.Context, path string) ([]string, error) { + ret := _m.Called(ctx, path) + + if len(ret) == 0 { + panic("no return value specified for List") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) ([]string, error)); ok { + return rf(ctx, path) + } + if rf, ok := ret.Get(0).(func(context.Context, string) []string); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Move provides a mock function with given fields: ctx, sourcePath, destPath +func (_m *StorageDriver) Move(ctx context.Context, sourcePath string, destPath string) error { + ret := _m.Called(ctx, sourcePath, destPath) + + if len(ret) == 0 { + panic("no return value specified for Move") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, sourcePath, destPath) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Name provides a mock function with no fields +func (_m *StorageDriver) Name() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Name") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// PutContent provides a mock function with given fields: ctx, path, content +func (_m *StorageDriver) PutContent(ctx context.Context, path string, content []byte) error { + ret := _m.Called(ctx, path, content) + + if len(ret) == 0 { + panic("no return value specified for PutContent") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, []byte) error); ok { + r0 = rf(ctx, path, content) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Reader provides a mock function with given fields: ctx, path, offset +func (_m *StorageDriver) Reader(ctx context.Context, path string, offset int64) (io.ReadCloser, error) { + ret := _m.Called(ctx, path, offset) + + if len(ret) == 0 { + panic("no return value specified for Reader") + } + + var r0 io.ReadCloser + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, int64) (io.ReadCloser, error)); ok { + return rf(ctx, path, offset) + } + if rf, ok := ret.Get(0).(func(context.Context, string, int64) io.ReadCloser); ok { + r0 = rf(ctx, path, offset) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(io.ReadCloser) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok { + r1 = rf(ctx, path, offset) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RedirectURL provides a mock function with given fields: ctx, method, path +func (_m *StorageDriver) RedirectURL(ctx context.Context, method string, path string) (string, error) { + ret := _m.Called(ctx, method, path) + + if len(ret) == 0 { + panic("no return value specified for RedirectURL") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (string, error)); ok { + return rf(ctx, method, path) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { + r0 = rf(ctx, method, path) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, method, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Stat provides a mock function with given fields: ctx, path +func (_m *StorageDriver) Stat(ctx context.Context, path string) (driver.FileInfo, error) { + ret := _m.Called(ctx, path) + + if len(ret) == 0 { + panic("no return value specified for Stat") + } + + var r0 driver.FileInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (driver.FileInfo, error)); ok { + return rf(ctx, path) + } + if rf, ok := ret.Get(0).(func(context.Context, string) driver.FileInfo); ok { + r0 = rf(ctx, path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(driver.FileInfo) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Walk provides a mock function with given fields: ctx, path, f, options +func (_m *StorageDriver) Walk(ctx context.Context, path string, f driver.WalkFn, options ...func(*driver.WalkOptions)) error { + _va := make([]interface{}, len(options)) + for _i := range options { + _va[_i] = options[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, path, f) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for Walk") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, driver.WalkFn, ...func(*driver.WalkOptions)) error); ok { + r0 = rf(ctx, path, f, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Writer provides a mock function with given fields: ctx, path, a +func (_m *StorageDriver) Writer(ctx context.Context, path string, a bool) (driver.FileWriter, error) { + ret := _m.Called(ctx, path, a) + + if len(ret) == 0 { + panic("no return value specified for Writer") + } + + var r0 driver.FileWriter + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, bool) (driver.FileWriter, error)); ok { + return rf(ctx, path, a) + } + if rf, ok := ret.Get(0).(func(context.Context, string, bool) driver.FileWriter); ok { + r0 = rf(ctx, path, a) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(driver.FileWriter) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok { + r1 = rf(ctx, path, a) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewStorageDriver creates a new instance of StorageDriver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewStorageDriver(t interface { + mock.TestingT + Cleanup(func()) +}) *StorageDriver { + mock := &StorageDriver{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/stream_producer.go b/registry/app/api/controller/mocks/stream_producer.go new file mode 100644 index 000000000..d4f5509b3 --- /dev/null +++ b/registry/app/api/controller/mocks/stream_producer.go @@ -0,0 +1,49 @@ +// Code generated by mockery v2.20.0. DO NOT EDIT. + +package mocks + +import ( + "context" + + mock "github.com/stretchr/testify/mock" +) + +// StreamProducer is an autogenerated mock type for the StreamProducer type +type StreamProducer struct { + mock.Mock +} + +// Send provides a mock function with given fields: ctx, topic, payload +func (m *StreamProducer) Send(ctx context.Context, topic string, payload map[string]interface{}) (string, error) { + ret := m.Called(ctx, topic, payload) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, map[string]interface{}) string); ok { + r0 = rf(ctx, topic, payload) + } else { + r0 = ret.Get(0).(string) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, map[string]interface{}) error); ok { + r1 = rf(ctx, topic, payload) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Close provides a mock function with given fields: +func (m *StreamProducer) Close() error { + ret := m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/registry/app/api/controller/mocks/tag_repository.go b/registry/app/api/controller/mocks/tag_repository.go new file mode 100644 index 000000000..793d7fe42 --- /dev/null +++ b/registry/app/api/controller/mocks/tag_repository.go @@ -0,0 +1,578 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// TagRepository is an autogenerated mock type for the TagRepository type +type TagRepository struct { + mock.Mock +} + +// CountAllArtifactsByParentID provides a mock function with given fields: ctx, parentID, registryIDs, search, latestVersion, packageTypes +func (_m *TagRepository) CountAllArtifactsByParentID(ctx context.Context, parentID int64, registryIDs *[]string, search string, latestVersion bool, packageTypes []string) (int64, error) { + ret := _m.Called(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + + if len(ret) == 0 { + panic("no return value specified for CountAllArtifactsByParentID") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, bool, []string) (int64, error)); ok { + return rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, bool, []string) int64); ok { + r0 = rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, *[]string, string, bool, []string) error); ok { + r1 = rf(ctx, parentID, registryIDs, search, latestVersion, packageTypes) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllArtifactsByRepo provides a mock function with given fields: ctx, parentID, repoKey, search, labels +func (_m *TagRepository) CountAllArtifactsByRepo(ctx context.Context, parentID int64, repoKey string, search string, labels []string) (int64, error) { + ret := _m.Called(ctx, parentID, repoKey, search, labels) + + if len(ret) == 0 { + panic("no return value specified for CountAllArtifactsByRepo") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, []string) (int64, error)); ok { + return rf(ctx, parentID, repoKey, search, labels) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, []string) int64); ok { + r0 = rf(ctx, parentID, repoKey, search, labels) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, []string) error); ok { + r1 = rf(ctx, parentID, repoKey, search, labels) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllTagsByRepoAndImage provides a mock function with given fields: ctx, parentID, repoKey, image, search +func (_m *TagRepository) CountAllTagsByRepoAndImage(ctx context.Context, parentID int64, repoKey string, image string, search string) (int64, error) { + ret := _m.Called(ctx, parentID, repoKey, image, search) + + if len(ret) == 0 { + panic("no return value specified for CountAllTagsByRepoAndImage") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) (int64, error)); ok { + return rf(ctx, parentID, repoKey, image, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) int64); ok { + r0 = rf(ctx, parentID, repoKey, image, search) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, image, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CreateOrUpdate provides a mock function with given fields: ctx, t +func (_m *TagRepository) CreateOrUpdate(ctx context.Context, t *types.Tag) error { + ret := _m.Called(ctx, t) + + if len(ret) == 0 { + panic("no return value specified for CreateOrUpdate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.Tag) error); ok { + r0 = rf(ctx, t) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteTag provides a mock function with given fields: ctx, registryID, imageName, name +func (_m *TagRepository) DeleteTag(ctx context.Context, registryID int64, imageName string, name string) error { + ret := _m.Called(ctx, registryID, imageName, name) + + if len(ret) == 0 { + panic("no return value specified for DeleteTag") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) error); ok { + r0 = rf(ctx, registryID, imageName, name) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteTagByManifestID provides a mock function with given fields: ctx, repoID, manifestID +func (_m *TagRepository) DeleteTagByManifestID(ctx context.Context, repoID int64, manifestID int64) (bool, error) { + ret := _m.Called(ctx, repoID, manifestID) + + if len(ret) == 0 { + panic("no return value specified for DeleteTagByManifestID") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) (bool, error)); ok { + return rf(ctx, repoID, manifestID) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, int64) bool); ok { + r0 = rf(ctx, repoID, manifestID) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, int64) error); ok { + r1 = rf(ctx, repoID, manifestID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteTagByName provides a mock function with given fields: ctx, repoID, name +func (_m *TagRepository) DeleteTagByName(ctx context.Context, repoID int64, name string) (bool, error) { + ret := _m.Called(ctx, repoID, name) + + if len(ret) == 0 { + panic("no return value specified for DeleteTagByName") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (bool, error)); ok { + return rf(ctx, repoID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) bool); ok { + r0 = rf(ctx, repoID, name) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, repoID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// DeleteTagsByImageName provides a mock function with given fields: ctx, registryID, imageName +func (_m *TagRepository) DeleteTagsByImageName(ctx context.Context, registryID int64, imageName string) error { + ret := _m.Called(ctx, registryID, imageName) + + if len(ret) == 0 { + panic("no return value specified for DeleteTagsByImageName") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, registryID, imageName) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// FindTag provides a mock function with given fields: ctx, repoID, imageName, name +func (_m *TagRepository) FindTag(ctx context.Context, repoID int64, imageName string, name string) (*types.Tag, error) { + ret := _m.Called(ctx, repoID, imageName, name) + + if len(ret) == 0 { + panic("no return value specified for FindTag") + } + + var r0 *types.Tag + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.Tag, error)); ok { + return rf(ctx, repoID, imageName, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.Tag); ok { + r0 = rf(ctx, repoID, imageName, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Tag) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, repoID, imageName, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllArtifactsByParentID provides a mock function with given fields: ctx, parentID, registryIDs, sortByField, sortByOrder, limit, offset, search, latestVersion, packageTypes +func (_m *TagRepository) GetAllArtifactsByParentID(ctx context.Context, parentID int64, registryIDs *[]string, sortByField string, sortByOrder string, limit int, offset int, search string, latestVersion bool, packageTypes []string) (*[]types.ArtifactMetadata, error) { + ret := _m.Called(ctx, parentID, registryIDs, sortByField, sortByOrder, limit, offset, search, latestVersion, packageTypes) + + if len(ret) == 0 { + panic("no return value specified for GetAllArtifactsByParentID") + } + + var r0 *[]types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) (*[]types.ArtifactMetadata, error)); ok { + return rf(ctx, parentID, registryIDs, sortByField, sortByOrder, limit, offset, search, latestVersion, packageTypes) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) *[]types.ArtifactMetadata); ok { + r0 = rf(ctx, parentID, registryIDs, sortByField, sortByOrder, limit, offset, search, latestVersion, packageTypes) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, *[]string, string, string, int, int, string, bool, []string) error); ok { + r1 = rf(ctx, parentID, registryIDs, sortByField, sortByOrder, limit, offset, search, latestVersion, packageTypes) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllArtifactsByRepo provides a mock function with given fields: ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels +func (_m *TagRepository) GetAllArtifactsByRepo(ctx context.Context, parentID int64, repoKey string, sortByField string, sortByOrder string, limit int, offset int, search string, labels []string) (*[]types.ArtifactMetadata, error) { + ret := _m.Called(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + + if len(ret) == 0 { + panic("no return value specified for GetAllArtifactsByRepo") + } + + var r0 *[]types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, int, int, string, []string) (*[]types.ArtifactMetadata, error)); ok { + return rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, int, int, string, []string) *[]types.ArtifactMetadata); ok { + r0 = rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string, int, int, string, []string) error); ok { + r1 = rf(ctx, parentID, repoKey, sortByField, sortByOrder, limit, offset, search, labels) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAllTagsByRepoAndImage provides a mock function with given fields: ctx, parentID, repoKey, image, sortByField, sortByOrder, limit, offset, search +func (_m *TagRepository) GetAllTagsByRepoAndImage(ctx context.Context, parentID int64, repoKey string, image string, sortByField string, sortByOrder string, limit int, offset int, search string) (*[]types.TagMetadata, error) { + ret := _m.Called(ctx, parentID, repoKey, image, sortByField, sortByOrder, limit, offset, search) + + if len(ret) == 0 { + panic("no return value specified for GetAllTagsByRepoAndImage") + } + + var r0 *[]types.TagMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, string, int, int, string) (*[]types.TagMetadata, error)); ok { + return rf(ctx, parentID, repoKey, image, sortByField, sortByOrder, limit, offset, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string, string, int, int, string) *[]types.TagMetadata); ok { + r0 = rf(ctx, parentID, repoKey, image, sortByField, sortByOrder, limit, offset, search) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.TagMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string, string, int, int, string) error); ok { + r1 = rf(ctx, parentID, repoKey, image, sortByField, sortByOrder, limit, offset, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLatestTag provides a mock function with given fields: ctx, repoID, imageName +func (_m *TagRepository) GetLatestTag(ctx context.Context, repoID int64, imageName string) (*types.Tag, error) { + ret := _m.Called(ctx, repoID, imageName) + + if len(ret) == 0 { + panic("no return value specified for GetLatestTag") + } + + var r0 *types.Tag + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*types.Tag, error)); ok { + return rf(ctx, repoID, imageName) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.Tag); ok { + r0 = rf(ctx, repoID, imageName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Tag) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, repoID, imageName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLatestTagMetadata provides a mock function with given fields: ctx, parentID, repoKey, imageName +func (_m *TagRepository) GetLatestTagMetadata(ctx context.Context, parentID int64, repoKey string, imageName string) (*types.ArtifactMetadata, error) { + ret := _m.Called(ctx, parentID, repoKey, imageName) + + if len(ret) == 0 { + panic("no return value specified for GetLatestTagMetadata") + } + + var r0 *types.ArtifactMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.ArtifactMetadata, error)); ok { + return rf(ctx, parentID, repoKey, imageName) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.ArtifactMetadata); ok { + r0 = rf(ctx, parentID, repoKey, imageName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.ArtifactMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, imageName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetLatestTagName provides a mock function with given fields: ctx, parentID, repoKey, imageName +func (_m *TagRepository) GetLatestTagName(ctx context.Context, parentID int64, repoKey string, imageName string) (string, error) { + ret := _m.Called(ctx, parentID, repoKey, imageName) + + if len(ret) == 0 { + panic("no return value specified for GetLatestTagName") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (string, error)); ok { + return rf(ctx, parentID, repoKey, imageName) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) string); ok { + r0 = rf(ctx, parentID, repoKey, imageName) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, imageName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetTagDetail provides a mock function with given fields: ctx, repoID, imageName, name +func (_m *TagRepository) GetTagDetail(ctx context.Context, repoID int64, imageName string, name string) (*types.TagDetail, error) { + ret := _m.Called(ctx, repoID, imageName, name) + + if len(ret) == 0 { + panic("no return value specified for GetTagDetail") + } + + var r0 *types.TagDetail + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) (*types.TagDetail, error)); ok { + return rf(ctx, repoID, imageName, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string) *types.TagDetail); ok { + r0 = rf(ctx, repoID, imageName, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.TagDetail) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string) error); ok { + r1 = rf(ctx, repoID, imageName, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetTagMetadata provides a mock function with given fields: ctx, parentID, repoKey, imageName, name +func (_m *TagRepository) GetTagMetadata(ctx context.Context, parentID int64, repoKey string, imageName string, name string) (*types.TagMetadata, error) { + ret := _m.Called(ctx, parentID, repoKey, imageName, name) + + if len(ret) == 0 { + panic("no return value specified for GetTagMetadata") + } + + var r0 *types.TagMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) (*types.TagMetadata, error)); ok { + return rf(ctx, parentID, repoKey, imageName, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, string, string) *types.TagMetadata); ok { + r0 = rf(ctx, parentID, repoKey, imageName, name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.TagMetadata) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, string, string) error); ok { + r1 = rf(ctx, parentID, repoKey, imageName, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HasTagsAfterName provides a mock function with given fields: ctx, repoID, filters +func (_m *TagRepository) HasTagsAfterName(ctx context.Context, repoID int64, filters types.FilterParams) (bool, error) { + ret := _m.Called(ctx, repoID, filters) + + if len(ret) == 0 { + panic("no return value specified for HasTagsAfterName") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, types.FilterParams) (bool, error)); ok { + return rf(ctx, repoID, filters) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, types.FilterParams) bool); ok { + r0 = rf(ctx, repoID, filters) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, types.FilterParams) error); ok { + r1 = rf(ctx, repoID, filters) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LockTagByNameForUpdate provides a mock function with given fields: ctx, repoID, name +func (_m *TagRepository) LockTagByNameForUpdate(ctx context.Context, repoID int64, name string) (bool, error) { + ret := _m.Called(ctx, repoID, name) + + if len(ret) == 0 { + panic("no return value specified for LockTagByNameForUpdate") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (bool, error)); ok { + return rf(ctx, repoID, name) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) bool); ok { + r0 = rf(ctx, repoID, name) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, repoID, name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TagsPaginated provides a mock function with given fields: ctx, repoID, image, filters +func (_m *TagRepository) TagsPaginated(ctx context.Context, repoID int64, image string, filters types.FilterParams) ([]*types.Tag, error) { + ret := _m.Called(ctx, repoID, image, filters) + + if len(ret) == 0 { + panic("no return value specified for TagsPaginated") + } + + var r0 []*types.Tag + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string, types.FilterParams) ([]*types.Tag, error)); ok { + return rf(ctx, repoID, image, filters) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string, types.FilterParams) []*types.Tag); ok { + r0 = rf(ctx, repoID, image, filters) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.Tag) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string, types.FilterParams) error); ok { + r1 = rf(ctx, repoID, image, filters) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewTagRepository creates a new instance of TagRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewTagRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *TagRepository { + mock := &TagRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/transaction.go b/registry/app/api/controller/mocks/transaction.go new file mode 100644 index 000000000..ffc4037b6 --- /dev/null +++ b/registry/app/api/controller/mocks/transaction.go @@ -0,0 +1,33 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/stretchr/testify/mock" +) + +// Transaction is an autogenerated mock type for the Transaction type +type Transaction struct { + mock.Mock +} + +// WithTx provides a mock function with given fields: ctx, fn, options +func (m *Transaction) WithTx(ctx context.Context, fn func(context.Context) error, options ...interface{}) error { + var args []interface{} + args = append(args, ctx, fn) + for _, opt := range options { + args = append(args, opt) + } + ret := m.Called(args...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, func(context.Context) error, ...interface{}) error); ok { + r0 = rf(ctx, fn, options...) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/registry/app/api/controller/mocks/transactor.go b/registry/app/api/controller/mocks/transactor.go new file mode 100644 index 000000000..08bc477d4 --- /dev/null +++ b/registry/app/api/controller/mocks/transactor.go @@ -0,0 +1,38 @@ +// Code generated by mockery. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/stretchr/testify/mock" +) + +// Transactor is a mock of dbtx.Transactor interface. +type Transactor struct { + mock.Mock +} + +// WithTx provides a mock function +func (m *Transactor) WithTx(ctx context.Context, fn func(context.Context) error, opts ...interface{}) error { + args := m.Called(ctx, fn, opts) + return args.Error(0) +} + +// BeginTx provides a mock function +func (m *Transactor) BeginTx(ctx context.Context) (context.Context, error) { + args := m.Called(ctx) + return args.Get(0).(context.Context), args.Error(1) +} + +// CommitTx provides a mock function +func (m *Transactor) CommitTx(ctx context.Context) error { + args := m.Called(ctx) + return args.Error(0) +} + +// RollbackTx provides a mock function +func (m *Transactor) RollbackTx(ctx context.Context) error { + args := m.Called(ctx) + return args.Error(0) +} diff --git a/registry/app/api/controller/mocks/upstream_proxy_config_repository.go b/registry/app/api/controller/mocks/upstream_proxy_config_repository.go new file mode 100644 index 000000000..0674b3c13 --- /dev/null +++ b/registry/app/api/controller/mocks/upstream_proxy_config_repository.go @@ -0,0 +1,242 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + types "github.com/harness/gitness/registry/types" + + mock "github.com/stretchr/testify/mock" +) + +// UpstreamProxyConfigRepository is an autogenerated mock type for the UpstreamProxyConfigRepository type +type UpstreamProxyConfigRepository struct { + mock.Mock +} + +// CountAll provides a mock function with given fields: ctx, parentID, packageTypes, search +func (_m *UpstreamProxyConfigRepository) CountAll(ctx context.Context, parentID string, packageTypes []string, search string) (int64, error) { + ret := _m.Called(ctx, parentID, packageTypes, search) + + if len(ret) == 0 { + panic("no return value specified for CountAll") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, []string, string) (int64, error)); ok { + return rf(ctx, parentID, packageTypes, search) + } + if rf, ok := ret.Get(0).(func(context.Context, string, []string, string) int64); ok { + r0 = rf(ctx, parentID, packageTypes, search) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, []string, string) error); ok { + r1 = rf(ctx, parentID, packageTypes, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Create provides a mock function with given fields: ctx, upstreamproxyRecord +func (_m *UpstreamProxyConfigRepository) Create(ctx context.Context, upstreamproxyRecord *types.UpstreamProxyConfig) (int64, error) { + ret := _m.Called(ctx, upstreamproxyRecord) + + if len(ret) == 0 { + panic("no return value specified for Create") + } + + var r0 int64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *types.UpstreamProxyConfig) (int64, error)); ok { + return rf(ctx, upstreamproxyRecord) + } + if rf, ok := ret.Get(0).(func(context.Context, *types.UpstreamProxyConfig) int64); ok { + r0 = rf(ctx, upstreamproxyRecord) + } else { + r0 = ret.Get(0).(int64) + } + + if rf, ok := ret.Get(1).(func(context.Context, *types.UpstreamProxyConfig) error); ok { + r1 = rf(ctx, upstreamproxyRecord) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, parentID, repoKey +func (_m *UpstreamProxyConfigRepository) Delete(ctx context.Context, parentID int64, repoKey string) error { + ret := _m.Called(ctx, parentID, repoKey) + + if len(ret) == 0 { + panic("no return value specified for Delete") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, parentID, repoKey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Get provides a mock function with given fields: ctx, id +func (_m *UpstreamProxyConfigRepository) Get(ctx context.Context, id int64) (*types.UpstreamProxy, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *types.UpstreamProxy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64) (*types.UpstreamProxy, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.UpstreamProxy); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.UpstreamProxy) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetAll provides a mock function with given fields: ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search +func (_m *UpstreamProxyConfigRepository) GetAll(ctx context.Context, parentID int64, packageTypes []string, sortByField string, sortByOrder string, limit int, offset int, search string) (*[]types.UpstreamProxy, error) { + ret := _m.Called(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + + var r0 *[]types.UpstreamProxy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, []string, string, string, int, int, string) (*[]types.UpstreamProxy, error)); ok { + return rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, []string, string, string, int, int, string) *[]types.UpstreamProxy); ok { + r0 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.UpstreamProxy) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, []string, string, string, int, int, string) error); ok { + r1 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByParentID provides a mock function with given fields: ctx, parentID +func (_m *UpstreamProxyConfigRepository) GetByParentID(ctx context.Context, parentID string) (*[]types.UpstreamProxy, error) { + ret := _m.Called(ctx, parentID) + + if len(ret) == 0 { + panic("no return value specified for GetByParentID") + } + + var r0 *[]types.UpstreamProxy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*[]types.UpstreamProxy, error)); ok { + return rf(ctx, parentID) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *[]types.UpstreamProxy); ok { + r0 = rf(ctx, parentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.UpstreamProxy) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, parentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByRegistryIdentifier provides a mock function with given fields: ctx, parentID, repoKey +func (_m *UpstreamProxyConfigRepository) GetByRegistryIdentifier(ctx context.Context, parentID int64, repoKey string) (*types.UpstreamProxy, error) { + ret := _m.Called(ctx, parentID, repoKey) + + if len(ret) == 0 { + panic("no return value specified for GetByRegistryIdentifier") + } + + var r0 *types.UpstreamProxy + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*types.UpstreamProxy, error)); ok { + return rf(ctx, parentID, repoKey) + } + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.UpstreamProxy); ok { + r0 = rf(ctx, parentID, repoKey) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.UpstreamProxy) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, parentID, repoKey) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Update provides a mock function with given fields: ctx, upstreamproxyRecord +func (_m *UpstreamProxyConfigRepository) Update(ctx context.Context, upstreamproxyRecord *types.UpstreamProxyConfig) error { + ret := _m.Called(ctx, upstreamproxyRecord) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.UpstreamProxyConfig) error); ok { + r0 = rf(ctx, upstreamproxyRecord) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// NewUpstreamProxyConfigRepository creates a new instance of UpstreamProxyConfigRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewUpstreamProxyConfigRepository(t interface { + mock.TestingT + Cleanup(func()) +}) *UpstreamProxyConfigRepository { + mock := &UpstreamProxyConfigRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/upstream_proxy_store.go b/registry/app/api/controller/mocks/upstream_proxy_store.go new file mode 100644 index 000000000..46776db49 --- /dev/null +++ b/registry/app/api/controller/mocks/upstream_proxy_store.go @@ -0,0 +1,176 @@ +package mocks + +import ( + "context" + + "github.com/harness/gitness/registry/types" + + "github.com/stretchr/testify/mock" +) + +// UpstreamProxyStore is an autogenerated mock type for the UpstreamProxyConfigRepository type +type UpstreamProxyStore struct { + mock.Mock +} + +// Get provides a mock function with given fields: ctx, id +func (m *UpstreamProxyStore) Get(ctx context.Context, id int64) (*types.UpstreamProxy, error) { + ret := m.Called(ctx, id) + + var r0 *types.UpstreamProxy + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.UpstreamProxy); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.UpstreamProxy) + } + } + + 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 +} + +// GetByRegistryIdentifier provides a mock function with given fields: ctx, parentID, repoKey +func (m *UpstreamProxyStore) GetByRegistryIdentifier(ctx context.Context, parentID int64, repoKey string) (*types.UpstreamProxy, error) { + ret := m.Called(ctx, parentID, repoKey) + + var r0 *types.UpstreamProxy + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.UpstreamProxy); ok { + r0 = rf(ctx, parentID, repoKey) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.UpstreamProxy) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, parentID, repoKey) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetByParentID provides a mock function with given fields: ctx, parentID +func (m *UpstreamProxyStore) GetByParentID(ctx context.Context, parentID string) (*[]types.UpstreamProxy, error) { + ret := m.Called(ctx, parentID) + + var r0 *[]types.UpstreamProxy + if rf, ok := ret.Get(0).(func(context.Context, string) *[]types.UpstreamProxy); ok { + r0 = rf(ctx, parentID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.UpstreamProxy) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, parentID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Create provides a mock function with given fields: ctx, upstreamproxyRecord +func (m *UpstreamProxyStore) Create(ctx context.Context, upstreamproxyRecord *types.UpstreamProxyConfig) (int64, error) { + ret := m.Called(ctx, upstreamproxyRecord) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, *types.UpstreamProxyConfig) int64); ok { + r0 = rf(ctx, upstreamproxyRecord) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.UpstreamProxyConfig) error); ok { + r1 = rf(ctx, upstreamproxyRecord) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Delete provides a mock function with given fields: ctx, parentID, repoKey +func (m *UpstreamProxyStore) Delete(ctx context.Context, parentID int64, repoKey string) error { + ret := m.Called(ctx, parentID, repoKey) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { + r0 = rf(ctx, parentID, repoKey) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Update provides a mock function with given fields: ctx, upstreamproxyRecord +func (m *UpstreamProxyStore) Update(ctx context.Context, upstreamproxyRecord *types.UpstreamProxyConfig) error { + ret := m.Called(ctx, upstreamproxyRecord) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *types.UpstreamProxyConfig) error); ok { + r0 = rf(ctx, upstreamproxyRecord) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetAll provides a mock function with given fields: ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search +func (m *UpstreamProxyStore) GetAll(ctx context.Context, parentID int64, packageTypes []string, sortByField string, sortByOrder string, limit int, offset int, search string) (*[]types.UpstreamProxy, error) { + ret := m.Called(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + + var r0 *[]types.UpstreamProxy + if rf, ok := ret.Get(0).(func(context.Context, int64, []string, string, string, int, int, string) *[]types.UpstreamProxy); ok { + r0 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*[]types.UpstreamProxy) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, []string, string, string, int, int, string) error); ok { + r1 = rf(ctx, parentID, packageTypes, sortByField, sortByOrder, limit, offset, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAll provides a mock function with given fields: ctx, parentID, packageTypes, search +func (m *UpstreamProxyStore) CountAll(ctx context.Context, parentID string, packageTypes []string, search string) (int64, error) { + ret := m.Called(ctx, parentID, packageTypes, search) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, string, []string, string) int64); ok { + r0 = rf(ctx, parentID, packageTypes, search) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, []string, string) error); ok { + r1 = rf(ctx, parentID, packageTypes, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/url_provider.go b/registry/app/api/controller/mocks/url_provider.go new file mode 100644 index 000000000..dfbb215c1 --- /dev/null +++ b/registry/app/api/controller/mocks/url_provider.go @@ -0,0 +1,337 @@ +// Code generated by mockery v2.53.3. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// Provider is an autogenerated mock type for the Provider type +type Provider struct { + mock.Mock +} + +// GenerateContainerGITCloneURL provides a mock function with given fields: ctx, repoPath +func (_m *Provider) GenerateContainerGITCloneURL(ctx context.Context, repoPath string) string { + ret := _m.Called(ctx, repoPath) + + if len(ret) == 0 { + panic("no return value specified for GenerateContainerGITCloneURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, repoPath) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateGITCloneSSHURL provides a mock function with given fields: ctx, repoPath +func (_m *Provider) GenerateGITCloneSSHURL(ctx context.Context, repoPath string) string { + ret := _m.Called(ctx, repoPath) + + if len(ret) == 0 { + panic("no return value specified for GenerateGITCloneSSHURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, repoPath) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateGITCloneURL provides a mock function with given fields: ctx, repoPath +func (_m *Provider) GenerateGITCloneURL(ctx context.Context, repoPath string) string { + ret := _m.Called(ctx, repoPath) + + if len(ret) == 0 { + panic("no return value specified for GenerateGITCloneURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, repoPath) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUIBuildURL provides a mock function with given fields: ctx, repoPath, pipelineIdentifier, seqNumber +func (_m *Provider) GenerateUIBuildURL(ctx context.Context, repoPath string, pipelineIdentifier string, seqNumber int64) string { + ret := _m.Called(ctx, repoPath, pipelineIdentifier, seqNumber) + + if len(ret) == 0 { + panic("no return value specified for GenerateUIBuildURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string, int64) string); ok { + r0 = rf(ctx, repoPath, pipelineIdentifier, seqNumber) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUICompareURL provides a mock function with given fields: ctx, repoPath, ref1, ref2 +func (_m *Provider) GenerateUICompareURL(ctx context.Context, repoPath string, ref1 string, ref2 string) string { + ret := _m.Called(ctx, repoPath, ref1, ref2) + + if len(ret) == 0 { + panic("no return value specified for GenerateUICompareURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) string); ok { + r0 = rf(ctx, repoPath, ref1, ref2) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUIPRURL provides a mock function with given fields: ctx, repoPath, prID +func (_m *Provider) GenerateUIPRURL(ctx context.Context, repoPath string, prID int64) string { + ret := _m.Called(ctx, repoPath, prID) + + if len(ret) == 0 { + panic("no return value specified for GenerateUIPRURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, int64) string); ok { + r0 = rf(ctx, repoPath, prID) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUIRefURL provides a mock function with given fields: ctx, repoPath, ref +func (_m *Provider) GenerateUIRefURL(ctx context.Context, repoPath string, ref string) string { + ret := _m.Called(ctx, repoPath, ref) + + if len(ret) == 0 { + panic("no return value specified for GenerateUIRefURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { + r0 = rf(ctx, repoPath, ref) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUIRegistryURL provides a mock function with given fields: ctx, parentSpacePath, registryName +func (_m *Provider) GenerateUIRegistryURL(ctx context.Context, parentSpacePath string, registryName string) string { + ret := _m.Called(ctx, parentSpacePath, registryName) + + if len(ret) == 0 { + panic("no return value specified for GenerateUIRegistryURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok { + r0 = rf(ctx, parentSpacePath, registryName) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GenerateUIRepoURL provides a mock function with given fields: ctx, repoPath +func (_m *Provider) GenerateUIRepoURL(ctx context.Context, repoPath string) string { + ret := _m.Called(ctx, repoPath) + + if len(ret) == 0 { + panic("no return value specified for GenerateUIRepoURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string) string); ok { + r0 = rf(ctx, repoPath) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetAPIHostname provides a mock function with given fields: ctx +func (_m *Provider) GetAPIHostname(ctx context.Context) string { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAPIHostname") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetAPIProto provides a mock function with given fields: ctx +func (_m *Provider) GetAPIProto(ctx context.Context) string { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAPIProto") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetGITHostname provides a mock function with given fields: ctx +func (_m *Provider) GetGITHostname(ctx context.Context) string { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetGITHostname") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetInternalAPIURL provides a mock function with given fields: ctx +func (_m *Provider) GetInternalAPIURL(ctx context.Context) string { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetInternalAPIURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// GetUIBaseURL provides a mock function with given fields: ctx, params +func (_m *Provider) GetUIBaseURL(ctx context.Context, params ...string) string { + _va := make([]interface{}, len(params)) + for _i := range params { + _va[_i] = params[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetUIBaseURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, ...string) string); ok { + r0 = rf(ctx, params...) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// PackageURL provides a mock function with given fields: ctx, regRef, pkgType, params +func (_m *Provider) PackageURL(ctx context.Context, regRef string, pkgType string, params ...string) string { + _va := make([]interface{}, len(params)) + for _i := range params { + _va[_i] = params[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, regRef, pkgType) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for PackageURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string, ...string) string); ok { + r0 = rf(ctx, regRef, pkgType, params...) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// RegistryURL provides a mock function with given fields: ctx, params +func (_m *Provider) RegistryURL(ctx context.Context, params ...string) string { + _va := make([]interface{}, len(params)) + for _i := range params { + _va[_i] = params[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RegistryURL") + } + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, ...string) string); ok { + r0 = rf(ctx, params...) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// NewProvider creates a new instance of Provider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProvider(t interface { + mock.TestingT + Cleanup(func()) +}) *Provider { + mock := &Provider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/registry/app/api/controller/mocks/webhook_service.go b/registry/app/api/controller/mocks/webhook_service.go new file mode 100644 index 000000000..8d9cf5f6a --- /dev/null +++ b/registry/app/api/controller/mocks/webhook_service.go @@ -0,0 +1,39 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + gitnesswebhook "github.com/harness/gitness/app/services/webhook" + + "github.com/stretchr/testify/mock" +) + +// WebhookService is a mock of WebhookService interface. +type WebhookService struct { + mock.Mock +} + +// ReTriggerWebhookExecution provides a mock function +func (m *WebhookService) ReTriggerWebhookExecution(ctx context.Context, webhookExecutionID int64) (*gitnesswebhook.TriggerResult, error) { + ret := m.Called(ctx, webhookExecutionID) + + var r0 *gitnesswebhook.TriggerResult + if rf, ok := ret.Get(0).(func(context.Context, int64) *gitnesswebhook.TriggerResult); ok { + r0 = rf(ctx, webhookExecutionID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gitnesswebhook.TriggerResult) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, webhookExecutionID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/webhooks_execution_repository.go b/registry/app/api/controller/mocks/webhooks_execution_repository.go new file mode 100644 index 000000000..c181259cc --- /dev/null +++ b/registry/app/api/controller/mocks/webhooks_execution_repository.go @@ -0,0 +1,112 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/types" + + "github.com/stretchr/testify/mock" +) + +// WebhooksExecutionRepository is a mock of store.WebhooksExecutionRepository interface. +type WebhooksExecutionRepository struct { + mock.Mock +} + +// Find provides a mock function +func (m *WebhooksExecutionRepository) Find(ctx context.Context, id int64) (*types.WebhookExecutionCore, error) { + ret := m.Called(ctx, id) + + var r0 *types.WebhookExecutionCore + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.WebhookExecutionCore); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.WebhookExecutionCore) + } + } + + 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 +} + +// Create provides a mock function +func (m *WebhooksExecutionRepository) Create(ctx context.Context, hook *types.WebhookExecutionCore) error { + ret := m.Called(ctx, hook) + return ret.Error(0) +} + +// ListForWebhook provides a mock function +func (m *WebhooksExecutionRepository) ListForWebhook(ctx context.Context, webhookID int64, limit int, page int, size int) ([]*types.WebhookExecutionCore, error) { + ret := m.Called(ctx, webhookID, limit, page, size) + + var r0 []*types.WebhookExecutionCore + if rf, ok := ret.Get(0).(func(context.Context, int64, int, int, int) []*types.WebhookExecutionCore); ok { + r0 = rf(ctx, webhookID, limit, page, size) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.WebhookExecutionCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, int, int, int) error); ok { + r1 = rf(ctx, webhookID, limit, page, size) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountForWebhook provides a mock function +func (m *WebhooksExecutionRepository) CountForWebhook(ctx context.Context, webhookID int64) (int64, error) { + ret := m.Called(ctx, webhookID) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok { + r0 = rf(ctx, webhookID) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, webhookID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListForTrigger provides a mock function +func (m *WebhooksExecutionRepository) ListForTrigger(ctx context.Context, triggerID string) ([]*types.WebhookExecutionCore, error) { + ret := m.Called(ctx, triggerID) + + var r0 []*types.WebhookExecutionCore + if rf, ok := ret.Get(0).(func(context.Context, string) []*types.WebhookExecutionCore); ok { + r0 = rf(ctx, triggerID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.WebhookExecutionCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, triggerID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/mocks/webhooks_repository.go b/registry/app/api/controller/mocks/webhooks_repository.go new file mode 100644 index 000000000..91c9674a4 --- /dev/null +++ b/registry/app/api/controller/mocks/webhooks_repository.go @@ -0,0 +1,170 @@ +// Code generated by testify. DO NOT EDIT. + +package mocks + +import ( + "context" + + "github.com/harness/gitness/types" + + "github.com/stretchr/testify/mock" +) + +// WebhooksRepository is a mock of store.WebhooksRepository interface. +type WebhooksRepository struct { + mock.Mock +} + +// Create provides a mock function +func (m *WebhooksRepository) Create(ctx context.Context, webhook *types.WebhookCore) error { + ret := m.Called(ctx, webhook) + return ret.Error(0) +} + +// GetByRegistryAndIdentifier provides a mock function +func (m *WebhooksRepository) GetByRegistryAndIdentifier(ctx context.Context, registryID int64, webhookIdentifier string) (*types.WebhookCore, error) { + ret := m.Called(ctx, registryID, webhookIdentifier) + + var r0 *types.WebhookCore + if rf, ok := ret.Get(0).(func(context.Context, int64, string) *types.WebhookCore); ok { + r0 = rf(ctx, registryID, webhookIdentifier) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.WebhookCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, registryID, webhookIdentifier) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Find provides a mock function +func (m *WebhooksRepository) Find(ctx context.Context, webhookID int64) (*types.WebhookCore, error) { + ret := m.Called(ctx, webhookID) + + var r0 *types.WebhookCore + if rf, ok := ret.Get(0).(func(context.Context, int64) *types.WebhookCore); ok { + r0 = rf(ctx, webhookID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.WebhookCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok { + r1 = rf(ctx, webhookID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListByRegistry provides a mock function +func (m *WebhooksRepository) ListByRegistry(ctx context.Context, sortByField string, sortByOrder string, limit int, offset int, search string, registryID int64) ([]*types.WebhookCore, error) { + ret := m.Called(ctx, sortByField, sortByOrder, limit, offset, search, registryID) + + var r0 []*types.WebhookCore + if rf, ok := ret.Get(0).(func(context.Context, string, string, int, int, string, int64) []*types.WebhookCore); ok { + r0 = rf(ctx, sortByField, sortByOrder, limit, offset, search, registryID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.WebhookCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, string, int, int, string, int64) error); ok { + r1 = rf(ctx, sortByField, sortByOrder, limit, offset, search, registryID) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ListAllByRegistry provides a mock function +func (m *WebhooksRepository) ListAllByRegistry(ctx context.Context, parents []types.WebhookParentInfo) ([]*types.WebhookCore, error) { + ret := m.Called(ctx, parents) + + var r0 []*types.WebhookCore + if rf, ok := ret.Get(0).(func(context.Context, []types.WebhookParentInfo) []*types.WebhookCore); ok { + r0 = rf(ctx, parents) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*types.WebhookCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, []types.WebhookParentInfo) error); ok { + r1 = rf(ctx, parents) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CountAllByRegistry provides a mock function +func (m *WebhooksRepository) CountAllByRegistry(ctx context.Context, registryID int64, search string) (int64, error) { + ret := m.Called(ctx, registryID, search) + + var r0 int64 + if rf, ok := ret.Get(0).(func(context.Context, int64, string) int64); ok { + r0 = rf(ctx, registryID, search) + } else { + r0 = ret.Get(0).(int64) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok { + r1 = rf(ctx, registryID, search) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Update provides a mock function +func (m *WebhooksRepository) Update(ctx context.Context, webhook *types.WebhookCore) error { + ret := m.Called(ctx, webhook) + return ret.Error(0) +} + +// DeleteByRegistryAndIdentifier provides a mock function +func (m *WebhooksRepository) DeleteByRegistryAndIdentifier(ctx context.Context, registryID int64, webhookIdentifier string) error { + ret := m.Called(ctx, registryID, webhookIdentifier) + return ret.Error(0) +} + +// UpdateOptLock provides a mock function +func (m *WebhooksRepository) UpdateOptLock(ctx context.Context, hook *types.WebhookCore, fn func(hook *types.WebhookCore) error) (*types.WebhookCore, error) { + ret := m.Called(ctx, hook, fn) + + var r0 *types.WebhookCore + if rf, ok := ret.Get(0).(func(context.Context, *types.WebhookCore, func(*types.WebhookCore) error) *types.WebhookCore); ok { + r0 = rf(ctx, hook, fn) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.WebhookCore) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *types.WebhookCore, func(*types.WebhookCore) error) error); ok { + r1 = rf(ctx, hook, fn) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/registry/app/api/controller/metadata/interfaces.go b/registry/app/api/interfaces/registry_metadata.go similarity index 54% rename from registry/app/api/controller/metadata/interfaces.go rename to registry/app/api/interfaces/registry_metadata.go index 2bdb6463f..bd18895d4 100644 --- a/registry/app/api/controller/metadata/interfaces.go +++ b/registry/app/api/interfaces/registry_metadata.go @@ -1,4 +1,4 @@ -// Copyright 2023 Harness, Inc. +// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,49 +12,59 @@ // See the License for the specific language governing permissions and // limitations under the License. -package metadata +package interfaces import ( "context" - gitnesswebhook "github.com/harness/gitness/app/services/webhook" api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" + registrytypes "github.com/harness/gitness/registry/types" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" ) -type SpaceFinder interface { - FindByRef(ctx context.Context, spaceRef string) (*types.SpaceCore, error) - FindByID(ctx context.Context, spaceID int64) (*types.SpaceCore, error) -} - +// RegistryMetadataHelper provides helper methods for registry metadata operations. type RegistryMetadataHelper interface { + // GetRegistryRequestBaseInfo retrieves base info for registry request. + GetRegistryRequestBaseInfo( + ctx context.Context, + parentPath string, + identifier string, + ) (*registrytypes.RegistryRequestBaseInfo, error) + + // GetPermissionChecks returns permission checks for registry operations. GetPermissionChecks( space *types.SpaceCore, registryIdentifier string, permission enum.Permission, ) []types.PermissionCheck - GetRegistryRequestBaseInfo( - ctx context.Context, - parentRef string, - regRef string, - ) (*RegistryRequestBaseInfo, error) - getSecretSpaceID(ctx context.Context, secretSpacePath *string) (int64, error) - MapToAPIWebhookTriggers(triggers []enum.WebhookTrigger) []api.Trigger - MapToInternalWebhookTriggers( - triggers []api.Trigger, - ) []enum.WebhookTrigger + + // MapToWebhookCore maps webhook request to core webhook type. MapToWebhookCore( ctx context.Context, webhookRequest api.WebhookRequest, - regInfo *RegistryRequestBaseInfo, + regInfo *registrytypes.RegistryRequestBaseInfo, ) (*types.WebhookCore, error) + + // MapToWebhookResponseEntity maps webhook core to response entity. MapToWebhookResponseEntity( ctx context.Context, - createdWebhook *types.WebhookCore, + webhook *types.WebhookCore, ) (*api.Webhook, error) -} -type WebhookService interface { - ReTriggerWebhookExecution(ctx context.Context, webhookExecutionID int64) (*gitnesswebhook.TriggerResult, error) + // MapToInternalWebhookTriggers maps webhook triggers to internal type. + MapToInternalWebhookTriggers( + triggers []api.Trigger, + ) []enum.WebhookTrigger + + // MapToAPIWebhookTriggers maps webhook triggers to API type. + MapToAPIWebhookTriggers( + triggers []enum.WebhookTrigger, + ) []api.Trigger + + // GetSecretSpaceID retrieves secret space ID from secret space path. + GetSecretSpaceID( + ctx context.Context, + secretSpacePath *string, + ) (int64, error) } diff --git a/registry/app/api/interfaces/space_finder.go b/registry/app/api/interfaces/space_finder.go new file mode 100644 index 000000000..00b7fcaf3 --- /dev/null +++ b/registry/app/api/interfaces/space_finder.go @@ -0,0 +1,30 @@ +// Copyright 2023 Harness, Inc. +// +// 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 interfaces + +import ( + "context" + + "github.com/harness/gitness/types" +) + +// SpaceFinder defines the interface for finding spaces. +type SpaceFinder interface { + // FindByID finds the space by id. + FindByID(ctx context.Context, id int64) (*types.SpaceCore, error) + + // FindByRef finds the space using the spaceRef as either the id or the space path. + FindByRef(ctx context.Context, spaceRef string) (*types.SpaceCore, error) +} diff --git a/registry/app/api/router/harness/route.go b/registry/app/api/router/harness/route.go index fe86f698f..86a150ba9 100644 --- a/registry/app/api/router/harness/route.go +++ b/registry/app/api/router/harness/route.go @@ -21,11 +21,11 @@ import ( "github.com/harness/gitness/app/api/middleware/encode" "github.com/harness/gitness/app/auth/authn" "github.com/harness/gitness/app/auth/authz" - "github.com/harness/gitness/app/services/refcache" corestore "github.com/harness/gitness/app/store" urlprovider "github.com/harness/gitness/app/url" "github.com/harness/gitness/audit" "github.com/harness/gitness/registry/app/api/controller/metadata" + "github.com/harness/gitness/registry/app/api/interfaces" "github.com/harness/gitness/registry/app/api/middleware" "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" storagedriver "github.com/harness/gitness/registry/app/driver" @@ -64,7 +64,7 @@ func NewAPIHandler( imageDao store.ImageRepository, driver storagedriver.StorageDriver, baseURL string, - spaceFinder refcache.SpaceFinder, + spaceFinder interfaces.SpaceFinder, tx dbtx.Transactor, authenticator authn.Authenticator, urlProvider urlprovider.Provider, diff --git a/registry/services/webhook/interface.go b/registry/services/webhook/interface.go new file mode 100644 index 000000000..2e5467555 --- /dev/null +++ b/registry/services/webhook/interface.go @@ -0,0 +1,26 @@ +// Copyright 2023 Harness, Inc. +// +// 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 webhook + +import ( + "context" + + gitnesswebhook "github.com/harness/gitness/app/services/webhook" +) + +// Service interface for webhook operations. +type ServiceInterface interface { + ReTriggerWebhookExecution(ctx context.Context, webhookExecutionID int64) (*gitnesswebhook.TriggerResult, error) +} diff --git a/registry/services/webhook/service.go b/registry/services/webhook/service.go index 4fb18160a..ca245c866 100644 --- a/registry/services/webhook/service.go +++ b/registry/services/webhook/service.go @@ -35,6 +35,9 @@ const ( eventsReaderGroupName = "gitness:webhook" ) +// Verify Service implements ServiceInterface. +var _ ServiceInterface = (*Service)(nil) + // Service is responsible for processing webhook events. type Service struct { WebhookExecutor *gitnesswebhook.WebhookExecutor diff --git a/registry/types/request.go b/registry/types/request.go new file mode 100644 index 000000000..e2aec36a7 --- /dev/null +++ b/registry/types/request.go @@ -0,0 +1,37 @@ +// Copyright 2023 Harness, Inc. +// +// 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 types + +import ( + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" +) + +// RegistryRequestBaseInfo represents base information about a registry request. +type RegistryRequestBaseInfo struct { + RootIdentifier string + RootIdentifierID int64 + RegistryRef string + RegistryIdentifier string + RegistryID int64 + ParentRef string + ParentID int64 + RegistryType api.RegistryType + PackageType api.PackageType +} + +// ArtifactFilesRequestInfo represents base information about an artifact files request. +type ArtifactFilesRequestInfo struct { + RegistryRequestBaseInfo +} diff --git a/registry/utils/pointer_helpers.go b/registry/utils/pointer_helpers.go new file mode 100644 index 000000000..b71edb99a --- /dev/null +++ b/registry/utils/pointer_helpers.go @@ -0,0 +1,30 @@ +// Copyright 2023 Harness, Inc. +// +// 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 utils + +import ( + api "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact" +) + +// Helper functions for creating pointers. +func StringPtr(s string) *string { return &s } +func Int64Ptr(i int64) *int64 { return &i } +func IntPtr(i int) *int { return &i } +func BoolPtr(b bool) *bool { return &b } +func Int32Ptr(i int32) *int32 { return &i } +func WebhookExecResultPtr(r api.WebhookExecResult) *api.WebhookExecResult { return &r } +func WebhookTriggerPtr(t api.Trigger) *api.Trigger { return &t } +func PageSizePtr(i int32) *api.PageSize { size := api.PageSize(i); return &size } +func PageNumberPtr(i int32) *api.PageNumber { num := api.PageNumber(i); return &num }