瀏覽代碼

Tests for filesystem-nio

* Renamed existing tests to ...IntegrationTest
* Created Unit-Tests for Readable- and WritableNioFile (incomplete)
Markus Kreusch 9 年之前
父節點
當前提交
71face8091

+ 6 - 1
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/NioFile.java

@@ -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;
+	}
+
 }

+ 4 - 0
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/ReadableNioFile.java

@@ -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);

+ 3 - 3
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/WritableNioFile.java

@@ -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());
 		}

+ 1 - 1
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFileTest.java

@@ -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();

+ 1 - 1
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFileSystemTest.java

@@ -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();

+ 1 - 1
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/NioFolderTest.java

@@ -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();

+ 313 - 0
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/ReadableNioFileTest.java

@@ -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));
+	}
+
+}

+ 169 - 0
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/WritableNioFileTest.java

@@ -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));
+	}
+
+}