mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-19 09:06:54 -04:00
Tests for filesystem-nio
* Renamed existing tests to ...IntegrationTest * Created Unit-Tests for Readable- and WritableNioFile (incomplete)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user