Increase code coverage.

This commit is contained in:
mgabriel 2018-08-22 16:07:35 +02:00
parent e28b54abed
commit bdbc806e85
4 changed files with 146 additions and 3 deletions

View File

@ -74,6 +74,7 @@ dependencies {
testCompile "org.junit.jupiter:junit-jupiter-engine:5.2.0"
testCompile "org.junit.platform:junit-platform-launcher:1.2.0"
testCompile "commons-io:commons-io:2.6"
testCompile "org.mockito:mockito-core:2.21.0"
}
test {

View File

@ -37,11 +37,15 @@ public abstract class AbstractChronicleStore<I, O> implements FluxStore<I, O> {
private final RollCycle rollCycle;
protected AbstractChronicleStore(AbstractChronicleStoreBuilder<I> builder) {
String path = builder.path;
serializer = builder.serializer;
deserializer = builder.deserializer;
rollCycle = builder.rollCycle;
this.queue = SingleChronicleQueueBuilder.binary(path).rollCycle(rollCycle).build();
this.queue = createQueue(builder.path);
}
//package private for testing
SingleChronicleQueue createQueue(String path) {
return SingleChronicleQueueBuilder.binary(path).rollCycle(rollCycle).build();
}
void close() {
@ -84,7 +88,8 @@ public abstract class AbstractChronicleStore<I, O> implements FluxStore<I, O> {
try {
while (!sink.isCancelled()) {
if (sink.requestedFromDownstream() > 0) {
boolean present = tailer.readBytes(b -> sink.next(deserializeValue(b)));
boolean present = tailer.readBytes(b ->
sink.next(deserializeValue(b)));
if (!present) {
if (readerType == ReaderType.ONLY_HISTORY) {
sink.complete();

View File

@ -0,0 +1,136 @@
package ch.streamly.chronicle.flux;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
import java.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import ch.streamly.chronicle.flux.AbstractChronicleStore.AbstractChronicleStoreBuilder;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.bytes.BytesIn;
import net.openhft.chronicle.bytes.ReadBytesMarshallable;
import net.openhft.chronicle.queue.ExcerptTailer;
import net.openhft.chronicle.queue.RollCycle;
import net.openhft.chronicle.queue.impl.WireStore;
import net.openhft.chronicle.queue.impl.single.SingleChronicleQueue;
import reactor.core.Disposable;
import reactor.test.StepVerifier;
class AbstractChronicleStoreTest {
private static final String TEST_VALUE = "testValue";
private AbstractChronicleStore<String, String> store;
private File file;
private SingleChronicleQueue queue;
private ArgumentCaptor<ReadBytesMarshallable> reader;
private ExcerptTailer tailer;
private WireStore wireStore;
@BeforeEach
void setUp() {
RollCycle rollCycle = Mockito.mock(RollCycle.class);
file = Mockito.mock(File.class);
queue = Mockito.mock(SingleChronicleQueue.class);
reader = ArgumentCaptor.forClass(ReadBytesMarshallable.class);
tailer = Mockito.mock(ExcerptTailer.class);
wireStore = Mockito.mock(WireStore.class);
when(queue.createTailer()).thenReturn(tailer);
when(tailer.readBytes(any(ReadBytesMarshallable.class))).thenReturn(true);
when(tailer.queue()).thenReturn(queue);
when(queue.file()).thenReturn(file);
when(file.getAbsolutePath()).thenReturn("");
when(rollCycle.toCycle(anyLong())).thenReturn(0).thenReturn(1);
when(queue.storeForCycle(anyInt(), anyLong(), anyBoolean())).thenReturn(wireStore);
when(wireStore.file()).thenReturn(file);
when(file.delete()).thenReturn(true);
AbstractChronicleStoreBuilder<String> builder = new AbstractChronicleStoreBuilder<String>() {
};
builder.rollCycle(rollCycle);
store = new AbstractChronicleStore<String, String>(builder) {
@Override
SingleChronicleQueue createQueue(String path) {
return queue;
}
@Override
protected String deserializeValue(BytesIn rawData) {
return TEST_VALUE;
}
};
}
@Test
@DisplayName("tests that the file is deleted once it has rolled")
void shouldDeleteAfterRead() {
Disposable sub = store.retrieveAll(true).subscribe();
verify(file, timeout(100)).delete();
sub.dispose();
}
@Test
@DisplayName("tests that the an exception on file deletion is swallowed")
void shouldSwallowExceptionOnFileDelete() {
when(file.delete()).thenThrow(new RuntimeException("Simulated for unit test"));
Disposable sub = store.retrieveAll(true).subscribe();
verify(file, timeout(100)).delete();
sub.dispose();
}
@Test
@DisplayName("tests that failure of file deletion does not send an exception")
void shouldNotFailIfFileNotDeleted() {
when(file.delete()).thenReturn(false);
Disposable sub = store.retrieveAll(true).subscribe();
verify(file, timeout(100)).delete();
sub.dispose();
}
@Test
@DisplayName("tests that a null wirestore throws no exception")
void testNullWirestore() {
when(queue.storeForCycle(anyInt(), anyLong(), anyBoolean())).thenReturn(null);
subscribeToValues();
}
private void subscribeToValues() {
StepVerifier.create(store.retrieveAll(true))
.expectSubscription()
.then(() -> {
verify(tailer, timeout(100).atLeastOnce()).readBytes(reader.capture());
reader.getValue().readMarshallable(Bytes.elasticByteBuffer());
reader.getValue().readMarshallable(Bytes.elasticByteBuffer());
reader.getValue().readMarshallable(Bytes.elasticByteBuffer());
})
.expectNext(TEST_VALUE)
.expectNext(TEST_VALUE)
.expectNext(TEST_VALUE)
.thenCancel()
.verify(Duration.ofMillis(500));
}
@Test
@DisplayName("tests that a null file throws no exception")
void testNullFile() {
when(queue.storeForCycle(anyInt(), anyLong(), anyBoolean())).thenReturn(wireStore);
when(wireStore.file()).thenReturn(null);
subscribeToValues();
}
}

View File

@ -0,0 +1 @@
mock-maker-inline