public async Task ProcessEventAsync_FinalizerIsNotAdded(WatchEventType eventType, bool withFinalizer)
        {
            // Arrange
            var resource      = CreateCustomResource(withFinalizer: withFinalizer);
            var resourceEvent = new CustomResourceEvent(eventType, resource);

            // Act
            await _controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            VerifyNoOtherApiIsCalled();
        }
        public async Task ProcessEventAsync_MissingFinalizerIsAdded(WatchEventType eventType)
        {
            // Arrange
            var resource      = CreateCustomResource(withFinalizer: false);
            var resourceEvent = new CustomResourceEvent(eventType, resource);

            // Act
            await _controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            VerifyReplaceIsCalled(resource, out TestableCustomResource updatedResource);
            Assert.Equal(CustomResourceDefinitionAttribute.DEFAULT_FINALIZER, updatedResource.Metadata.Finalizers[0]);
        }
        public async Task ProcessEventAsync_AddOrModifyIsNotCalled(WatchEventType eventType)
        {
            // Arrange
            var resource      = CreateCustomResource();
            var resourceEvent = new CustomResourceEvent(eventType, resource);

            // Act
            await _controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            VerifyAddOrModifyIsNotCalled(_controller);
            VerifyDeleteIsNotCalled(_controller);
            VerifyNoOtherApiIsCalled();
        }
        public async Task ProcessEventAsync_NoRetryAfterMaxAttempts(WatchEventType eventType, bool delete)
        {
            // Arrange
            var resource      = CreateCustomResource(deletionTimeStamp: delete ? DateTime.Now : (DateTime?)null);
            var resourceEvent = new CustomResourceEvent(eventType, resource);

            _controller.ThrowExceptionOnNextEvents(_controller.RetryPolicy.MaxAttempts + 1); // ProcessEventAsync will fail n + 1 times, where n = MaxAttempts

            // Act
            await _controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            VerifyCompletedEvents(_controller);
        }
        public async Task ProcessEventAsync_DeleteIsCalled()
        {
            // Arrange
            var resource      = CreateCustomResource(deletionTimeStamp: DateTime.Now);
            var resourceEvent = new CustomResourceEvent(WatchEventType.Modified, resource);

            // Act
            await _controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            VerifyAddOrModifyIsNotCalled(_controller);
            VerifyDeleteIsCalledWith(_controller, resource);
            VerifyReplaceIsCalled(resource, out TestableCustomResource updatedResource);
            Assert.Equal(0, updatedResource.Metadata.Finalizers.Count);
        }
        public async Task ProcessEventAsync_WithDynamicCustomResource(WatchEventType eventType)
        {
            // Arrange
            var resource = new TestableDynamicCustomResource();

            resource.Spec.property   = "desired";
            resource.Status.property = "actual";
            var resourceEvent = new CustomResourceEvent(eventType, resource);
            var controller    = new TestableDynamicController();

            // Act
            await controller.ProcessEventAsync(resourceEvent, DUMMY_TOKEN);

            // Assert
            Assert.Equal(resource.Spec.property, resource.Status.property);
        }