blob: 7cac4884d363cc1863077fc2e25b56a6a9e923b2 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.apache.nifi.minifi.bootstrap.configuration.ingestors;
import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.apache.nifi.minifi.bootstrap.ConfigurationFileHolder;
import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier;
import org.apache.nifi.minifi.bootstrap.configuration.differentiators.interfaces.Differentiator;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
public class FileChangeIngestorTest {
private static final String CONFIG_FILENAME = "config.yml";
private static final String TEST_CONFIG_PATH = "src/test/resources/config.yml";
private FileChangeIngestor notifierSpy;
private WatchService mockWatchService;
private Properties testProperties;
private Differentiator<InputStream> mockDifferentiator;
private ConfigurationChangeNotifier testNotifier;
@Before
public void setUp() throws Exception {
mockWatchService = Mockito.mock(WatchService.class);
notifierSpy = Mockito.spy(new FileChangeIngestor());
mockDifferentiator = Mockito.mock(Differentiator.class);
testNotifier = Mockito.mock(ConfigurationChangeNotifier.class);
notifierSpy.setConfigFilePath(Paths.get(TEST_CONFIG_PATH));
notifierSpy.setWatchService(mockWatchService);
notifierSpy.setDifferentiator(mockDifferentiator);
notifierSpy.setConfigurationChangeNotifier(testNotifier);
testProperties = new Properties();
testProperties.put(FileChangeIngestor.CONFIG_FILE_PATH_KEY, TEST_CONFIG_PATH);
testProperties.put(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY, FileChangeIngestor.DEFAULT_POLLING_PERIOD_INTERVAL);
}
@After
public void tearDown() throws Exception {
notifierSpy.close();
}
@Test(expected = IllegalStateException.class)
public void testInitialize_invalidFile() throws Exception {
testProperties.put(FileChangeIngestor.CONFIG_FILE_PATH_KEY, "/land/of/make/believe");
notifierSpy.initialize(testProperties, Mockito.mock(ConfigurationFileHolder.class), Mockito.mock(ConfigurationChangeNotifier.class));
}
@Test
public void testInitialize_validFile() throws Exception {
notifierSpy.initialize(testProperties, Mockito.mock(ConfigurationFileHolder.class), Mockito.mock(ConfigurationChangeNotifier.class));
}
@Test(expected = IllegalStateException.class)
public void testInitialize_invalidPollingPeriod() throws Exception {
testProperties.put(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY, "abc");
notifierSpy.initialize(testProperties, Mockito.mock(ConfigurationFileHolder.class), Mockito.mock(ConfigurationChangeNotifier.class));
}
@Test
public void testInitialize_useDefaultPolling() throws Exception {
testProperties.remove(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY);
notifierSpy.initialize(testProperties, Mockito.mock(ConfigurationFileHolder.class), Mockito.mock(ConfigurationChangeNotifier.class));
}
/* Verify handleChange events */
@Test
public void testTargetChangedNoModification() throws Exception {
when(mockDifferentiator.isNew(Mockito.any(InputStream.class))).thenReturn(false);
final ConfigurationChangeNotifier testNotifier = Mockito.mock(ConfigurationChangeNotifier.class);
// In this case the WatchKey is null because there were no events found
establishMockEnvironmentForChangeTests(testNotifier, null);
verify(testNotifier, Mockito.never()).notifyListeners(Mockito.any(ByteBuffer.class));
}
@Test
public void testTargetChangedWithModificationEvent_nonConfigFile() throws Exception {
when(mockDifferentiator.isNew(Mockito.any(InputStream.class))).thenReturn(false);
final ConfigurationChangeNotifier testNotifier = Mockito.mock(ConfigurationChangeNotifier.class);
// In this case, we receive a trigger event for the directory monitored, but it was another file not being monitored
final WatchKey mockWatchKey = createMockWatchKeyForPath("footage_not_found.yml");
establishMockEnvironmentForChangeTests(testNotifier, mockWatchKey);
notifierSpy.targetChanged();
verify(testNotifier, Mockito.never()).notifyListeners(Mockito.any(ByteBuffer.class));
}
@Test
public void testTargetChangedWithModificationEvent() throws Exception {
when(mockDifferentiator.isNew(Mockito.any(InputStream.class))).thenReturn(true);
final WatchKey mockWatchKey = createMockWatchKeyForPath(CONFIG_FILENAME);
// Provided as a spy to allow injection of mock objects for some tests when dealing with the finalized FileSystems class
establishMockEnvironmentForChangeTests(testNotifier, mockWatchKey);
// Invoke the method of interest
notifierSpy.run();
verify(mockWatchService, Mockito.atLeastOnce()).poll();
verify(testNotifier, Mockito.atLeastOnce()).notifyListeners(Mockito.any(ByteBuffer.class));
}
/* Helper methods to establish mock environment */
private WatchKey createMockWatchKeyForPath(String configFilePath) {
final WatchKey mockWatchKey = Mockito.mock(WatchKey.class);
final List<WatchEvent<?>> mockWatchEvents = (List<WatchEvent<?>>) Mockito.mock(List.class);
when(mockWatchKey.pollEvents()).thenReturn(mockWatchEvents);
when(mockWatchKey.reset()).thenReturn(true);
final Iterator mockIterator = Mockito.mock(Iterator.class);
when(mockWatchEvents.iterator()).thenReturn(mockIterator);
final WatchEvent mockWatchEvent = Mockito.mock(WatchEvent.class);
when(mockIterator.hasNext()).thenReturn(true, false);
when(mockIterator.next()).thenReturn(mockWatchEvent);
// In this case, we receive a trigger event for the directory monitored, and it was the file monitored
when(mockWatchEvent.context()).thenReturn(Paths.get(configFilePath));
when(mockWatchEvent.kind()).thenReturn(ENTRY_MODIFY);
return mockWatchKey;
}
private void establishMockEnvironmentForChangeTests(ConfigurationChangeNotifier configurationChangeNotifier, final WatchKey watchKey) throws Exception {
// Establish the file mock and its parent directory
final Path mockConfigFilePath = Mockito.mock(Path.class);
final Path mockConfigFileParentPath = Mockito.mock(Path.class);
// When getting the parent of the file, get the directory
when(mockConfigFilePath.getParent()).thenReturn(mockConfigFileParentPath);
when(mockWatchService.poll()).thenReturn(watchKey);
}
}