package rocks.inspectit.server.storage; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.sql.Timestamp; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import rocks.inspectit.server.cache.IBuffer; import rocks.inspectit.server.dao.StorageDataDao; import rocks.inspectit.server.test.AbstractTestNGLogSupport; import rocks.inspectit.shared.all.communication.DefaultData; import rocks.inspectit.shared.all.exception.BusinessException; import rocks.inspectit.shared.all.serializer.SerializationException; import rocks.inspectit.shared.all.serializer.impl.SerializationManager; import rocks.inspectit.shared.all.serializer.provider.SerializationManagerProvider; import rocks.inspectit.shared.all.version.VersionService; import rocks.inspectit.shared.cs.cmr.service.IServerStatusService; import rocks.inspectit.shared.cs.communication.data.cmr.WritingStatus; import rocks.inspectit.shared.cs.storage.StorageData; import rocks.inspectit.shared.cs.storage.StorageManager; import rocks.inspectit.shared.cs.storage.processor.AbstractDataProcessor; import rocks.inspectit.shared.cs.storage.recording.RecordingProperties; import rocks.inspectit.shared.cs.storage.recording.RecordingState; /** * Test the {@link CmrStorageManager} class. * * @author Ivan Senic * */ @SuppressWarnings("PMD") public class CmrStorageManagerTest extends AbstractTestNGLogSupport { private static final String CMR_VERSION = "v1"; /** * Class under test. */ private CmrStorageManager storageManager; @Mock private StorageDataDao storageDataDao; @Mock private CmrStorageWriterProvider storageWriterProvider; @Mock private CmrStorageRecorder storageRecorder; @Mock private CmrStorageWriter storageWriter; @Mock private SerializationManagerProvider serializationManagerProvider; @Mock private SerializationManager serializer; @Mock private IServerStatusService serverStatusService; @Mock private VersionService versionService; @Mock IBuffer<DefaultData> buffer; private StorageData storageData; /** * Init method. * * @throws Exception */ @BeforeMethod public void init() throws Exception { MockitoAnnotations.initMocks(this); storageManager = new CmrStorageManager(); storageManager.setStorageDefaultFolder("storageTest"); storageManager.storageDataDao = storageDataDao; storageManager.storageWriterProvider = storageWriterProvider; storageManager.storageRecorder = storageRecorder; storageManager.buffer = buffer; storageManager.setSerializationManagerProvider(serializationManagerProvider); storageManager.serverStatusService = serverStatusService; storageManager.log = LoggerFactory.getLogger(CmrStorageManager.class); storageManager.versionService = versionService; when(storageWriterProvider.getCmrStorageWriter()).thenReturn(storageWriter); when(serializationManagerProvider.createSerializer()).thenReturn(serializer); when(versionService.getVersionAsString()).thenReturn(CMR_VERSION); Field field = StorageManager.class.getDeclaredField("log"); field.setAccessible(true); field.set(storageManager, LoggerFactory.getLogger(CmrStorageManager.class)); field = StorageManager.class.getDeclaredField("storageUploadsFolder"); field.setAccessible(true); field.set(storageManager, "uploadTest"); storageManager.postConstruct(); } /** * Test correct creation of storage. */ @Test public void createStorage() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); assertThat(storageData.getId(), is(notNullValue())); assertThat(storageData.getCmrVersion(), is(CMR_VERSION)); assertThat(storageManager.isStorageExisting(storageData), is(true)); assertThat(storageManager.isStorageOpen(storageData), is(false)); assertThat(storageManager.isStorageClosed(storageData), is(false)); assertThat(storageManager.getExistingStorages(), hasSize(1)); assertThat(storageManager.getOpenedStorages(), is(empty())); assertThat(storageManager.getReadableStorages(), is(empty())); } /** * Tests correct opening of storage. */ @Test public void openStorage() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); assertThat(storageManager.isStorageExisting(storageData), is(true)); assertThat(storageManager.isStorageOpen(storageData), is(true)); assertThat(storageManager.isStorageClosed(storageData), is(false)); assertThat(storageManager.getExistingStorages(), hasSize(1)); assertThat(storageManager.getOpenedStorages(), hasSize(1)); assertThat(storageManager.getReadableStorages(), is(empty())); verify(storageWriterProvider, times(1)).getCmrStorageWriter(); verify(storageWriter, times(1)).prepareForWrite(storageData); } /** * Tests that already closed storage can not be opened. */ @Test(expectedExceptions = { BusinessException.class }) public void canNotOpenAlreadyClosed() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); storageManager.closeStorage(storageData); storageManager.openStorage(storageData); } /** * Tests closing of storage. */ @Test public void closeStorage() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); storageManager.closeStorage(storageData); assertThat(storageManager.isStorageExisting(storageData), is(true)); assertThat(storageManager.isStorageOpen(storageData), is(false)); assertThat(storageManager.isStorageClosed(storageData), is(true)); assertThat(storageManager.getExistingStorages(), hasSize(1)); assertThat(storageManager.getOpenedStorages(), is(empty())); assertThat(storageManager.getReadableStorages(), hasSize(1)); // can not verify StorageWriter.closeStorageWriter cause it s final method } /** * Tests closing of all storages. */ @Test public void closeAllStorages() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); storageManager.closeAllStorages(); assertThat(storageManager.isStorageExisting(storageData), is(true)); assertThat(storageManager.isStorageOpen(storageData), is(false)); assertThat(storageManager.isStorageClosed(storageData), is(true)); assertThat(storageManager.getExistingStorages(), hasSize(1)); assertThat(storageManager.getOpenedStorages(), is(empty())); assertThat(storageManager.getReadableStorages(), hasSize(1)); // can not verify StorageWriter.closeStorageWriter cause it s final method } /** * Tests that storage used for recording can not be closed. */ @Test(expectedExceptions = { BusinessException.class }) public void canNotCloseWhileRecording() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); RecordingProperties recordingProperties = mock(RecordingProperties.class); // AbstractDataProcessor dataProcessor = mock(AbstractDataProcessor.class); // when(recordingProperties.getRecordingDataProcessors()).thenReturn(Collections.singleton(dataProcessor)); storageManager.startOrScheduleRecording(storageData, recordingProperties); when(storageRecorder.isRecordingOn()).thenReturn(true); when(storageRecorder.getRecordingState()).thenReturn(RecordingState.ON); when(storageRecorder.getRecordingProperties()).thenReturn(recordingProperties); when(storageRecorder.getStorageWriter()).thenReturn(storageWriter); storageManager.closeStorage(storageData); } /** * Tests start of the recording. */ @Test public void startOrScheduleRecording() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); RecordingProperties recordingProperties = mock(RecordingProperties.class); WritingStatus writingStatus = WritingStatus.GOOD; storageManager.startOrScheduleRecording(storageData, recordingProperties); when(storageRecorder.isRecordingOn()).thenReturn(true); when(storageRecorder.getRecordingState()).thenReturn(RecordingState.ON); when(storageRecorder.getRecordingProperties()).thenReturn(recordingProperties); when(storageRecorder.getStorageWriter()).thenReturn(storageWriter); when(storageWriter.getWritingStatus()).thenReturn(writingStatus); verify(storageRecorder, times(1)).startOrScheduleRecording(storageWriter, recordingProperties); assertThat(storageManager.getRecordingState(), is(RecordingState.ON)); assertThat(storageManager.getRecordingProperties(), is(recordingProperties)); assertThat(storageManager.getRecordingStorage(), is(storageData)); assertThat(storageManager.getRecordingStatus(), is(writingStatus)); } /** * Tests that recording can not be started if it s already running. */ @Test public void canNotStartRecordingWhenAlreadyRunning() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); RecordingProperties recordingProperties = mock(RecordingProperties.class); storageManager.startOrScheduleRecording(storageData, recordingProperties); when(storageRecorder.isRecordingOn()).thenReturn(true); when(storageRecorder.getRecordingState()).thenReturn(RecordingState.ON); when(storageRecorder.getRecordingProperties()).thenReturn(recordingProperties); when(storageRecorder.getStorageWriter()).thenReturn(storageWriter); verify(storageRecorder, times(1)).startOrScheduleRecording(storageWriter, recordingProperties); storageManager.startOrScheduleRecording(storageData, recordingProperties); verify(storageRecorder, times(1)).startOrScheduleRecording(storageWriter, recordingProperties); } /** * Tests stop recording. */ @Test public void stopRecording() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); RecordingProperties recordingProperties = mock(RecordingProperties.class); when(recordingProperties.isAutoFinalize()).thenReturn(true); storageManager.startOrScheduleRecording(storageData, recordingProperties); when(storageRecorder.isRecordingOn()).thenReturn(true); when(storageRecorder.getRecordingState()).thenReturn(RecordingState.ON); when(storageRecorder.getRecordingProperties()).thenReturn(recordingProperties); when(storageRecorder.getStorageWriter()).thenReturn(storageWriter); doAnswer(new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { when(storageRecorder.isRecordingOn()).thenReturn(false); when(storageRecorder.getRecordingState()).thenReturn(RecordingState.OFF); return null; } }).when(storageRecorder).stopRecording(); storageManager.stopRecording(); verify(storageRecorder, times(1)).stopRecording(); assertThat(storageManager.isStorageClosed(storageData), is(true)); // due to auto-finalize assertThat(storageManager.getRecordingState(), is(RecordingState.OFF)); } /** * Tests data to be recorded. */ @Test public void record() { storageManager = spy(storageManager); DefaultData defaultData = mock(DefaultData.class); when(storageManager.canWriteMore()).thenReturn(true); when(storageRecorder.isRecordingOn()).thenReturn(true); storageManager.record(defaultData); verify(storageRecorder, times(1)).record(defaultData); when(storageRecorder.isRecordingOn()).thenReturn(false); } /** * Tests that stop recording will be executed if manager reports that can not write more on * disk. */ @Test public void stopRecordingWhenCanNotWriteMore() throws IOException, SerializationException, BusinessException { storageManager = spy(storageManager); DefaultData defaultData = mock(DefaultData.class); when(storageManager.canWriteMore()).thenReturn(false); when(storageRecorder.isRecordingOn()).thenReturn(true); Mockito.doNothing().when(storageManager).stopRecording(); storageManager.record(defaultData); verify(storageManager, times(1)).stopRecording(); } /** * Tests writing of data to disk. */ @Test public void writeDataToStorage() throws BusinessException, IOException, SerializationException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); Collection<? extends DefaultData> data = Collections.singleton(mock(DefaultData.class)); Collection<AbstractDataProcessor> processors = Collections.singleton(mock(AbstractDataProcessor.class)); // first synchronously storageManager.writeToStorage(storageData, data, processors, true); verify(storageWriter, times(1)).processSynchronously(data, processors); // then asynchronously storageManager.writeToStorage(storageData, data, processors, false); verify(storageWriter, times(1)).process(data, processors); } /** * Proves that no writing can be done to a closed storage. */ @Test(expectedExceptions = { BusinessException.class }) public void canNotWriteToClosedStorage() throws BusinessException, IOException, SerializationException { storageData = new StorageData(); storageData.setName("Test"); storageManager.createStorage(storageData); storageManager.openStorage(storageData); storageManager.closeStorage(storageData); Collection<? extends DefaultData> data = Collections.singleton(mock(DefaultData.class)); Collection<AbstractDataProcessor> processors = Collections.singleton(mock(AbstractDataProcessor.class)); // first synchronously storageManager.writeToStorage(storageData, data, processors, true); } /** * Tests copy buffer action. */ @Test public void copyBufferToStorage() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); DefaultData defaultData = mock(DefaultData.class); Timestamp timestamp = mock(Timestamp.class); when(defaultData.getTimeStamp()).thenReturn(timestamp); when(buffer.getOldestElement()).thenReturn(defaultData); List<DefaultData> data = Collections.singletonList(mock(DefaultData.class)); Collection<AbstractDataProcessor> processors = Collections.singleton(mock(AbstractDataProcessor.class)); Long platformId = 10L; List<Long> platformIdents = Collections.singletonList(platformId); storageManager = spy(storageManager); when(storageDataDao.getAllDefaultDataForAgent(eq(platformId), Matchers.<Date> any(), Matchers.<Date> any())).thenReturn(data); // first with no auto-finalize storageManager.copyBufferToStorage(storageData, platformIdents, processors, false); verify(storageDataDao, times(1)).getAllDefaultDataForAgent(eq(platformId), Matchers.<Date> any(), Matchers.<Date> any()); verify(storageManager, times(1)).writeToStorage(storageData, data, processors, true); // first with auto-finalize storageManager.copyBufferToStorage(storageData, platformIdents, processors, true); verify(storageDataDao, times(2)).getAllDefaultDataForAgent(eq(platformId), Matchers.<Date> any(), Matchers.<Date> any()); verify(storageManager, times(2)).writeToStorage(storageData, data, processors, true); assertThat(storageManager.isStorageClosed(storageData), is(true)); } /** * Tests copy data to storage action. */ @SuppressWarnings("unchecked") public void copyDataToStorage() throws IOException, SerializationException, BusinessException { storageData = new StorageData(); storageData.setName("Test"); List<DefaultData> data = Collections.singletonList(mock(DefaultData.class)); Collection<AbstractDataProcessor> processors = Collections.singleton(mock(AbstractDataProcessor.class)); storageManager = spy(storageManager); long platformIdent = 10L; Collection<Long> elementIds = mock(Collection.class); when(storageDataDao.getDataFromIdList(elementIds, platformIdent)).thenReturn(data); // first with no auto-finalize storageManager.copyDataToStorage(storageData, elementIds, platformIdent, processors, false); verify(storageDataDao, times(1)).getDataFromIdList(elementIds, platformIdent); verify(storageManager, times(1)).writeToStorage(storageData, data, processors, true); // first with auto-finalize storageManager.copyDataToStorage(storageData, elementIds, platformIdent, processors, false); verify(storageDataDao, times(2)).getDataFromIdList(elementIds, platformIdent); verify(storageManager, times(2)).writeToStorage(storageData, data, processors, true); assertThat(storageManager.isStorageClosed(storageData), is(true)); } /** * After processing to delete storage that might be created in the test. */ @AfterMethod public void deleteStorage() throws BusinessException, IOException, SerializationException { if (null != storageData) { if (storageManager.getRecordingState() == RecordingState.ON) { storageManager.stopRecording(); } if (!storageManager.isStorageClosed(storageData)) { storageManager.closeStorage(storageData); } storageManager.deleteStorage(storageData); storageData = null; } assertThat(storageManager.getExistingStorages(), is(empty())); } /** * After tests delete created folders. */ @AfterTest public void deleteFolders() throws IOException { Files.deleteIfExists(Paths.get(storageManager.getStorageDefaultFolder())); Files.deleteIfExists(Paths.get(storageManager.getStorageUploadsFolder())); } }