Tests for filesystem-nio

* Renamed existing tests to ...IntegrationTest
* Created Unit-Tests for Readable- and WritableNioFile (incomplete)
This commit is contained in:
Markus Kreusch
2016-01-01 19:00:31 +01:00
parent 0c2caf4469
commit 71face8091
8 changed files with 498 additions and 7 deletions

View File

@@ -8,6 +8,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.cryptomator.filesystem.File;
@@ -28,7 +29,7 @@ class NioFile extends NioNode implements File {
return sharedChannel;
}
public ReentrantReadWriteLock lock() {
public ReadWriteLock lock() {
return lock;
}
@@ -84,4 +85,8 @@ class NioFile extends NioNode implements File {
return format("NioFile(%s)", path);
}
Path path() {
return path;
}
}

View File

@@ -40,6 +40,9 @@ class ReadableNioFile implements ReadableFile {
@Override
public void position(long position) throws UncheckedIOException {
assertOpen();
if (position < 0) {
throw new IllegalArgumentException();
}
this.position = position;
}
@@ -58,6 +61,7 @@ class ReadableNioFile implements ReadableFile {
}
private void internalCopyTo(WritableNioFile target) {
target.assertOpen();
target.ensureChannelIsOpened();
SharedFileChannel targetChannel = target.channel();
targetChannel.truncate(0);

View File

@@ -105,7 +105,7 @@ class WritableNioFile implements WritableFile {
assertOpen();
try {
closeChannelIfOpened();
Files.delete(nioFile.path);
Files.delete(nioFile.path());
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
@@ -155,11 +155,11 @@ class WritableNioFile implements WritableFile {
return nioFile.path;
}
public NioFile nioFile() {
NioFile nioFile() {
return nioFile;
}
private void assertOpen() {
void assertOpen() {
if (!open) {
throw new UncheckedIOException(format("%s already closed.", this), new ClosedChannelException());
}

View File

@@ -28,7 +28,7 @@ import org.junit.runner.RunWith;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
@RunWith(HierarchicalContextRunner.class)
public class NioFileTest {
public class NioFileIntegrationTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

View File

@@ -16,7 +16,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class NioFileSystemTest {
public class NioFileSystemIntegrationTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

View File

@@ -31,7 +31,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class NioFolderTest {
public class NioFolderIntegrationTest {
@Rule
public ExpectedException thrown = ExpectedException.none();

View File

@@ -0,0 +1,313 @@
package org.cryptomator.filesystem.nio;
import static org.cryptomator.filesystem.nio.OpenMode.READ;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
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.UncheckedIOException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
@RunWith(HierarchicalContextRunner.class)
@SuppressWarnings("resource")
public class ReadableNioFileTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private NioFile file;
private SharedFileChannel channel;
private ReadWriteLock lock;
private Lock readLock;
@Before
public void setup() {
file = mock(NioFile.class);
channel = mock(SharedFileChannel.class);
lock = mock(ReadWriteLock.class);
readLock = mock(Lock.class);
when(file.channel()).thenReturn(channel);
when(file.lock()).thenReturn(lock);
when(lock.readLock()).thenReturn(readLock);
}
@Test
public void testConstructorInvokesOpenWithReadModeOnChannelOfNioFile() {
new ReadableNioFile(file);
verify(channel).open(READ);
}
@Test
public void testReadFailsIfClosed() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer irrelevant = null;
inTest.close();
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.read(irrelevant);
}
@Test
public void testPositionFailsIfClosed() {
ReadableNioFile inTest = new ReadableNioFile(file);
int irrelevant = 1;
inTest.close();
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.position(irrelevant);
}
@Test
public void testPositionFailsIfNegative() {
ReadableNioFile inTest = new ReadableNioFile(file);
thrown.expect(IllegalArgumentException.class);
inTest.position(-1);
}
@Test
public void testReadDelegatesToChannelReadFullyWithZeroPositionIfNotSet() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
inTest.read(buffer);
verify(channel).readFully(0, buffer);
}
@Test
public void testReadDelegatesToChannelReadFullyWithPositionAtEndOfPreviousReadIfInvokedTwice() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
int endOfPreviousRead = 10;
when(channel.readFully(0, buffer)).thenReturn(endOfPreviousRead);
inTest.read(buffer);
inTest.read(buffer);
verify(channel).readFully(0, buffer);
verify(channel).readFully(10, buffer);
}
@Test
public void testReadDelegatesToChannelReadFullyWithPositionUnchangedIfPreviousReadReturnedEof() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
when(channel.readFully(0, buffer)).thenReturn(SharedFileChannel.EOF);
inTest.read(buffer);
inTest.read(buffer);
verify(channel, times(2)).readFully(0, buffer);
}
@Test
public void testReadDelegatesToChannelReadFullyWithSetPosition() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
int position = 10;
inTest.position(position);
inTest.read(buffer);
verify(channel).readFully(position, buffer);
}
@Test
public void testReadReturnsValueOfChannelReadFully() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
int expectedResult = 37028;
when(channel.readFully(0, buffer)).thenReturn(expectedResult);
int result = inTest.read(buffer);
assertThat(result, is(expectedResult));
}
@Test
public void testReadDoesNotModifyBuffer() {
ReadableNioFile inTest = new ReadableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
inTest.read(buffer);
verifyZeroInteractions(buffer);
}
public class CopyTo {
@Mock
private NioFile otherFile;
@Mock
private WritableNioFile writableOtherFile;
@Mock
private SharedFileChannel otherChannel;
@Before
public void setup() {
otherFile = mock(NioFile.class);
writableOtherFile = mock(WritableNioFile.class);
otherChannel = mock(SharedFileChannel.class);
when(writableOtherFile.nioFile()).thenReturn(otherFile);
when(writableOtherFile.channel()).thenReturn(otherChannel);
}
@Test
public void testCopyToFailsIfTargetBelongsToOtherFileSystem() {
ReadableNioFile inTest = new ReadableNioFile(file);
when(otherFile.belongsToSameFilesystem(file)).thenReturn(false);
thrown.expect(IllegalArgumentException.class);
inTest.copyTo(writableOtherFile);
}
@Test
public void testCopyToFailsIfSourceIsClosed() {
ReadableNioFile inTest = new ReadableNioFile(file);
when(otherFile.belongsToSameFilesystem(file)).thenReturn(true);
inTest.close();
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.copyTo(writableOtherFile);
}
@Test
public void testCopyToAssertsThatTargetIsOpenEnsuresTargetChannelIsOpenTuncatesItAndTransfersDataFromSourceChannel() {
ReadableNioFile inTest = new ReadableNioFile(file);
when(otherFile.belongsToSameFilesystem(file)).thenReturn(true);
long sizeOfSourceChannel = 3283;
when(channel.size()).thenReturn(sizeOfSourceChannel);
when(channel.transferTo(0, sizeOfSourceChannel, otherChannel)).thenReturn(sizeOfSourceChannel);
inTest.copyTo(writableOtherFile);
InOrder inOrder = inOrder(writableOtherFile, otherChannel, channel);
inOrder.verify(writableOtherFile).assertOpen();
inOrder.verify(writableOtherFile).ensureChannelIsOpened();
inOrder.verify(otherChannel).truncate(0);
inOrder.verify(channel).transferTo(0, sizeOfSourceChannel, otherChannel);
}
@Test
public void testCopyToInvokesTransferToUntilAllBytesHaveBeenTransferred() {
ReadableNioFile inTest = new ReadableNioFile(file);
when(otherFile.belongsToSameFilesystem(file)).thenReturn(true);
long firstTransferAmount = 100;
long secondTransferAmount = 300;
long thirdTransferAmount = 500;
long sizeRemainingAfterSecondTransfer = thirdTransferAmount;
long sizeRemainingAfterFirstTransfer = sizeRemainingAfterSecondTransfer + secondTransferAmount;
long size = sizeRemainingAfterFirstTransfer + firstTransferAmount;
when(channel.size()).thenReturn(size);
when(channel.transferTo(0, size, otherChannel)).thenReturn(firstTransferAmount);
when(channel.transferTo(firstTransferAmount, sizeRemainingAfterFirstTransfer, otherChannel)).thenReturn(secondTransferAmount);
when(channel.transferTo(firstTransferAmount + secondTransferAmount, sizeRemainingAfterSecondTransfer, otherChannel)).thenReturn(thirdTransferAmount);
inTest.copyTo(writableOtherFile);
InOrder inOrder = inOrder(channel);
inOrder.verify(channel).transferTo(0, size, otherChannel);
inOrder.verify(channel).transferTo(firstTransferAmount, sizeRemainingAfterFirstTransfer, otherChannel);
inOrder.verify(channel).transferTo(firstTransferAmount + secondTransferAmount, sizeRemainingAfterSecondTransfer, otherChannel);
}
}
@Test
public void testIsOpenReturnsTrueForNewReadableNioFile() {
ReadableNioFile inTest = new ReadableNioFile(file);
assertThat(inTest.isOpen(), is(true));
}
@Test
public void testIsOpenReturnsFalseForClosed() {
ReadableNioFile inTest = new ReadableNioFile(file);
inTest.close();
assertThat(inTest.isOpen(), is(false));
}
@Test
public void testCloseClosesChannelAndUnlocksReadLock() {
ReadableNioFile inTest = new ReadableNioFile(file);
inTest.close();
InOrder inOrder = Mockito.inOrder(channel, readLock);
inOrder.verify(channel).close();
inOrder.verify(readLock).unlock();
}
@Test
public void testCloseClosesChannelAndUnlocksReadLockOnlyOnceIfInvokedTwice() {
ReadableNioFile inTest = new ReadableNioFile(file);
inTest.close();
inTest.close();
InOrder inOrder = Mockito.inOrder(channel, readLock);
inOrder.verify(channel).close();
inOrder.verify(readLock).unlock();
}
@Test
public void testCloseUnlocksReadLockEvenIfCloseFails() {
ReadableNioFile inTest = new ReadableNioFile(file);
String message = "exceptionMessage";
doThrow(new RuntimeException(message)).when(channel).close();
thrown.expectMessage(message);
try {
inTest.close();
} finally {
verify(readLock).unlock();
}
}
@Test
public void testToString() {
String nioFileToString = file.toString();
ReadableNioFile inTest = new ReadableNioFile(file);
assertThat(inTest.toString(), is("Readable" + nioFileToString));
}
}

View File

@@ -0,0 +1,169 @@
package org.cryptomator.filesystem.nio;
import static org.cryptomator.filesystem.nio.OpenMode.WRITE;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
@RunWith(HierarchicalContextRunner.class)
@SuppressWarnings("resource")
public class WritableNioFileTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private NioFile file;
private SharedFileChannel channel;
private ReadWriteLock lock;
private Lock writeLock;
@Before
public void setup() {
file = mock(NioFile.class);
channel = mock(SharedFileChannel.class);
lock = mock(ReadWriteLock.class);
writeLock = mock(Lock.class);
when(file.channel()).thenReturn(channel);
when(file.lock()).thenReturn(lock);
when(lock.writeLock()).thenReturn(writeLock);
}
@Test
public void testWriteFailsIfClosed() {
WritableNioFile inTest = new WritableNioFile(file);
inTest.close();
ByteBuffer irrelevant = null;
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.write(irrelevant);
}
@Test
public void testPositionFailsIfClosed() {
WritableNioFile inTest = new WritableNioFile(file);
inTest.close();
long irrelevant = 1023;
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.position(irrelevant);
}
@Test
public void testIsOpenReturnsTrueForNewInstance() {
WritableNioFile inTest = new WritableNioFile(file);
assertThat(inTest.isOpen(), is(true));
}
@Test
public void testIsOpenReturnsFalseForClosedInstance() {
WritableNioFile inTest = new WritableNioFile(file);
inTest.close();
assertThat(inTest.isOpen(), is(false));
}
@Test
public void testWriteInvokesChannelsOpenWithModeWriteIfInvokedForTheFirstTimeBeforeInvokingWriteFully() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer irrelevant = null;
inTest.write(irrelevant);
InOrder inOrder = inOrder(channel);
inOrder.verify(channel).open(WRITE);
inOrder.verify(channel).writeFully(0, irrelevant);
}
@Test
public void testWriteDoesNotModifyBuffer() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
inTest.write(buffer);
verifyZeroInteractions(buffer);
}
@Test
public void testWriteInvokesWriteFullyWithZeroPositionIfNotSet() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
inTest.write(buffer);
verify(channel).writeFully(0, buffer);
}
@Test
public void testWriteInvokesWriteFullyWithSetPosition() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
long position = 10;
inTest.position(position);
inTest.write(buffer);
verify(channel).writeFully(position, buffer);
}
@Test
public void testWriteInvokesWriteFullyWithEndOfPreviousWriteIfInvokedTwice() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
int endOfPreviousWrite = 10;
when(channel.writeFully(0, buffer)).thenReturn(endOfPreviousWrite);
inTest.write(buffer);
inTest.write(buffer);
verify(channel).writeFully(endOfPreviousWrite, buffer);
}
@Test
public void testWriteReturnsResultOfWriteFully() {
WritableNioFile inTest = new WritableNioFile(file);
ByteBuffer buffer = mock(ByteBuffer.class);
int resultOfWriteFully = 14;
when(channel.writeFully(0, buffer)).thenReturn(resultOfWriteFully);
int result = inTest.write(buffer);
assertThat(result, is(resultOfWriteFully));
}
@Test
public void testToString() {
String fileToString = file.toString();
WritableNioFile inTest = new WritableNioFile(file);
assertThat(inTest.toString(), is("Writable" + fileToString));
}
}