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