Removed SharedFileChannel transferTo and corresponding methods

* Removed from SharedFileChannel and Test
* Refactored Copier#copy(File,File) to sequence of truncated, followed
by looping read and write till EOF
* Changed tests accordingly
* Implemented CryptoWritableFile#truncate to make things work
This commit is contained in:
Markus Kreusch
2016-01-24 22:14:06 +01:00
parent e241c5ba05
commit f081e7d3ea
24 changed files with 231 additions and 260 deletions

View File

@@ -0,0 +1,61 @@
package org.cryptomator.common.test.mockito;
import static java.util.Arrays.asList;
import java.util.function.Consumer;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class Answers {
public static <T> Answer<T> collectParameters(Answer<T> answer, Consumer<?>... parameterConsumers) {
return new Answer<T>() {
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
for (int i = 0; i < invocation.getArguments().length; i++) {
if (parameterConsumers.length > i) {
((Consumer) parameterConsumers[i]).accept(invocation.getArguments()[i]);
}
}
return answer.answer(invocation);
}
};
}
@SafeVarargs
public static <T> Answer<T> consecutiveAnswers(Answer<T>... answers) {
if (answers == null || answers.length == 0) {
throw new IllegalArgumentException("Required at least one answer");
}
if (asList(answers).contains(null)) {
throw new IllegalArgumentException("No answers must be null");
}
return new Answer<T>() {
private int nextIndex = 0;
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
try {
return answers[nextIndex].answer(invocation);
} finally {
nextIndex = (nextIndex + 1) % answers.length;
}
}
};
}
public static <T> Answer<T> value(T value) {
return new Answer<T>() {
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
return value;
}
};
}
}

View File

@@ -8,8 +8,14 @@
*******************************************************************************/
package org.cryptomator.filesystem;
import static org.cryptomator.filesystem.File.EOF;
import java.nio.ByteBuffer;
class Copier {
private static final int COPY_BUFFER_SIZE = 128 * 1024;
public static void copy(Folder source, Folder destination) {
assertFoldersAreNotNested(source, destination);
@@ -29,7 +35,15 @@ class Copier {
public static void copy(File source, File destination) {
try (OpenFiles openFiles = DeadlockSafeFileOpener.withReadable(source).andWritable(destination).open()) {
openFiles.readable(source).copyTo(openFiles.writable(destination));
ReadableFile readable = openFiles.readable(source);
WritableFile writable = openFiles.writable(destination);
ByteBuffer buffer = ByteBuffer.allocate(COPY_BUFFER_SIZE);
writable.truncate();
while (readable.read(buffer) != EOF) {
buffer.flip();
writable.write(buffer);
buffer.clear();
}
}
}

View File

@@ -15,6 +15,8 @@ import java.io.UncheckedIOException;
*/
public interface File extends Node, Comparable<File> {
static final int EOF = -1;
/**
* <p>
* Opens this file for reading.

View File

@@ -12,8 +12,6 @@ import java.nio.channels.ReadableByteChannel;
public interface ReadableFile extends ReadableByteChannel {
void copyTo(WritableFile other) throws UncheckedIOException;
/**
* <p>
* Tries to fill the remaining space in the given byte buffer with data from

View File

@@ -12,7 +12,6 @@ import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
public class DelegatingReadableFile implements ReadableFile {
@@ -27,16 +26,6 @@ public class DelegatingReadableFile implements ReadableFile {
return delegate.isOpen();
}
@Override
public void copyTo(WritableFile destination) throws UncheckedIOException {
if (destination instanceof DelegatingWritableFile) {
final WritableFile delegateDest = ((DelegatingWritableFile) destination).delegate;
delegate.copyTo(delegateDest);
} else {
delegate.copyTo(destination);
}
}
@Override
public int read(ByteBuffer target) throws UncheckedIOException {
return delegate.read(target);

View File

@@ -0,0 +1,36 @@
package org.cryptomator.filesystem;
import java.nio.ByteBuffer;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
public class ByteBufferMatcher {
public static Matcher<ByteBuffer> byteBufferFilledWith(int value) {
if (((byte) value) != value) {
throw new IllegalArgumentException("Invalid byte value");
}
return new TypeSafeDiagnosingMatcher<ByteBuffer>(ByteBuffer.class) {
@Override
public void describeTo(Description description) {
description.appendText("a byte buffer filled with " + value);
}
@Override
protected boolean matchesSafely(ByteBuffer item, Description mismatchDescription) {
while (item.hasRemaining()) {
byte currentValue = item.get();
if (currentValue != value) {
mismatchDescription.appendText("a byte buffer containing also " + currentValue);
return false;
}
}
return true;
}
};
}
}

View File

@@ -1,21 +1,35 @@
package org.cryptomator.filesystem;
import static java.util.Arrays.asList;
import static org.cryptomator.common.test.matcher.ContainsMatcher.contains;
import static org.cryptomator.common.test.mockito.Answers.collectParameters;
import static org.cryptomator.common.test.mockito.Answers.consecutiveAnswers;
import static org.cryptomator.common.test.mockito.Answers.value;
import static org.cryptomator.filesystem.File.EOF;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Stream;
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.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.stubbing.Answer;
import de.bechte.junit.runners.context.HierarchicalContextRunner;
@@ -36,11 +50,22 @@ public class CopierTest {
@Mock
private File destination;
@Mock
private ReadableFile readable;
@Mock
private WritableFile writable;
@Before
public void setUp() {
when(source.openReadable()).thenReturn(readable);
when(destination.openWritable()).thenReturn(writable);
}
@Test
public void testCopyFileOpensFilesInSortedOrderIfSourceIsSmallerDestination() {
mockCompareToWithOrder(source, destination);
when(source.openReadable()).thenReturn(mock(ReadableFile.class));
when(destination.openWritable()).thenReturn(mock(WritableFile.class));
when(readable.read(any())).thenReturn(EOF);
Copier.copy(source, destination);
@@ -52,8 +77,7 @@ public class CopierTest {
@Test
public void testCopyFileOpensFilesInSortedOrderIfDestinationIsSmallerSource() {
mockCompareToWithOrder(destination, source);
when(source.openReadable()).thenReturn(mock(ReadableFile.class));
when(destination.openWritable()).thenReturn(mock(WritableFile.class));
when(readable.read(any())).thenReturn(EOF);
Copier.copy(source, destination);
@@ -63,16 +87,46 @@ public class CopierTest {
}
@Test
public void testCopyFileInvokesCopyToOnReadableSourceWithWritableDestintation() {
ReadableFile readableSource = mock(ReadableFile.class);
WritableFile writableDestination = mock(WritableFile.class);
public void testCopyFileReadsAndWritesReadableSourceAndWritableDestintationUntilEof() {
int irrelevantValue = 0;
Collection<byte[]> written = new ArrayList<>();
mockCompareToWithOrder(source, destination);
when(source.openReadable()).thenReturn(readableSource);
when(destination.openWritable()).thenReturn(writableDestination);
byte[] read1 = {1, 48, 32, 33, 22};
byte[] read2 = {4, 3, 1, -2, -8};
when(readable.read(any())).then(consecutiveAnswers(fillBufferWith(read1), fillBufferWith(read2), value(EOF)));
when(writable.write(any())).then(collectParameters(value(irrelevantValue), (ByteBuffer buffer) -> {
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
written.add(data);
}));
Copier.copy(source, destination);
verify(readableSource).copyTo(writableDestination);
InOrder inOrder = inOrder(readable, writable);
inOrder.verify(writable).truncate();
inOrder.verify(readable).read(any());
inOrder.verify(writable).write(any());
inOrder.verify(readable).read(any());
inOrder.verify(writable).write(any());
inOrder.verify(readable).read(any());
inOrder.verify(readable).close();
inOrder.verify(writable).close();
assertThat(written, contains(is(read1), is(read2)));
}
private Answer<Integer> fillBufferWith(byte[] data) {
return new Answer<Integer>() {
@Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
ByteBuffer buffer = invocation.getArgumentAt(0, ByteBuffer.class);
for (byte value : data) {
buffer.put(value);
}
return data.length;
}
};
}
private void mockCompareToWithOrder(File first, File last) {
@@ -105,7 +159,7 @@ public class CopierTest {
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public void testCopyFolderInvokesCopyToOnAllFilesInSourceWithFileWithSameNameFromDestination() {
String filename1 = "nameOfFile1";
String filename2 = "nameOfFile2";
@@ -127,7 +181,7 @@ public class CopierTest {
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
public void testCopyFolderInvokesCopyToOnAllFoldersInSourceWithFolderWithSameNameFromDestination() {
String folderName1 = "nameOfFolder1";
String folderName2 = "nameOfFolder2";

View File

@@ -11,7 +11,6 @@ package org.cryptomator.filesystem.delegating;
import java.nio.ByteBuffer;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
@@ -31,29 +30,6 @@ public class DelegatingReadableFileTest {
Assert.assertFalse(delegatingReadableFile.isOpen());
}
@Test
public void testCopyTo() {
ReadableFile mockReadableFile = Mockito.mock(ReadableFile.class);
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
@SuppressWarnings("resource")
DelegatingReadableFile delegatingReadableFile = new DelegatingReadableFile(mockReadableFile);
DelegatingWritableFile delegatingWritableFile = new DelegatingWritableFile(mockWritableFile);
delegatingReadableFile.copyTo(delegatingWritableFile);
Mockito.verify(mockReadableFile).copyTo(mockWritableFile);
}
@Test
public void testCopyToDestinationFromDifferentLayer() {
ReadableFile mockReadableFile = Mockito.mock(ReadableFile.class);
WritableFile mockWritableFile = Mockito.mock(WritableFile.class);
@SuppressWarnings("resource")
DelegatingReadableFile delegatingReadableFile = new DelegatingReadableFile(mockReadableFile);
delegatingReadableFile.copyTo(mockWritableFile);
Mockito.verify(mockReadableFile).copyTo(mockWritableFile);
}
@Test
public void testRead() {
ReadableFile mockReadableFile = Mockito.mock(ReadableFile.class);

View File

@@ -27,6 +27,11 @@ public interface FileContentEncryptor extends Destroyable, Closeable {
*/
ByteBuffer getHeader();
/**
* @return the size of headers created by this {@code FileContentCryptor}. The length of headers returned by {@link #getHeader()} equals this value.
*/
int getHeaderSize();
/**
* Appends further cleartext to this encryptor. This method might block until space becomes available.
*

View File

@@ -60,6 +60,11 @@ class FileContentEncryptorImpl implements FileContentEncryptor {
return header.toByteBuffer(headerKey, hmacSha256);
}
@Override
public int getHeaderSize() {
return FileHeader.HEADER_SIZE;
}
@Override
public void append(ByteBuffer cleartext) throws InterruptedException {
cleartextBytesEncrypted.add(cleartext.remaining());

View File

@@ -18,7 +18,6 @@ import java.util.concurrent.Future;
import org.cryptomator.crypto.engine.FileContentCryptor;
import org.cryptomator.crypto.engine.FileContentDecryptor;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.io.ByteBuffers;
class CryptoReadableFile implements ReadableFile {
@@ -90,16 +89,6 @@ class CryptoReadableFile implements ReadableFile {
return ByteBuffers.copy(bufferedCleartext, target);
}
@Override
public void copyTo(WritableFile other) {
if (other instanceof CryptoWritableFile) {
CryptoWritableFile dst = (CryptoWritableFile) other;
file.copyTo(dst.file);
} else {
throw new IllegalArgumentException("Can not move CryptoFile to conventional File.");
}
}
@Override
public boolean isOpen() {
return file.isOpen();

View File

@@ -28,14 +28,21 @@ class CryptoWritableFile implements WritableFile {
final WritableFile file;
private final ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
private final FileContentEncryptor encryptor;
private final Future<Void> writeTask;
private final FileContentCryptor cryptor;
private FileContentEncryptor encryptor;
private Future<Void> writeTask;
public CryptoWritableFile(FileContentCryptor cryptor, WritableFile file) {
this.file = file;
this.encryptor = cryptor.createFileContentEncryptor(Optional.empty(), 0);
this.cryptor = cryptor;
initialize(0);
}
private void initialize(long firstCleartextByte) {
encryptor = cryptor.createFileContentEncryptor(Optional.empty(), firstCleartextByte);
writeHeader();
this.writeTask = executorService.submit(new CiphertextWriter(file, encryptor));
writeTask = executorService.submit(new CiphertextWriter(file, encryptor));
}
private void writeHeader() {
@@ -87,11 +94,9 @@ class CryptoWritableFile implements WritableFile {
@Override
public void truncate() {
/*
* TODO kill writer thread (EOF) and reinitialize CryptoWritableFile
* after truncating the file
*/
throw new UnsupportedOperationException("Truncate not supported yet");
terminateAndWaitForWriteTask();
file.truncate();
initialize(0);
}
@Override
@@ -108,11 +113,20 @@ class CryptoWritableFile implements WritableFile {
public void close() {
try {
if (file.isOpen()) {
encryptor.append(FileContentCryptor.EOF);
writeTask.get();
terminateAndWaitForWriteTask();
writeHeader();
// TODO append padding
}
} finally {
executorService.shutdownNow();
file.close();
}
}
private void terminateAndWaitForWriteTask() {
try {
encryptor.append(FileContentCryptor.EOF);
writeTask.get();
} catch (ExecutionException e) {
if (e.getCause() instanceof UncheckedIOException || e.getCause() instanceof IOException) {
throw new UncheckedIOException(new IOException(e));
@@ -121,9 +135,6 @@ class CryptoWritableFile implements WritableFile {
}
} catch (InterruptedException e) {
throw new UncheckedIOException(new InterruptedIOException("Task interrupted while flushing encrypted content"));
} finally {
executorService.shutdownNow();
file.close();
}
}

View File

@@ -100,6 +100,11 @@ class NoFileContentCryptor implements FileContentCryptor {
return buf;
}
@Override
public int getHeaderSize() {
return Long.BYTES;
}
@Override
public void append(ByteBuffer cleartext) {
try {

View File

@@ -14,7 +14,6 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.function.Supplier;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.cryptomator.io.ByteBuffers;
class InMemoryReadableFile implements ReadableFile {
@@ -34,14 +33,6 @@ class InMemoryReadableFile implements ReadableFile {
return open;
}
@Override
public void copyTo(WritableFile other) throws UncheckedIOException {
ByteBuffer source = contentGetter.get().asReadOnlyBuffer();
source.position(0);
other.truncate();
this.position += other.write(source);
}
@Override
public int read(ByteBuffer destination) throws UncheckedIOException {
ByteBuffer source = contentGetter.get().asReadOnlyBuffer();

View File

@@ -110,11 +110,7 @@ public class InMemoryFileSystemTest {
// copy foo to bar
File barFile = fs.file("bar.txt");
try (WritableFile writable = barFile.openWritable()) {
try (ReadableFile readable = fooFile.openReadable()) {
readable.copyTo(writable);
}
}
fooFile.copyTo(barFile);
Assert.assertTrue(fooFile.exists());
Assert.assertTrue(barFile.exists());

View File

@@ -28,8 +28,8 @@ class DefaultInstanceFactory implements InstanceFactory {
}
@Override
public ReadableNioFile readableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
return new ReadableNioFile(fileSystem, path, channel, afterCloseCallback);
public ReadableNioFile readableNioFile(Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
return new ReadableNioFile(path, channel, afterCloseCallback);
}
}

View File

@@ -18,6 +18,6 @@ interface InstanceFactory {
WritableNioFile writableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback, NioAccess nioAccess);
ReadableNioFile readableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback);
ReadableNioFile readableNioFile(Path path, SharedFileChannel channel, Runnable afterCloseCallback);
}

View File

@@ -32,7 +32,7 @@ class NioFile extends NioNode implements File {
throw new IllegalStateException("Current thread is already reading this file");
}
lock.readLock().lock();
return instanceFactory.readableNioFile(fileSystem(), path, sharedChannel, this::unlockReadLock);
return instanceFactory.readableNioFile(path, sharedChannel, this::unlockReadLock);
}
private void unlockReadLock() {

View File

@@ -8,13 +8,10 @@ import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.file.Path;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
class ReadableNioFile implements ReadableFile {
private final FileSystem fileSystem;
private final Path path;
private final SharedFileChannel channel;
private final Runnable afterCloseCallback;
@@ -22,8 +19,7 @@ class ReadableNioFile implements ReadableFile {
private boolean open = true;
private long position = 0;
public ReadableNioFile(FileSystem fileSystem, Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
this.fileSystem = fileSystem;
public ReadableNioFile(Path path, SharedFileChannel channel, Runnable afterCloseCallback) {
this.path = path;
this.channel = channel;
this.afterCloseCallback = afterCloseCallback;
@@ -59,32 +55,6 @@ class ReadableNioFile implements ReadableFile {
this.position = position;
}
@Override
public void copyTo(WritableFile other) throws UncheckedIOException {
assertOpen();
if (belongsToSameFilesystem(other)) {
internalCopyTo((WritableNioFile) other);
} else {
throw new IllegalArgumentException("Can only copy to a WritableFile from the same FileSystem");
}
}
private boolean belongsToSameFilesystem(WritableFile other) {
return other instanceof WritableNioFile && ((WritableNioFile) other).fileSystem() == fileSystem;
}
private void internalCopyTo(WritableNioFile target) {
target.assertOpen();
target.ensureChannelIsOpened();
SharedFileChannel targetChannel = target.channel();
targetChannel.truncate(0);
long size = size();
long transferred = 0;
while (transferred < size) {
transferred += channel.transferTo(transferred, size - transferred, targetChannel, transferred);
}
}
@Override
public void close() {
if (!open) {

View File

@@ -134,37 +134,6 @@ class SharedFileChannel {
}
}
public long transferTo(long position, long count, SharedFileChannel targetChannel, long targetPosition) {
assertOpen();
targetChannel.assertOpen();
if (count < 0) {
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 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);
}
}
private void doLocked(Runnable task) {
lock.lock();
try {

View File

@@ -81,7 +81,7 @@ public class DefaultInstanceFactoryTest {
@Test
public void testReadableNioFileCreatesWritableNioFile() throws IOException {
Runnable afterCloseCallback = mock(Runnable.class);
ReadableNioFile result = inTest.readableNioFile(fileSystem, path, channel, afterCloseCallback);
ReadableNioFile result = inTest.readableNioFile(path, channel, afterCloseCallback);
assertThat(result.toString(), is(format("ReadableNioFile(%s)", path)));

View File

@@ -85,7 +85,7 @@ public class NioFileTest {
@Test
public void testOpenReadableCreatesReadableNioFileFromNioFile() {
ReadableNioFile readableNioFile = mock(ReadableNioFile.class);
when(instanceFactory.readableNioFile(same(fileSystem), same(path), same(channel), any())).thenReturn(readableNioFile);
when(instanceFactory.readableNioFile(same(path), same(channel), any())).thenReturn(readableNioFile);
ReadableFile readableFile = inTest.openReadable();
@@ -106,7 +106,7 @@ public class NioFileTest {
public void testOpenReadableInvokedAfterAfterCloseOperationCreatesNewReadableFile() {
ReadableNioFile readableNioFile = mock(ReadableNioFile.class);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.readableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null, readableNioFile);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(null, readableNioFile);
inTest.openReadable();
captor.getValue().run();
@@ -181,7 +181,7 @@ public class NioFileTest {
@Test
public void testOpenWritableInvokedAfterInvokingAfterCloseOperationWorks() {
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.readableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(null);
inTest.openReadable();
captor.getValue().run();

View File

@@ -5,7 +5,6 @@ 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;
@@ -16,7 +15,6 @@ import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import org.cryptomator.filesystem.FileSystem;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -33,8 +31,6 @@ public class ReadableNioFileTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private FileSystem fileSystem;
private Path path;
private SharedFileChannel channel;
@@ -45,12 +41,11 @@ public class ReadableNioFileTest {
@Before
public void setup() {
fileSystem = mock(FileSystem.class);
path = mock(Path.class);
channel = mock(SharedFileChannel.class);
afterCloseCallback = mock(Runnable.class);
inTest = new ReadableNioFile(fileSystem, path, channel, afterCloseCallback);
inTest = new ReadableNioFile(path, channel, afterCloseCallback);
}
@Test
@@ -162,79 +157,6 @@ public class ReadableNioFileTest {
verifyZeroInteractions(buffer);
}
public class CopyTo {
private WritableNioFile target;
private SharedFileChannel channelOfTarget;
@Before
public void setup() {
target = mock(WritableNioFile.class);
channelOfTarget = mock(SharedFileChannel.class);
when(target.fileSystem()).thenReturn(fileSystem);
when(target.channel()).thenReturn(channelOfTarget);
}
@Test
public void testCopyToFailsIfTargetBelongsToOtherFileSystem() {
WritableNioFile targetFromOtherFileSystem = mock(WritableNioFile.class);
when(targetFromOtherFileSystem.fileSystem()).thenReturn(mock(FileSystem.class));
thrown.expect(IllegalArgumentException.class);
inTest.copyTo(targetFromOtherFileSystem);
}
@Test
public void testCopyToFailsIfSourceIsClosed() {
when(target.fileSystem()).thenReturn(fileSystem);
inTest.close();
thrown.expect(UncheckedIOException.class);
thrown.expectMessage("already closed");
inTest.copyTo(target);
}
@Test
public void testCopyToAssertsThatTargetIsOpenEnsuresTargetChannelIsOpenTuncatesItAndTransfersDataFromSourceChannel() {
long sizeOfSourceChannel = 3283;
when(channel.size()).thenReturn(sizeOfSourceChannel);
when(channel.transferTo(0, sizeOfSourceChannel, channelOfTarget, 0)).thenReturn(sizeOfSourceChannel);
inTest.copyTo(target);
InOrder inOrder = inOrder(target, channel, channelOfTarget);
inOrder.verify(target).assertOpen();
inOrder.verify(target).ensureChannelIsOpened();
inOrder.verify(channelOfTarget).truncate(0);
inOrder.verify(channel).transferTo(0, sizeOfSourceChannel, channelOfTarget, 0);
}
@Test
public void testCopyToInvokesTransferToUntilAllBytesHaveBeenTransferred() {
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, channelOfTarget, 0)).thenReturn(firstTransferAmount);
when(channel.transferTo(firstTransferAmount, sizeRemainingAfterFirstTransfer, channelOfTarget, firstTransferAmount)).thenReturn(secondTransferAmount);
when(channel.transferTo(firstTransferAmount + secondTransferAmount, sizeRemainingAfterSecondTransfer, channelOfTarget, firstTransferAmount + secondTransferAmount)).thenReturn(thirdTransferAmount);
inTest.copyTo(target);
InOrder inOrder = inOrder(channel);
inOrder.verify(channel).transferTo(0, size, channelOfTarget, 0);
inOrder.verify(channel).transferTo(firstTransferAmount, sizeRemainingAfterFirstTransfer, channelOfTarget, firstTransferAmount);
inOrder.verify(channel).transferTo(firstTransferAmount + secondTransferAmount, sizeRemainingAfterSecondTransfer, channelOfTarget, firstTransferAmount + secondTransferAmount);
}
}
@Test
public void testIsOpenReturnsTrueForNewReadableNioFile() {
assertThat(inTest.isOpen(), is(true));

View File

@@ -653,28 +653,6 @@ public class SharedFileChannelTest {
inTest.size();
}
@Test
public void testTransferToFailsIfSourceNotOpen() {
SharedFileChannel irrelevant = null;
thrown.expect(IllegalStateException.class);
thrown.expectMessage("SharedFileChannel is not open");
inTest.transferTo(0, 0, irrelevant, 0);
}
@Test
public void testTransferToFailsIfTargetNotOpen() {
Path targetPath = mock(Path.class);
SharedFileChannel targetInTest = new SharedFileChannel(targetPath, nioAccess);
inTest.open(OpenMode.WRITE);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("SharedFileChannel is not open");
inTest.transferTo(0, 0, targetInTest, 0);
}
@Test
public void testWriteFullyFailsIfNotOpen() {
ByteBuffer irrelevant = null;