mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-08-31 21:31:40 +00:00
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:
@@ -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
|
||||
|
||||
-11
@@ -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";
|
||||
|
||||
-24
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user