package rocks.inspectit.shared.cs.storage;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.esotericsoftware.kryo.io.Output;
import rocks.inspectit.shared.all.communication.DefaultData;
import rocks.inspectit.shared.all.communication.data.TimerData;
import rocks.inspectit.shared.all.serializer.ISerializer;
import rocks.inspectit.shared.all.serializer.SerializationException;
import rocks.inspectit.shared.all.storage.nio.stream.ExtendedByteBufferOutputStream;
import rocks.inspectit.shared.all.storage.nio.stream.StreamProvider;
import rocks.inspectit.shared.cs.indexing.impl.IndexingException;
import rocks.inspectit.shared.cs.storage.StorageWriter.WriteTask;
import rocks.inspectit.shared.cs.storage.nio.WriteReadCompletionRunnable;
import rocks.inspectit.shared.cs.storage.nio.write.WritingChannelManager;
import rocks.inspectit.shared.cs.storage.processor.AbstractDataProcessor;
import rocks.inspectit.shared.cs.storage.processor.write.AbstractWriteDataProcessor;
import rocks.inspectit.shared.cs.storage.util.DeleteFileVisitor;
@SuppressWarnings("PMD")
public class StorageWriterTest {
private StorageWriter storageWriter;
@Mock
private ISerializer serializer;
@Mock
private StreamProvider streamProvider;
@Mock
private ExtendedByteBufferOutputStream extendedByteBufferOutputStream;
@Mock
private WritingChannelManager writingChannelManager;
@Mock
private StorageIndexingTreeHandler storageIndexingTreeHandler;
@Mock
private StorageManager storageManager;
@Mock
private BlockingQueue<ISerializer> serializerQueue;
@Mock
private ScheduledExecutorService scheduledExecutorService;
@Mock
private AbstractWriteDataProcessor writeDataProcessor;
@SuppressWarnings("rawtypes")
@Mock
private ScheduledFuture future;
private Path testPath = Paths.get("myTestPath" + File.separator);
@SuppressWarnings({ "unchecked" })
@BeforeMethod
public void init() throws IndexingException, InterruptedException, IOException {
MockitoAnnotations.initMocks(this);
storageWriter = new StorageWriter();
when(streamProvider.getExtendedByteBufferOutputStream()).thenReturn(extendedByteBufferOutputStream);
when(storageIndexingTreeHandler.startWrite(Matchers.<WriteTask> anyObject())).thenReturn(1);
when(storageManager.canWriteMore()).thenReturn(true);
when(storageManager.getChannelPath(Matchers.<IStorageData> anyObject(), anyInt())).thenReturn(Paths.get("test"));
when(serializerQueue.take()).thenReturn(serializer);
when(scheduledExecutorService.scheduleWithFixedDelay(Matchers.<Runnable> anyObject(), anyLong(), anyLong(), Matchers.<TimeUnit> anyObject())).thenReturn(future);
storageWriter.indexingTreeHandler = storageIndexingTreeHandler;
storageWriter.storageManager = storageManager;
storageWriter.writingChannelManager = writingChannelManager;
storageWriter.streamProvider = streamProvider;
storageWriter.serializerQueue = serializerQueue;
storageWriter.scheduledExecutorService = scheduledExecutorService;
storageWriter.writeDataProcessors = Collections.singletonList(writeDataProcessor);
storageWriter.log = LoggerFactory.getLogger(storageWriter.getClass());
}
@SuppressWarnings("unchecked")
@Test
public void nonSyncProcessing() {
DefaultData defaultData = mock(DefaultData.class);
AbstractDataProcessor dataProcessor = mock(AbstractDataProcessor.class);
Future<Void> future1 = mock(Future.class);
Future<Void> future2 = mock(Future.class);
when(dataProcessor.process(defaultData)).thenReturn(Collections.singletonList(future1));
when(dataProcessor.flush()).thenReturn(Collections.singletonList(future2));
Collection<Future<Void>> futures = storageWriter.process(Collections.singletonList(defaultData), Collections.singletonList(dataProcessor));
verify(dataProcessor, times(1)).setStorageWriter(storageWriter);
verify(dataProcessor, times(1)).process(defaultData);
verify(dataProcessor, times(1)).flush();
verify(dataProcessor, times(1)).setStorageWriter(null);
assertThat(futures, hasSize(2));
assertThat(futures, hasItem(future1));
assertThat(futures, hasItem(future2));
}
@SuppressWarnings("unchecked")
@Test
public void syncProcessing() {
DefaultData defaultData = mock(DefaultData.class);
AbstractDataProcessor dataProcessor = mock(AbstractDataProcessor.class);
Future<Void> future1 = mock(Future.class);
when(dataProcessor.process(defaultData)).thenReturn(Collections.singletonList(future1));
when(future1.isDone()).thenReturn(true);
storageWriter.process(Collections.singletonList(defaultData), Collections.singletonList(dataProcessor));
verify(dataProcessor, times(1)).setStorageWriter(storageWriter);
verify(dataProcessor, times(1)).process(defaultData);
verify(dataProcessor, times(1)).flush();
verify(dataProcessor, times(1)).setStorageWriter(null);
}
@Test
public void writeTaskWriteNotAllowedByStorageManager() {
when(storageManager.canWriteMore()).thenReturn(false);
storageWriter.new WriteTask(new TimerData(), Collections.emptyMap()).run();
verifyZeroInteractions(storageIndexingTreeHandler, extendedByteBufferOutputStream, streamProvider, serializer, serializerQueue, writingChannelManager);
}
@Test
public void writeTaskFailedIndexing() throws IndexingException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
doThrow(new IndexingException("Test msg")).when(storageIndexingTreeHandler).startWrite(writeTask);
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verifyZeroInteractions(serializer, serializerQueue, streamProvider, writingChannelManager);
}
@Test
public void writeTaskZeroChannelReturnedFromIndexing() throws IndexingException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
when(storageIndexingTreeHandler.startWrite(writeTask)).thenReturn(0);
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verifyZeroInteractions(serializer, serializerQueue, streamProvider, writingChannelManager);
}
@Test
public void writeTaskNoSerializerAvailable() throws InterruptedException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
when(serializerQueue.take()).thenReturn(null);
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verifyZeroInteractions(writingChannelManager, streamProvider, extendedByteBufferOutputStream);
}
@Test
public void writeTaskSerializerQueueInterrupted() throws InterruptedException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
doThrow(InterruptedException.class).when(serializerQueue).take();
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verifyZeroInteractions(writingChannelManager, streamProvider, extendedByteBufferOutputStream);
}
@Test
public void writeTaskFailedSerialization() throws SerializationException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
doThrow(SerializationException.class).when(serializer).serialize(anyObject(), Matchers.<Output> anyObject(), Matchers.<Map<?, ?>> anyObject());
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verify(extendedByteBufferOutputStream, times(1)).close();
verify(serializerQueue, times(1)).add(serializer);
verifyZeroInteractions(writingChannelManager);
}
@Test
public void writeTaskExceptionDuringWrite() throws IOException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
doThrow(IOException.class).when(writingChannelManager).write(Matchers.<ExtendedByteBufferOutputStream> anyObject(), Matchers.<Path> anyObject(),
Matchers.<WriteReadCompletionRunnable> anyObject());
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verify(extendedByteBufferOutputStream, times(1)).close();
verify(serializerQueue, times(1)).add(serializer);
}
@Test
public void writeTaskThrowableDuringWrite() throws IOException {
TimerData timerData = new TimerData();
WriteTask writeTask = storageWriter.new WriteTask(timerData, Collections.emptyMap());
doThrow(Throwable.class).when(writingChannelManager).write(Matchers.<ExtendedByteBufferOutputStream> anyObject(), Matchers.<Path> anyObject(),
Matchers.<WriteReadCompletionRunnable> anyObject());
writeTask.run();
verify(storageIndexingTreeHandler, times(1)).writeFailed(writeTask);
verify(extendedByteBufferOutputStream, times(1)).close();
verify(serializerQueue, times(1)).add(serializer);
}
@Test
public void objectWriteNoSerializerAvailable() throws InterruptedException {
when(serializerQueue.take()).thenReturn(null);
storageWriter.writeNonDefaultDataObject(new Object(), "myFile");
verifyZeroInteractions(writingChannelManager, streamProvider, extendedByteBufferOutputStream);
}
@Test
public void objectWriteSerializerQueueInterrupted() throws InterruptedException {
doThrow(InterruptedException.class).when(serializerQueue).take();
storageWriter.writeNonDefaultDataObject(new Object(), "myFile");
verifyZeroInteractions(writingChannelManager, streamProvider, extendedByteBufferOutputStream);
}
@Test
public void objectWriteFailedSerialization() throws Exception {
StorageData storageData = new StorageData();
when(storageManager.getStoragePath(storageData)).thenReturn(testPath);
storageWriter.prepareForWrite(storageData);
doThrow(SerializationException.class).when(serializer).serialize(anyObject(), Matchers.<Output> anyObject(), Matchers.<Map<?, ?>> anyObject());
doThrow(SerializationException.class).when(serializer).serialize(anyObject(), Matchers.<Output> anyObject());
storageWriter.writeNonDefaultDataObject(new Object(), "myFile");
verify(serializerQueue, times(1)).add(serializer);
verifyZeroInteractions(writingChannelManager, extendedByteBufferOutputStream);
}
@AfterTest
public void cleanUp() throws IOException {
if (Files.exists(testPath)) {
Files.walkFileTree(testPath, new DeleteFileVisitor());
}
Files.deleteIfExists(testPath);
}
}