package com.thinkbiganalytics.nifi.v2.metadata; /*- * #%L * thinkbig-nifi-core-processors * %% * Copyright (C) 2017 ThinkBig Analytics * %% * 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. * #L% */ import com.thinkbiganalytics.metadata.api.feed.FeedProperties; import com.thinkbiganalytics.metadata.rest.model.event.FeedCleanupTriggerEvent; import com.thinkbiganalytics.nifi.core.api.cleanup.CleanupEventService; import com.thinkbiganalytics.nifi.core.api.cleanup.CleanupListener; import com.thinkbiganalytics.nifi.core.api.metadata.KyloNiFiFlowProvider; import com.thinkbiganalytics.nifi.core.api.metadata.MetadataProvider; import com.thinkbiganalytics.nifi.core.api.metadata.MetadataProviderService; import com.thinkbiganalytics.nifi.core.api.metadata.MetadataRecorder; import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.util.MockFlowFile; import org.apache.nifi.util.MockProcessContext; import org.apache.nifi.util.TestRunner; import org.apache.nifi.util.TestRunners; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import javax.annotation.Nonnull; public class TriggerCleanupTest { /** * Identifier for the cleanup event service */ private static final String CLEANUP_SERVICE_IDENTIFIER = "MockCleanupEventService"; /** * Identifier for the metadata provider service */ private static final String METADATA_SERVICE_IDENTIFIER = "MockMetadataProviderService"; /** * Test runner */ private final TestRunner runner = TestRunners.newTestRunner(TriggerCleanup.class); /** * Initialize instance variables. */ @Before public void setUp() throws Exception { // Setup services final CleanupEventService cleanupService = new MockCleanupEventService(); final MetadataProviderService metadataService = new MockMetadataProviderService(); // Setup test runner runner.addControllerService(CLEANUP_SERVICE_IDENTIFIER, cleanupService); runner.addControllerService(METADATA_SERVICE_IDENTIFIER, metadataService); runner.enableControllerService(cleanupService); runner.enableControllerService(metadataService); runner.setProperty(TriggerCleanup.CLEANUP_SERVICE, CLEANUP_SERVICE_IDENTIFIER); runner.setProperty(TriggerCleanup.METADATA_SERVICE, METADATA_SERVICE_IDENTIFIER); } /** * Verify property validators. */ @Test public void testValidators() { // Test with no properties runner.removeProperty(TriggerCleanup.CLEANUP_SERVICE); runner.removeProperty(TriggerCleanup.METADATA_SERVICE); runner.enqueue(new byte[0]); Set<String> results = ((MockProcessContext) runner.getProcessContext()).validate().stream().map(Object::toString).collect(Collectors.toSet()); Assert.assertEquals(2, results.size()); Assert.assertTrue(results.contains("'Feed Cleanup Event Service' is invalid because Feed Cleanup Event Service is required")); Assert.assertTrue(results.contains("'Metadata Provider Service' is invalid because Metadata Provider Service is required")); // Test with valid properties runner.setProperty(TriggerCleanup.CLEANUP_SERVICE, CLEANUP_SERVICE_IDENTIFIER); runner.setProperty(TriggerCleanup.METADATA_SERVICE, METADATA_SERVICE_IDENTIFIER); runner.enqueue(new byte[0]); Assert.assertEquals(0, ((MockProcessContext) runner.getProcessContext()).validate().size()); } /** * Verify scheduling the processor. */ @Test public void testScheduled() { runner.setProperty(TriggerCleanup.CATEGORY_NAME, "cat"); runner.setProperty(TriggerCleanup.FEED_NAME, "feed"); runner.enqueue(new byte[0]); runner.run(); } /** * Verify exception when scheduling the processor. */ @Test(expected = AssertionError.class) public void testTriggeredWithException() { runner.setProperty(TriggerCleanup.CATEGORY_NAME, "invalid"); runner.setProperty(TriggerCleanup.FEED_NAME, "invalid"); ((TriggerCleanup) runner.getProcessor()).triggered(new FeedCleanupTriggerEvent("FEEDID")); runner.run(); } /** * Verify triggering the processor. */ @Test public void testTriggered() { runner.setProperty(TriggerCleanup.CATEGORY_NAME, "cat"); runner.setProperty(TriggerCleanup.FEED_NAME, "feed"); ((TriggerCleanup) runner.getProcessor()).triggered(new FeedCleanupTriggerEvent("FEEDID")); runner.run(); List<MockFlowFile> flowFiles = runner.getFlowFilesForRelationship(TriggerCleanup.REL_SUCCESS); Assert.assertEquals(1, flowFiles.size()); flowFiles.get(0).assertAttributeEquals("category", "cat"); flowFiles.get(0).assertAttributeEquals("feed", "feed"); } /** * Verify triggering the processor when the cleanup property is disabled. */ @Test public void testTriggeredWhenDisabled() { runner.setProperty(TriggerCleanup.CATEGORY_NAME, "cat"); runner.setProperty(TriggerCleanup.FEED_NAME, "disabled"); ((TriggerCleanup) runner.getProcessor()).triggered(new FeedCleanupTriggerEvent("FEEDID")); runner.run(); Assert.assertEquals(0, runner.getFlowFilesForRelationship(TriggerCleanup.REL_SUCCESS).size()); } /** * Verify exception when the metadata service is unavailable. */ @Test(expected = AssertionError.class) public void testTriggeredWhenUnavailable() { runner.setProperty(TriggerCleanup.CATEGORY_NAME, "cat"); runner.setProperty(TriggerCleanup.FEED_NAME, "unavailable"); ((TriggerCleanup) runner.getProcessor()).triggered(new FeedCleanupTriggerEvent("FEEDID")); runner.run(); Assert.assertEquals(0, runner.getFlowFilesForRelationship(TriggerCleanup.REL_SUCCESS).size()); } /** * A mock implementation of {@link MetadataProviderService} for testing. */ private static class MockMetadataProviderService extends AbstractControllerService implements MetadataProviderService { @Override public MetadataProvider getProvider() { final MetadataProvider provider = Mockito.mock(MetadataProvider.class); Mockito.when(provider.getFeedId(Mockito.anyString(), Mockito.anyString())).then(invocation -> { if ("invalid".equals(invocation.getArgumentAt(0, String.class))) { throw new IllegalArgumentException(); } return invocation.getArgumentAt(1, String.class); }); Mockito.when(provider.getFeedProperties(Mockito.anyString())).then(invocation -> { final String feedId = invocation.getArgumentAt(0, String.class); if ("disabled".equals(feedId)) { return new Properties(); } if ("unavailable".equals(feedId)) { return null; } Properties properties = new Properties(); properties.setProperty(FeedProperties.CLEANUP_ENABLED, "true"); return properties; }); return provider; } @Override public KyloNiFiFlowProvider getKyloNiFiFlowProvider() { return null; } @Override public MetadataRecorder getRecorder() { return null; } } /** * A mock implementation of {@link CleanupEventService} for testing. */ private class MockCleanupEventService extends AbstractControllerService implements CleanupEventService { @Override public void addListener(@Nonnull final String category, @Nonnull final String feedName, @Nonnull final CleanupListener listener) { Assert.assertEquals(runner.getProcessor(), listener); } @Override public void removeListener(@Nonnull final CleanupListener listener) { Assert.assertEquals(runner.getProcessor(), listener); } } }