Преглед на файлове

Using AsynchronousFileChannel

* Replaced FileChannel with AsynchronousFileChannel
* Adapted tests
** transferTo tests and exception handling tests still pending (see
TODOs)
Markus Kreusch преди 9 години
родител
ревизия
8ff5659680

+ 0 - 3
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FolderCopyToTests.java

@@ -13,7 +13,6 @@ import org.cryptomator.filesystem.Folder;
 import org.cryptomator.filesystem.invariants.FileSystemFactories.FileSystemFactory;
 import org.cryptomator.filesystem.invariants.WaysToObtainAFile.WayToObtainAFile;
 import org.cryptomator.filesystem.invariants.WaysToObtainAFolder.WayToObtainAFolder;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.experimental.theories.DataPoints;
 import org.junit.experimental.theories.Theories;
@@ -104,8 +103,6 @@ public class FolderCopyToTests {
 	}
 
 	@Theory
-	@Ignore
-	// FIXME not working yet due to concurrent access to and interruption of channel
 	public void testCopyAFolderWithChildrenCopiesChildrenRecursive(FileSystemFactory fileSystemFactory, WayToObtainAFolder wayToObtainAnExistingFolder, WayToObtainAFile wayToObtainAnExisitingFile,
 			WayToObtainAFolder wayToObtainANonExistingFolder) {
 

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

@@ -1,7 +1,7 @@
 package org.cryptomator.filesystem.nio;
 
 import java.io.IOException;
-import java.nio.channels.FileChannel;
+import java.nio.channels.AsynchronousFileChannel;
 import java.nio.file.CopyOption;
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
@@ -17,8 +17,8 @@ import java.util.stream.Stream;
 class DefaultNioAccess implements NioAccess {
 
 	@Override
-	public FileChannel open(Path path, OpenOption... options) throws IOException {
-		return FileChannel.open(path, options);
+	public AsynchronousFileChannel open(Path path, OpenOption... options) throws IOException {
+		return AsynchronousFileChannel.open(path, options);
 	}
 
 	@Override
@@ -57,7 +57,7 @@ class DefaultNioAccess implements NioAccess {
 	}
 
 	@Override
-	public void close(FileChannel channel) throws IOException {
+	public void close(AsynchronousFileChannel channel) throws IOException {
 		channel.close();
 	}
 

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

@@ -1,7 +1,7 @@
 package org.cryptomator.filesystem.nio;
 
 import java.io.IOException;
-import java.nio.channels.FileChannel;
+import java.nio.channels.AsynchronousFileChannel;
 import java.nio.file.CopyOption;
 import java.nio.file.LinkOption;
 import java.nio.file.OpenOption;
@@ -16,7 +16,7 @@ interface NioAccess {
 
 	public static final Holder<NioAccess> DEFAULT = new Holder<>(new DefaultNioAccess());
 
-	FileChannel open(Path path, OpenOption... options) throws IOException;
+	AsynchronousFileChannel open(Path path, OpenOption... options) throws IOException;
 
 	boolean isRegularFile(Path path, LinkOption... options);
 
@@ -32,7 +32,7 @@ interface NioAccess {
 
 	void delete(Path path) throws IOException;
 
-	void close(FileChannel channel) throws IOException;
+	void close(AsynchronousFileChannel channel) throws IOException;
 
 	void move(Path source, Path target, CopyOption... options) throws IOException;
 

+ 31 - 14
main/filesystem-nio/src/main/java/org/cryptomator/filesystem/nio/SharedFileChannel.java

@@ -3,12 +3,14 @@ package org.cryptomator.filesystem.nio;
 import static java.lang.String.format;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
+import java.nio.channels.AsynchronousFileChannel;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -22,7 +24,7 @@ class SharedFileChannel {
 
 	private Lock lock = new ReentrantLock();
 
-	private FileChannel delegate;
+	private AsynchronousFileChannel delegate;
 
 	public SharedFileChannel(Path path, NioAccess nioAccess) {
 		this.path = path;
@@ -92,16 +94,18 @@ class SharedFileChannel {
 		assertOpen();
 		try {
 			return tryReadFully(position, target);
-		} catch (IOException e) {
-			throw new UncheckedIOException(e);
+		} catch (InterruptedException e) {
+			throw new UncheckedIOException(new InterruptedIOException("read has been interrupted"));
+		} catch (ExecutionException e) {
+			throw new UncheckedIOException(new IOException(e));
 		}
 	}
 
-	private int tryReadFully(long position, ByteBuffer target) throws IOException {
+	private int tryReadFully(long position, ByteBuffer target) throws InterruptedException, ExecutionException {
 		int initialRemaining = target.remaining();
 		long maxPosition = position + initialRemaining;
 		do {
-			if (delegate.read(target, maxPosition - target.remaining()) == EOF) {
+			if (delegate.read(target, maxPosition - target.remaining()).get() == EOF) {
 				if (initialRemaining == target.remaining()) {
 					return EOF;
 				} else {
@@ -137,14 +141,25 @@ class SharedFileChannel {
 			throw new IllegalArgumentException("Count must not be negative");
 		}
 		try {
+			ByteBuffer buffer = ByteBuffer.allocate(32 * 1024);
 			long maxPosition = Math.min(delegate.size(), position + count);
 			long transferCount = Math.max(0, maxPosition - position);
-			long remaining = transferCount;
-			targetChannel.delegate.position(targetPosition);
-			while (remaining > 0) {
-				remaining -= delegate.transferTo(maxPosition - remaining, remaining, targetChannel.delegate);
+			long transferred = 0;
+			while (transferred < transferCount) {
+				int read = delegate.read(buffer, position + transferred).get();
+				if (read == -1) {
+					throw new IllegalStateException("Reached end of file during transfer to");
+				}
+				buffer.flip();
+				while (buffer.hasRemaining()) {
+					transferred += targetChannel.delegate.write(buffer, targetPosition + transferred).get();
+				}
 			}
 			return transferCount;
+		} catch (InterruptedException e) {
+			throw new UncheckedIOException(new InterruptedIOException("read has been interrupted"));
+		} catch (ExecutionException e) {
+			throw new UncheckedIOException(new IOException(e));
 		} catch (IOException e) {
 			throw new UncheckedIOException(e);
 		}
@@ -163,16 +178,18 @@ class SharedFileChannel {
 		assertOpen();
 		try {
 			return tryWriteFully(position, source);
-		} catch (IOException e) {
-			throw new UncheckedIOException(e);
+		} catch (InterruptedException e) {
+			throw new UncheckedIOException(new InterruptedIOException("read has been interrupted"));
+		} catch (ExecutionException e) {
+			throw new UncheckedIOException(new IOException(e));
 		}
 	}
 
-	private int tryWriteFully(long position, ByteBuffer source) throws IOException {
+	private int tryWriteFully(long position, ByteBuffer source) throws InterruptedException, ExecutionException {
 		int count = source.remaining();
 		long maxPosition = position + count;
 		do {
-			delegate.write(source, maxPosition - source.remaining());
+			delegate.write(source, maxPosition - source.remaining()).get();
 		} while (source.hasRemaining());
 		return count;
 	}

+ 6 - 12
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/DefaultNioAccessTest.java

@@ -15,7 +15,7 @@ import static org.mockito.Mockito.when;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.nio.channels.FileChannel;
+import java.nio.channels.AsynchronousFileChannel;
 import java.nio.file.CopyOption;
 import java.nio.file.DirectoryStream;
 import java.nio.file.FileSystem;
@@ -64,10 +64,10 @@ public class DefaultNioAccessTest {
 	@Test
 	public void testOpenCallsOpenOnProvider() throws IOException {
 		OpenOption[] options = {StandardOpenOption.APPEND};
-		FileChannel channel = mock(FileChannel.class);
-		when(provider.newFileChannel(path, new HashSet<>(asList(options)))).thenReturn(channel);
+		AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
+		when(provider.newAsynchronousFileChannel(path, new HashSet<>(asList(options)), null, new FileAttribute[0])).thenReturn(channel);
 
-		FileChannel result = inTest.open(path, options);
+		AsynchronousFileChannel result = inTest.open(path, options);
 
 		assertThat(result, is(channel));
 	}
@@ -177,17 +177,11 @@ public class DefaultNioAccessTest {
 
 	@Test
 	public void testCloseInvokesCloseOnChannel() throws IOException {
-		Runnable implCloseChannel = mock(Runnable.class);
-		FileChannel channel = new FileChannelAdapter() {
-			@Override
-			public void implCloseChannel() throws IOException {
-				implCloseChannel.run();
-			}
-		};
+		AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 
 		inTest.close(channel);
 
-		verify(implCloseChannel).run();
+		verify(channel).close();
 	}
 
 	@Test

+ 0 - 96
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/FileChannelAdapter.java

@@ -1,96 +0,0 @@
-package org.cryptomator.filesystem.nio;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.MappedByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.channels.WritableByteChannel;
-
-class FileChannelAdapter extends FileChannel {
-
-	@Override
-	public int read(ByteBuffer dst) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public int write(ByteBuffer src) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public long position() throws IOException {
-		return 0;
-	}
-
-	@Override
-	public FileChannel position(long newPosition) throws IOException {
-		return null;
-	}
-
-	@Override
-	public long size() throws IOException {
-		return 0;
-	}
-
-	@Override
-	public FileChannel truncate(long size) throws IOException {
-		return null;
-	}
-
-	@Override
-	public void force(boolean metaData) throws IOException {
-	}
-
-	@Override
-	public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public int read(ByteBuffer dst, long position) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public int write(ByteBuffer src, long position) throws IOException {
-		return 0;
-	}
-
-	@Override
-	public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
-		return null;
-	}
-
-	@Override
-	public FileLock lock(long position, long size, boolean shared) throws IOException {
-		return null;
-	}
-
-	@Override
-	public FileLock tryLock(long position, long size, boolean shared) throws IOException {
-		return null;
-	}
-
-	@Override
-	public void implCloseChannel() throws IOException {
-	}
-
-}

+ 161 - 154
main/filesystem-nio/src/test/java/org/cryptomator/filesystem/nio/SharedFileChannelTest.java

@@ -1,11 +1,11 @@
 package org.cryptomator.filesystem.nio;
 
 import static java.lang.String.format;
+import static org.apache.commons.lang3.concurrent.ConcurrentUtils.constantFuture;
 import static org.cryptomator.filesystem.nio.SharedFileChannel.EOF;
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyLong;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
@@ -17,9 +17,11 @@ import static org.mockito.Mockito.when;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
+import java.nio.channels.AsynchronousFileChannel;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 
 import org.cryptomator.common.Holder;
 import org.junit.Before;
@@ -122,7 +124,7 @@ public class SharedFileChannelTest {
 		public void testOpenDoesNotOpenChannelTwiceIfInvokedTwiceByDifferentThreads() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(mock(FileChannel.class));
+			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(mock(AsynchronousFileChannel.class));
 
 			inThreadRethrowingException(() -> inTest.open(OpenMode.WRITE));
 			inThreadRethrowingException(() -> inTest.open(OpenMode.WRITE));
@@ -146,7 +148,7 @@ public class SharedFileChannelTest {
 		public void testCloseIfClosedFails() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(mock(FileChannel.class));
+			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(mock(AsynchronousFileChannel.class));
 			inTest.open(OpenMode.WRITE);
 			inTest.close();
 
@@ -160,7 +162,7 @@ public class SharedFileChannelTest {
 		public void testCloseForcesAndClosesChannel() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			FileChannel channel = mock(FileChannel.class);
+			AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 
@@ -175,7 +177,7 @@ public class SharedFileChannelTest {
 		public void testCloseWrapsIOExceptionFromForceInUncheckedIOExceptionAndStillClosesChannel() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			FileChannel channel = mock(FileChannel.class);
+			AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 			IOException exceptionFromForce = new IOException();
@@ -195,7 +197,7 @@ public class SharedFileChannelTest {
 		public void testCloseWrapsIOExceptionFromCloseInUncheckedIOException() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			FileChannel channel = mock(FileChannel.class);
+			AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 			IOException exceptionFromClose = new IOException();
@@ -211,7 +213,7 @@ public class SharedFileChannelTest {
 		public void testCloseDoesNotCloseChannelIfOpenedTwice() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			FileChannel channel = mock(FileChannel.class);
+			AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 			inThreadRethrowingException(() -> inTest.open(OpenMode.WRITE));
@@ -225,7 +227,7 @@ public class SharedFileChannelTest {
 		public void testLastCloseDoesCloseChannelIfOpenedTwice() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(false);
-			FileChannel channel = mock(FileChannel.class);
+			AsynchronousFileChannel channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 			inThreadRethrowingException(() -> {
@@ -245,25 +247,27 @@ public class SharedFileChannelTest {
 		@Rule
 		public Timeout timeoutRule = Timeout.seconds(1);
 
-		private FileChannel channel;
+		private AsynchronousFileChannel channel;
 
 		@Before
 		public void setUp() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(true);
-			channel = mock(FileChannel.class);
+			channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.READ);
 		}
 
 		@Test
-		public void testReadFullyWrapsExceptionFromReadInUncheckedIOException() throws IOException {
+		public void testReadFullyWrapsExceptionFromReadInUncheckedIOException() throws InterruptedException, ExecutionException {
 			ByteBuffer buffer = ByteBuffer.allocate(0);
-			IOException exceptionFromRead = new IOException();
-			when(channel.read(buffer, 0)).thenThrow(exceptionFromRead);
+			ExecutionException exceptionFromRead = new ExecutionException(new IOException());
+			Future<Integer> result = mock(Future.class);
+			when(channel.read(buffer, 0)).thenReturn(result);
+			when(result.get()).thenThrow(exceptionFromRead);
 
 			thrown.expect(UncheckedIOException.class);
-			thrown.expectCause(is(exceptionFromRead));
+			thrown.expectCause(is(instanceOf(IOException.class))); // TODO check correct cause of cause
 
 			inTest.readFully(0, buffer);
 		}
@@ -271,11 +275,11 @@ public class SharedFileChannelTest {
 		@Test
 		public void testReadFullyDelegatesToChannelRead() throws IOException {
 			ByteBuffer buffer = ByteBuffer.allocate(50);
-			when(channel.read(buffer, 0)).thenAnswer(new Answer<Integer>() {
+			when(channel.read(buffer, 0)).thenAnswer(new Answer<Future<Integer>>() {
 				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
+				public Future<Integer> answer(InvocationOnMock invocation) throws Throwable {
 					buffer.position(50);
-					return 50;
+					return constantFuture(50);
 				}
 			});
 
@@ -289,7 +293,7 @@ public class SharedFileChannelTest {
 		@Test
 		public void testReadFullyReturnsEofWhenFirstReadReturnsIt() throws IOException {
 			ByteBuffer buffer = ByteBuffer.allocate(50);
-			when(channel.read(buffer, 0)).thenReturn(EOF);
+			when(channel.read(buffer, 0)).thenReturn(constantFuture(EOF));
 
 			int result = inTest.readFully(0, buffer);
 
@@ -302,7 +306,7 @@ public class SharedFileChannelTest {
 		public void testReadStopsReadingIfEofIsReached() throws IOException {
 			ByteBuffer buffer = ByteBuffer.allocate(50);
 			when(channel.read(buffer, 0)).thenAnswer(simulateRead(20, buffer));
-			when(channel.read(buffer, 20)).thenReturn(EOF);
+			when(channel.read(buffer, 20)).thenReturn(constantFuture(EOF));
 
 			int result = inTest.readFully(0, buffer);
 
@@ -328,12 +332,12 @@ public class SharedFileChannelTest {
 			verifyNoMoreInteractions(channel);
 		}
 
-		private Answer<Integer> simulateRead(int amount, ByteBuffer target) {
-			return new Answer<Integer>() {
+		private Answer<Future<Integer>> simulateRead(int amount, ByteBuffer target) {
+			return new Answer<Future<Integer>>() {
 				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
+				public Future<Integer> answer(InvocationOnMock invocation) throws Throwable {
 					target.position(target.position() + amount);
-					return amount;
+					return constantFuture(amount);
 				}
 			};
 		}
@@ -342,13 +346,13 @@ public class SharedFileChannelTest {
 
 	public class Truncate {
 
-		private FileChannel channel;
+		private AsynchronousFileChannel channel;
 
 		@Before
 		public void setUp() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(true);
-			channel = mock(FileChannel.class);
+			channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 		}
@@ -378,13 +382,13 @@ public class SharedFileChannelTest {
 
 	public class Size {
 
-		private FileChannel channel;
+		private AsynchronousFileChannel channel;
 
 		@Before
 		public void setUp() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(true);
-			channel = mock(FileChannel.class);
+			channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 		}
@@ -412,148 +416,151 @@ public class SharedFileChannelTest {
 
 	}
 
-	public class TransferTo {
-
-		private FileChannel channel;
-
-		private Path targetPath;
-		private SharedFileChannel targetInTest;
-		private FileChannel targetChannel;
-
-		@Before
-		public void setUp() throws IOException {
-			targetPath = mock(Path.class);
-			targetInTest = new SharedFileChannel(targetPath, nioAccess);
-
-			when(nioAccess.isDirectory(path)).thenReturn(false);
-			when(nioAccess.isRegularFile(path)).thenReturn(true);
-			channel = mock(FileChannel.class);
-			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
-			inTest.open(OpenMode.WRITE);
-
-			when(nioAccess.isDirectory(targetPath)).thenReturn(false);
-			when(nioAccess.isRegularFile(targetPath)).thenReturn(true);
-			targetChannel = mock(FileChannel.class);
-			when(nioAccess.open(targetPath, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(targetChannel);
-			targetInTest.open(OpenMode.WRITE);
-		}
-
-		@Test
-		public void testTransferToThrowsIllegalArugmentExceptionIfCountIsNegative() {
-			thrown.expect(IllegalArgumentException.class);
-			thrown.expectMessage("Count must not be negative");
-
-			inTest.transferTo(0, -1, targetInTest, 0);
-		}
-
-		@Test
-		public void testTransferToSetsPositionOfTargetChannelAndThenDelegatesToChannelsTransferTo() throws IOException {
-			long targetPosition = 43L;
-			long startPosition = 22L;
-			long count = 39L;
-			when(channel.transferTo(startPosition, count, targetChannel)).thenReturn(count);
-			when(channel.size()).thenReturn(startPosition + count);
-
-			long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
-
-			assertThat(result, is(count));
-			InOrder inOrder = inOrder(channel, targetChannel);
-			inOrder.verify(targetChannel).position(targetPosition);
-			inOrder.verify(channel).transferTo(startPosition, count, targetChannel);
-		}
-
-		@Test
-		public void testTransferToInvokesTransferUntilAllBytesHaveBeenTransferred() throws IOException {
-			long targetPosition = 43L;
-			long startPosition = 22L;
-			long count = 39L;
-			long firstTransferCount = 10L;
-			long secondTransferCount = 7L;
-			long thridTransferCount = count - firstTransferCount - secondTransferCount;
-			when(channel.transferTo(startPosition, count, targetChannel)).thenReturn(firstTransferCount);
-			when(channel.transferTo(startPosition + firstTransferCount, count - firstTransferCount, targetChannel)).thenReturn(secondTransferCount);
-			when(channel.transferTo(startPosition + firstTransferCount + secondTransferCount, thridTransferCount, targetChannel)).thenReturn(thridTransferCount);
-			when(channel.size()).thenReturn(startPosition + count);
-
-			long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
-
-			assertThat(result, is(count));
-			InOrder inOrder = inOrder(channel, targetChannel);
-			inOrder.verify(targetChannel).position(targetPosition);
-			inOrder.verify(channel).transferTo(startPosition, count, targetChannel);
-			inOrder.verify(channel).transferTo(startPosition + firstTransferCount, count - firstTransferCount, targetChannel);
-			inOrder.verify(channel).transferTo(startPosition + firstTransferCount + secondTransferCount, thridTransferCount, targetChannel);
-		}
-
-		@Test
-		public void testTransferToStopsTransferAtEndOfSourceFile() throws IOException {
-			long targetPosition = 43L;
-			long startPosition = 22L;
-			long count = 39L;
-			long countAvailable = 30L;
-			when(channel.transferTo(startPosition, countAvailable, targetChannel)).thenReturn(countAvailable);
-			when(channel.size()).thenReturn(startPosition + countAvailable);
-
-			long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
-
-			assertThat(result, is(countAvailable));
-			InOrder inOrder = inOrder(channel, targetChannel);
-			inOrder.verify(targetChannel).position(targetPosition);
-			inOrder.verify(channel).transferTo(startPosition, countAvailable, targetChannel);
-		}
-
-		@Test
-		public void testTransferToWrapsIOExceptionFromPositionInUncheckedIOException() throws IOException {
-			when(channel.size()).thenReturn(Long.MAX_VALUE);
-			IOException exceptionFromPosition = new IOException();
-			when(targetChannel.position(anyLong())).thenThrow(exceptionFromPosition);
-
-			thrown.expect(UncheckedIOException.class);
-			thrown.expectCause(is(exceptionFromPosition));
-
-			inTest.transferTo(0L, 10L, targetInTest, 0L);
-		}
-
-		@Test
-		public void testTransferToWrapsIOExceptionFromTransferToInUncheckedIOException() throws IOException {
-			when(channel.size()).thenReturn(Long.MAX_VALUE);
-			IOException exceptionFromTransferTo = new IOException();
-			when(channel.transferTo(anyLong(), anyLong(), any())).thenThrow(exceptionFromTransferTo);
-
-			thrown.expect(UncheckedIOException.class);
-			thrown.expectCause(is(exceptionFromTransferTo));
-
-			inTest.transferTo(0L, 10L, targetInTest, 0L);
-		}
-
-	}
+	// TODO fix / implement tests
+	// public class TransferTo {
+	//
+	// private AsynchronousFileChannel channel;
+	//
+	// private Path targetPath;
+	// private SharedFileChannel targetInTest;
+	// private AsynchronousFileChannel targetChannel;
+	//
+	// @Before
+	// public void setUp() throws IOException {
+	// targetPath = mock(Path.class);
+	// targetInTest = new SharedFileChannel(targetPath, nioAccess);
+	//
+	// when(nioAccess.isDirectory(path)).thenReturn(false);
+	// when(nioAccess.isRegularFile(path)).thenReturn(true);
+	// channel = mock(AsynchronousFileChannel.class);
+	// when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
+	// inTest.open(OpenMode.WRITE);
+	//
+	// when(nioAccess.isDirectory(targetPath)).thenReturn(false);
+	// when(nioAccess.isRegularFile(targetPath)).thenReturn(true);
+	// targetChannel = mock(AsynchronousFileChannel.class);
+	// when(nioAccess.open(targetPath, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(targetChannel);
+	// targetInTest.open(OpenMode.WRITE);
+	// }
+	//
+	// @Test
+	// public void testTransferToThrowsIllegalArugmentExceptionIfCountIsNegative() {
+	// thrown.expect(IllegalArgumentException.class);
+	// thrown.expectMessage("Count must not be negative");
+	//
+	// inTest.transferTo(0, -1, targetInTest, 0);
+	// }
+	//
+	// @Test
+	// public void testTransferToSetsPositionOfTargetChannelAndThenDelegatesToChannelsTransferTo() throws IOException {
+	// long targetPosition = 43L;
+	// long startPosition = 22L;
+	// long count = 39L;
+	// when(channel.transferTo(startPosition, count, targetChannel)).thenReturn(count);
+	// when(channel.size()).thenReturn(startPosition + count);
+	//
+	// long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
+	//
+	// assertThat(result, is(count));
+	// InOrder inOrder = inOrder(channel, targetChannel);
+	// inOrder.verify(targetChannel).position(targetPosition);
+	// inOrder.verify(channel).transferTo(startPosition, count, targetChannel);
+	// }
+	//
+	// @Test
+	// public void testTransferToInvokesTransferUntilAllBytesHaveBeenTransferred() throws IOException {
+	// long targetPosition = 43L;
+	// long startPosition = 22L;
+	// long count = 39L;
+	// long firstTransferCount = 10L;
+	// long secondTransferCount = 7L;
+	// long thridTransferCount = count - firstTransferCount - secondTransferCount;
+	// when(channel.transferTo(startPosition, count, targetChannel)).thenReturn(firstTransferCount);
+	// when(channel.transferTo(startPosition + firstTransferCount, count - firstTransferCount, targetChannel)).thenReturn(secondTransferCount);
+	// when(channel.transferTo(startPosition + firstTransferCount + secondTransferCount, thridTransferCount, targetChannel)).thenReturn(thridTransferCount);
+	// when(channel.size()).thenReturn(startPosition + count);
+	//
+	// long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
+	//
+	// assertThat(result, is(count));
+	// InOrder inOrder = inOrder(channel, targetChannel);
+	// inOrder.verify(targetChannel).position(targetPosition);
+	// inOrder.verify(channel).transferTo(startPosition, count, targetChannel);
+	// inOrder.verify(channel).transferTo(startPosition + firstTransferCount, count - firstTransferCount, targetChannel);
+	// inOrder.verify(channel).transferTo(startPosition + firstTransferCount + secondTransferCount, thridTransferCount, targetChannel);
+	// }
+	//
+	// @Test
+	// public void testTransferToStopsTransferAtEndOfSourceFile() throws IOException {
+	// long targetPosition = 43L;
+	// long startPosition = 22L;
+	// long count = 39L;
+	// long countAvailable = 30L;
+	// when(channel.transferTo(startPosition, countAvailable, targetChannel)).thenReturn(countAvailable);
+	// when(channel.size()).thenReturn(startPosition + countAvailable);
+	//
+	// long result = inTest.transferTo(startPosition, count, targetInTest, targetPosition);
+	//
+	// assertThat(result, is(countAvailable));
+	// InOrder inOrder = inOrder(channel, targetChannel);
+	// inOrder.verify(targetChannel).position(targetPosition);
+	// inOrder.verify(channel).transferTo(startPosition, countAvailable, targetChannel);
+	// }
+	//
+	// @Test
+	// public void testTransferToWrapsIOExceptionFromPositionInUncheckedIOException() throws IOException {
+	// when(channel.size()).thenReturn(Long.MAX_VALUE);
+	// IOException exceptionFromPosition = new IOException();
+	// when(targetChannel.position(anyLong())).thenThrow(exceptionFromPosition);
+	//
+	// thrown.expect(UncheckedIOException.class);
+	// thrown.expectCause(is(exceptionFromPosition));
+	//
+	// inTest.transferTo(0L, 10L, targetInTest, 0L);
+	// }
+	//
+	// @Test
+	// public void testTransferToWrapsIOExceptionFromTransferToInUncheckedIOException() throws IOException {
+	// when(channel.size()).thenReturn(Long.MAX_VALUE);
+	// IOException exceptionFromTransferTo = new IOException();
+	// when(channel.transferTo(anyLong(), anyLong(), any())).thenThrow(exceptionFromTransferTo);
+	//
+	// thrown.expect(UncheckedIOException.class);
+	// thrown.expectCause(is(exceptionFromTransferTo));
+	//
+	// inTest.transferTo(0L, 10L, targetInTest, 0L);
+	// }
+	//
+	// }
 
 	public class WriteFully {
 
 		@Rule
 		public Timeout timeoutRule = Timeout.seconds(1);
 
-		private FileChannel channel;
+		private AsynchronousFileChannel channel;
 
 		@Before
 		public void setUp() throws IOException {
 			when(nioAccess.isDirectory(path)).thenReturn(false);
 			when(nioAccess.isRegularFile(path)).thenReturn(true);
-			channel = mock(FileChannel.class);
+			channel = mock(AsynchronousFileChannel.class);
 			when(nioAccess.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE)).thenReturn(channel);
 			inTest.open(OpenMode.WRITE);
 		}
 
 		@Test
-		public void testWriteFullyWrapsIOExceptionFromWriteIntoUncheckedIOException() throws IOException {
+		public void testWriteFullyWrapsIOExceptionFromWriteIntoUncheckedIOException() throws InterruptedException, ExecutionException {
 			int count = 1;
 			int position = 0;
 			ByteBuffer buffer = ByteBuffer.allocate(count);
-			IOException exceptionFromWrite = new IOException();
-			when(channel.write(buffer, position)).thenThrow(exceptionFromWrite);
+			ExecutionException exceptionFromWrite = new ExecutionException(new IOException());
+			Future<Integer> result = mock(Future.class);
+			when(channel.write(buffer, position)).thenReturn(result);
+			when(result.get()).thenThrow(exceptionFromWrite);
 
 			thrown.expect(UncheckedIOException.class);
-			thrown.expectCause(is(exceptionFromWrite));
+			thrown.expectCause(is(instanceOf(IOException.class))); // TODO check correct cause of cause
 
 			inTest.writeFully(position, buffer);
 		}
@@ -604,12 +611,12 @@ public class SharedFileChannelTest {
 			verify(channel).write(buffer, position);
 		}
 
-		private Answer<Integer> simulateWrite(int amount, ByteBuffer target) {
-			return new Answer<Integer>() {
+		private Answer<Future<Integer>> simulateWrite(int amount, ByteBuffer target) {
+			return new Answer<Future<Integer>>() {
 				@Override
-				public Integer answer(InvocationOnMock invocation) throws Throwable {
+				public Future<Integer> answer(InvocationOnMock invocation) throws Throwable {
 					target.position(target.position() + amount);
-					return amount;
+					return constantFuture(amount);
 				}
 			};
 		}