package registry import ( "bytes" "context" "crypto/sha512" "errors" "fmt" "io" "strings" "testing" "time" "github.com/bnema/zerowrap" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/bnema/gordon/internal/boundaries/out/mocks" "github.com/bnema/gordon/internal/domain" "github.com/bnema/gordon/internal/usecase/registrystate" ) func testContext() context.Context { return zerowrap.WithCtx(context.Background(), zerowrap.Default()) } func TestService_GetManifest_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestData := []byte(`{"schemaVersion": 2}`) manifestStorage.EXPECT().GetManifest("myapp", "latest").Return(manifestData, "application/vnd.docker.distribution.manifest.v2+json", nil) result, err := svc.GetManifest(ctx, "myapp", "latest") assert.NoError(t, err) assert.NotNil(t, result) assert.Equal(t, "myapp", result.Name) assert.Equal(t, "latest", result.Reference) assert.Equal(t, "application/vnd.docker.distribution.manifest.v2+json", result.ContentType) assert.Equal(t, manifestData, result.Data) } func TestService_GetManifest_NotFound(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().GetManifest("myapp", "notexists").Return(nil, "", errors.New("manifest not found")) result, err := svc.GetManifest(ctx, "myapp", "notexists") assert.Error(t, err) assert.Nil(t, result) assert.Contains(t, err.Error(), "failed to get manifest") } func TestService_PutManifest_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifest := &domain.Manifest{ Name: "myapp", Reference: "latest", ContentType: "application/vnd.docker.distribution.manifest.v2+json", Data: []byte(`{"schemaVersion": 2}`), } manifestStorage.EXPECT().PutManifest("myapp", "latest", "application/vnd.docker.distribution.manifest.v2+json", manifest.Data).Return(nil) eventBus.EXPECT().Publish(domain.EventImagePushed, mock.AnythingOfType("domain.ImagePushedPayload")).Return(nil) digest, err := svc.PutManifest(ctx, manifest) assert.NoError(t, err) assert.NotEmpty(t, digest) assert.True(t, strings.HasPrefix(digest, "sha256:")) } func TestService_PutManifest_SHA512DigestDoesNotPublishEvent(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) state := registrystate.New() state.AddPending("sha256:config", time.Now().UTC()) svc := NewService(blobStorage, manifestStorage, eventBus, state) data := []byte(`{"schemaVersion":2,"config":{"digest":"sha256:config"}}`) reference := fmt.Sprintf("sha512:%x", sha512.Sum512(data)) manifest := &domain.Manifest{Name: "myapp", Reference: reference, ContentType: "application/vnd.oci.image.manifest.v1+json", Data: data} manifestStorage.EXPECT().PutManifest("myapp", reference, manifest.ContentType, data).Return(nil) digest, err := svc.PutManifest(testContext(), manifest) require.NoError(t, err) assert.Equal(t, reference, digest) assert.Empty(t, state.PendingDigests(time.Now().UTC())) } func TestService_PutManifest_RejectsDigestMismatch(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) manifest := &domain.Manifest{ Name: "myapp", Reference: "sha256:0000000000000000000000000000000000000000000000000000000000000000", ContentType: "application/vnd.oci.image.manifest.v1+json", Data: []byte(`{"schemaVersion":2}`), } _, err := svc.PutManifest(testContext(), manifest) require.Error(t, err) assert.ErrorIs(t, err, domain.ErrDigestMismatch) } func TestService_GetBlobPath_RequiresRepositoryReference(t *testing.T) { const digest = "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) svc := NewService(blobStorage, manifestStorage, nil) manifestStorage.EXPECT().ListTags("allowed").Return([]string{"latest"}, nil) manifestStorage.EXPECT().GetManifest("allowed", "latest").Return( []byte(`{"schemaVersion":2,"layers":[{"digest":"`+digest+`"}]}`), "application/vnd.oci.image.manifest.v1+json", nil, ) blobStorage.EXPECT().GetBlobPath(digest).Return("/registry/blob", nil) path, err := svc.GetBlobPath(testContext(), "allowed", digest) require.NoError(t, err) assert.Equal(t, "/registry/blob", path) manifestStorage.EXPECT().ListTags("denied").Return([]string{"latest"}, nil) manifestStorage.EXPECT().GetManifest("denied", "latest").Return( []byte(`{"schemaVersion":2,"layers":[]}`), "application/vnd.oci.image.manifest.v1+json", nil, ) _, err = svc.GetBlobPath(testContext(), "denied", digest) assert.ErrorIs(t, err, domain.ErrBlobNotFound) } func TestService_GetBlobPath_FollowsSubjectManifest(t *testing.T) { const target = "sha256:target" blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) svc := NewService(blobStorage, manifestStorage, nil) manifestStorage.EXPECT().ListTags("artifacts").Return([]string{"latest"}, nil) manifestStorage.EXPECT().GetManifest("artifacts", "latest").Return( []byte(`{"subject":{"digest":"sha256:subject"}}`), "application/vnd.oci.artifact.manifest.v1+json", nil, ) manifestStorage.EXPECT().GetManifest("artifacts", "sha256:subject").Return( []byte(`{"config":{"digest":"`+target+`"}}`), "application/vnd.oci.image.manifest.v1+json", nil, ) blobStorage.EXPECT().GetBlobPath(target).Return("/registry/target", nil) path, err := svc.GetBlobPath(testContext(), "artifacts", target) require.NoError(t, err) assert.Equal(t, "/registry/target", path) } func TestService_GetBlobPath_BoundsManifestTraversal(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) svc := NewService(blobStorage, manifestStorage, nil) tags := make([]string, maxManifestTraversal+1) manifestStorage.EXPECT().ListTags("busy").Return(tags, nil) _, err := svc.GetBlobPath(testContext(), "busy", "sha256:target") assert.ErrorIs(t, err, domain.ErrBlobNotFound) } func TestService_PutManifest_StorageError(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifest := &domain.Manifest{ Name: "myapp", Reference: "latest", ContentType: "application/vnd.docker.distribution.manifest.v2+json", Data: []byte(`{"schemaVersion": 2}`), } manifestStorage.EXPECT().PutManifest("myapp", "latest", "application/vnd.docker.distribution.manifest.v2+json", manifest.Data).Return(errors.New("storage full")) _, err := svc.PutManifest(ctx, manifest) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to store manifest") } func TestService_PutManifest_EventPublishError(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifest := &domain.Manifest{ Name: "myapp", Reference: "latest", ContentType: "application/vnd.docker.distribution.manifest.v2+json", Data: []byte(`{"schemaVersion": 2}`), } manifestStorage.EXPECT().PutManifest("myapp", "latest", "application/vnd.docker.distribution.manifest.v2+json", manifest.Data).Return(nil) eventBus.EXPECT().Publish(domain.EventImagePushed, mock.Anything).Return(errors.New("event bus error")) // Should still succeed - event publish error is logged but doesn't fail the operation _, err := svc.PutManifest(ctx, manifest) assert.NoError(t, err) } func TestService_PutManifest_NilEventBus(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) // Nil event bus svc := NewService(blobStorage, manifestStorage, nil) ctx := testContext() manifest := &domain.Manifest{ Name: "myapp", Reference: "latest", ContentType: "application/vnd.docker.distribution.manifest.v2+json", Data: []byte(`{"schemaVersion": 2}`), } manifestStorage.EXPECT().PutManifest("myapp", "latest", "application/vnd.docker.distribution.manifest.v2+json", manifest.Data).Return(nil) _, err := svc.PutManifest(ctx, manifest) assert.NoError(t, err) } func TestService_DeleteManifest_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().DeleteManifest("myapp", "latest").Return(nil) err := svc.DeleteManifest(ctx, "myapp", "latest") assert.NoError(t, err) } func TestService_DeleteManifest_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().DeleteManifest("myapp", "latest").Return(errors.New("manifest not found")) err := svc.DeleteManifest(ctx, "myapp", "latest") assert.Error(t, err) assert.Contains(t, err.Error(), "failed to delete manifest") } func TestService_GetBlob_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobData := []byte("blob content") blobStorage.EXPECT().GetBlob("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4").Return(io.NopCloser(bytes.NewReader(blobData)), nil) reader, err := svc.GetBlob(ctx, "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4") assert.NoError(t, err) assert.NotNil(t, reader) data, _ := io.ReadAll(reader) assert.Equal(t, blobData, data) } func TestService_GetBlob_NotFound(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().GetBlob("sha256:notexists").Return(nil, errors.New("blob not found")) reader, err := svc.GetBlob(ctx, "sha256:notexists") assert.Error(t, err) assert.Nil(t, reader) assert.Contains(t, err.Error(), "failed to get blob") } func TestService_PutBlob_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobData := []byte("blob content") reader := bytes.NewReader(blobData) blobStorage.EXPECT().PutBlob("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", mock.Anything, int64(len(blobData))).Return(nil) err := svc.PutBlob(ctx, "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", reader, int64(len(blobData))) assert.NoError(t, err) } func TestService_PutBlob_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobData := []byte("blob content") reader := bytes.NewReader(blobData) blobStorage.EXPECT().PutBlob("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", mock.Anything, int64(len(blobData))).Return(errors.New("storage full")) err := svc.PutBlob(ctx, "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", reader, int64(len(blobData))) assert.Error(t, err) assert.Contains(t, err.Error(), "failed to store blob") } func TestService_BlobExists(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().BlobExists("sha256:exists").Return(true) blobStorage.EXPECT().BlobExists("sha256:notexists").Return(false) assert.True(t, svc.BlobExists(ctx, "sha256:exists")) assert.False(t, svc.BlobExists(ctx, "sha256:notexists")) } func TestService_StartUpload_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().StartBlobUpload("myapp").Return("1234567890-myapp", nil) uuid, err := svc.StartUpload(ctx, "myapp") assert.NoError(t, err) assert.Equal(t, "1234567890-myapp", uuid) } func TestService_StartUpload_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().StartBlobUpload("myapp").Return("", errors.New("cannot create upload")) uuid, err := svc.StartUpload(ctx, "myapp") assert.Error(t, err) assert.Empty(t, uuid) assert.Contains(t, err.Error(), "failed to start blob upload") } func TestService_AppendBlobChunk_PassesMaxBlobSize(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().AppendBlobChunk("myapp", "upload-id", mock.Anything, int64(4), int64(10)).Return(int64(4), nil) length, err := svc.AppendBlobChunk(ctx, "myapp", "upload-id", strings.NewReader("data"), 4, 10) assert.NoError(t, err) assert.Equal(t, int64(4), length) } func TestService_AppendBlobChunk_MaxBlobSizeExceeded(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().AppendBlobChunk("myapp", "upload-id", mock.Anything, int64(11), int64(10)).Return(int64(0), domain.ErrBlobSizeExceeded) _, err := svc.AppendBlobChunk(ctx, "myapp", "upload-id", strings.NewReader("too large"), 11, 10) require.Error(t, err) assert.ErrorIs(t, err, domain.ErrBlobSizeExceeded) } func TestService_FinishUpload_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().FinishBlobUpload("1234567890-myapp", "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4").Return(nil) err := svc.FinishUpload(ctx, "1234567890-myapp", "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4") assert.NoError(t, err) } func TestService_FinishUploadMarksBlobPending(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) state := registrystate.New() svc := NewService(blobStorage, manifestStorage, eventBus, state) const digest = "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" blobStorage.EXPECT().FinishBlobUpload("1234567890-myapp", digest).Return(nil) require.NoError(t, svc.FinishUpload(testContext(), "1234567890-myapp", digest)) assert.Contains(t, state.PendingDigests(time.Now().UTC()), digest) } func TestService_FinishUploadBlocksRegistryPruning(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) state := registrystate.New() svc := NewService(blobStorage, manifestStorage, eventBus, state) started := make(chan struct{}) release := make(chan struct{}) blobStorage.EXPECT().FinishBlobUpload("1234567890-myapp", mock.Anything).RunAndReturn(func(string, string) error { close(started) <-release return nil }) finished := make(chan error, 1) go func() { finished <- svc.FinishUpload(testContext(), "1234567890-myapp", "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4") }() <-started pruneLockAcquired := make(chan struct{}) go func() { state.MutationMu.Lock() close(pruneLockAcquired) state.MutationMu.Unlock() }() assert.Never(t, func() bool { select { case <-pruneLockAcquired: return true default: return false } }, 100*time.Millisecond, 10*time.Millisecond) close(release) require.NoError(t, <-finished) require.Eventually(t, func() bool { select { case <-pruneLockAcquired: return true default: return false } }, time.Second, 10*time.Millisecond) } func TestService_FinishUpload_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().FinishBlobUpload("1234567890-myapp", "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4").Return(errors.New("digest mismatch")) err := svc.FinishUpload(ctx, "1234567890-myapp", "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4") assert.Error(t, err) assert.Contains(t, err.Error(), "failed to finish blob upload") } func TestService_CancelUpload_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().CancelBlobUpload("1234567890-myapp").Return(nil) err := svc.CancelUpload(ctx, "1234567890-myapp") assert.NoError(t, err) } func TestService_CancelUpload_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() blobStorage.EXPECT().CancelBlobUpload("1234567890-myapp").Return(errors.New("upload not found")) err := svc.CancelUpload(ctx, "1234567890-myapp") assert.Error(t, err) assert.Contains(t, err.Error(), "failed to cancel blob upload") } func TestService_ListTags_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().ListTags("myapp").Return([]string{ "latest", "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "v1.0", "v2.0", }, nil) tags, err := svc.ListTags(ctx, "myapp") assert.NoError(t, err) assert.Equal(t, []string{"latest", "v1.0", "v2.0"}, tags) } func TestService_ListTags_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().ListTags("myapp").Return(nil, errors.New("repository not found")) tags, err := svc.ListTags(ctx, "myapp") assert.Error(t, err) assert.Nil(t, tags) assert.Contains(t, err.Error(), "failed to list tags") } func TestService_ListRepositories_Success(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().ListRepositories().Return([]string{"myapp", "otherapp", "thirdapp"}, nil) repos, err := svc.ListRepositories(ctx) assert.NoError(t, err) assert.Equal(t, []string{"myapp", "otherapp", "thirdapp"}, repos) } func TestService_ListRepositories_Error(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) ctx := testContext() manifestStorage.EXPECT().ListRepositories().Return(nil, errors.New("storage error")) repos, err := svc.ListRepositories(ctx) assert.Error(t, err) assert.Nil(t, repos) assert.Contains(t, err.Error(), "failed to list repositories") } func TestPutManifest_SkipsEventWhenDeployIntentSuppressed(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) svc.SuppressDeployEvent("my-app") manifestStorage.EXPECT().PutManifest("my-app", "latest", "application/vnd.oci.image.manifest.v1+json", mock.Anything).Return(nil) manifest := &domain.Manifest{ Name: "my-app", Reference: "latest", ContentType: "application/vnd.oci.image.manifest.v1+json", Data: []byte(`{"schemaVersion":2}`), } _, err := svc.PutManifest(context.Background(), manifest) require.NoError(t, err) eventBus.AssertNotCalled(t, "Publish", mock.Anything, mock.Anything) } func TestSuppressDeployEvent_ClearsCorrectly(t *testing.T) { blobStorage := mocks.NewMockBlobStorage(t) manifestStorage := mocks.NewMockManifestStorage(t) eventBus := mocks.NewMockEventPublisher(t) svc := NewService(blobStorage, manifestStorage, eventBus) svc.SuppressDeployEvent("my-app") assert.True(t, svc.IsDeployEventSuppressed("my-app")) svc.ClearDeployEventSuppression("my-app") assert.False(t, svc.IsDeployEventSuppressed("my-app")) }