Skip to content

Commit

Permalink
Tests for filesystem-nio
Browse files Browse the repository at this point in the history
* Renamed tests from ...IntegrationTest back to ...Test
** to allow better integration with moreunit
** because some methods of the classes can only be integration tested
some not which lead to a strange splitting of the tests
* Added more tests
  • Loading branch information
markuskreusch committed Jan 2, 2016
1 parent e9f5593 commit ff4448b
Show file tree
Hide file tree
Showing 10 changed files with 816 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private void internalCopyTo(WritableNioFile target) {
long size = nioFile.channel().size();
long transferred = 0;
while (transferred < size) {
transferred += nioFile.channel().transferTo(transferred, size - transferred, targetChannel);
transferred += nioFile.channel().transferTo(transferred, size - transferred, targetChannel, transferred);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,26 @@ public void close() {
assertOpenedByCurrentThread();
doLocked(() -> {
openedBy.remove(Thread.currentThread());
if (openedBy.isEmpty()) {
closeChannel();
try {
delegate.force(true);
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
if (openedBy.isEmpty()) {
closeChannel();
}
}
});
}

/**
* @deprecated only intended to be used in tests
*/
@Deprecated
void forceClose() {
closeSilently(delegate);
}

private void assertOpenedByCurrentThread() {
if (!openedBy.containsKey(Thread.currentThread())) {
throw new IllegalStateException("SharedFileChannel closed for current thread");
Expand All @@ -61,14 +75,22 @@ private void createChannel(OpenMode mode) {
readChannel = FileChannel.open(path, StandardOpenOption.READ);
}
delegate = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
if (readChannel != null) {
readChannel.close();
}
closeSilently(readChannel);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

private void closeSilently(FileChannel channel) {
if (channel != null) {
try {
channel.close();
} catch (IOException e) {
// ignore
}
}
}

private void closeChannel() {
try {
delegate.close();
Expand Down Expand Up @@ -121,13 +143,14 @@ public long size() {
}
}

public long transferTo(long position, long count, SharedFileChannel targetChannel) {
public long transferTo(long position, long count, SharedFileChannel targetChannel, long targetPosition) {
assertOpenedByCurrentThread();
targetChannel.assertOpenedByCurrentThread();
try {
long maxPosition = delegate.size();
long maxCount = Math.min(count, maxPosition - position);
long remaining = maxCount;
targetChannel.delegate.position(targetPosition);
while (remaining > 0) {
remaining -= delegate.transferTo(maxPosition - remaining, remaining, targetChannel.delegate);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class NioFileSystemIntegrationTest {
public class NioFileSystemTest {

@Rule
public ExpectedException thrown = ExpectedException.none();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import static org.cryptomator.filesystem.nio.FilesystemSetupUtils.testFilesystem;
import static org.cryptomator.filesystem.nio.PathMatcher.doesNotExist;
import static org.cryptomator.filesystem.nio.PathMatcher.isFile;
import static org.cryptomator.filesystem.nio.ThreadStackMatcher.stackContains;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.sameInstance;
Expand All @@ -16,19 +18,25 @@
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.time.Instant;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Supplier;

import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.FileSystem;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.Timeout;
import org.junit.runner.RunWith;

import de.bechte.junit.runners.context.HierarchicalContextRunner;

@RunWith(HierarchicalContextRunner.class)
public class NioFileIntegrationTest {
public class NioFileTest {

@Rule
public ExpectedException thrown = ExpectedException.none();
Expand Down Expand Up @@ -339,6 +347,250 @@ public void testMoveToOfFileWhichIsAFolderThrowsUncheckedIOExceptionWithPathInMe
fileWhichIsAFolder.moveTo(target);
}

public class OpenReadable {

@Test
public void testOpenReadableReturnsAReadableNioFileForAnExistingFile() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");

ReadableFile result = file.openReadable();

assertThat(result, is(instanceOf(ReadableNioFile.class)));
}

@Test
public void testOpenReadableThrowsAnUncheckedIOExceptionIfTheFileDoesNotExists() {
Path filesystemPath = emptyFilesystem();
Path nonExistingFilePath = filesystemPath.resolve("nonExistingFile");
File nonExistingFile = NioFileSystem.rootedAt(filesystemPath).file("nonExistingFile");

thrown.expect(UncheckedIOException.class);
thrown.expectMessage(nonExistingFilePath.toString());

nonExistingFile.openReadable();
}

@Test
public void testOpenReadableThrowsIllegalStateExceptionIfInvokedTwiceFromWithingTheSameThread() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openReadable();

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Current thread is already reading this file");

file.openReadable();
}

@Test
public void testOpenReadableDoesNotThrowIllegalStateExceptionIfInvokedTwiceFromWithingTheSameThreadButTheFirstReadableFileHasBeenClosed() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openReadable().close();

ReadableFile result = file.openReadable();

assertThat(result, is(instanceOf(ReadableNioFile.class)));
}

@Test
public void testOpenReadableThrowsIllegalStateExceptionIfInvokedAfterOpenWritable() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable();

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Current thread is currently writing this file");

file.openReadable();
}

@Test
public void testOpenReadableDoesNotThrowIllegalStateExceptionIfInvokedAfterOpenWritableButTheWritableFileHasBeenClosed() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable().close();

ReadableFile result = file.openReadable();

assertThat(result, is(instanceOf(ReadableNioFile.class)));
}

}

public class OpenWritable {

@Test
public void testOpenWritableReturnsAWritableNioFileForAnExistingFile() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");

WritableFile result = file.openWritable();

assertThat(result, is(instanceOf(WritableNioFile.class)));
}

@Test
public void testOpenWritableReturnsAWritableNioFileForANonExisitingFile() {
File file = NioFileSystem.rootedAt(emptyFilesystem()).file("nonExistingFile");

WritableFile result = file.openWritable();

assertThat(result, is(instanceOf(WritableNioFile.class)));
}

@Test
public void testOpenWritableDoesNotCreateANonExisitingFile() {
Path filesystemPath = emptyFilesystem();
Path filePath = filesystemPath.resolve("nonExistingFile");
File file = NioFileSystem.rootedAt(filesystemPath).file("nonExistingFile");

file.openWritable();

assertThat(filePath, doesNotExist());
}

@Test
public void testOpenWritableThrowsIllegalStateExceptionIfInvokedTwiceFromWithingTheSameThread() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable();

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Current thread is already writing this file");

file.openWritable();
}

@Test
public void testOpenWritableDoesNotThrowIllegalStateExceptionIfInvokedTwiceFromWithingTheSameThreadButTheFirstWritableFileHasBeenClosed() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable().close();

WritableFile result = file.openWritable();

assertThat(result, is(instanceOf(WritableNioFile.class)));
}

@Test
public void testOpenWritableThrowsIllegalStateExceptionIfInvokedAfterOpenReadable() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openReadable();

thrown.expect(IllegalStateException.class);
thrown.expectMessage("Current thread is currently reading this file");

file.openWritable();
}

@Test
public void testOpenWritableDoesNotThrowIllegalStateExceptionIfInvokedAfterOpenReadableButTheReadableFileHasBeenClosed() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openReadable().close();

WritableFile result = file.openWritable();

assertThat(result, is(instanceOf(WritableNioFile.class)));
}

}

public class OpenWithMultipleThreads {

@Rule
public Timeout timeout = Timeout.seconds(5);

@Test
public void testOpenReadableInvokedInTwoThreadsCompletes() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");

ReadableFile readableFileFromThread1 = computeInThread(file::openReadable);
ReadableFile readableFileFromThread2 = computeInThread(file::openReadable);

assertThat(readableFileFromThread1, is(instanceOf(ReadableNioFile.class)));
assertThat(readableFileFromThread2, is(instanceOf(ReadableNioFile.class)));
assertThat(readableFileFromThread1, is(not(sameInstance(readableFileFromThread2))));
}

@Test
public void testOpenReadableInvokedWhileWritableFileIsOpenBlocks() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable();

Thread thread = inThread(file::openReadable);

assertThat(thread, is(stackContains(NioFile.class, "openReadable")));
}

@Test
public void testOpenWritableInvokedWhileReadableFileIsOpenBlocks() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openReadable();

Thread thread = inThread(file::openWritable);

assertThat(thread, is(stackContains(NioFile.class, "openWritable")));
}

@Test
public void testOpenWritableInvokedWhileWritableFileIsOpenBlocks() {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
file.openWritable();

Thread thread = inThread(file::openWritable);

assertThat(thread, is(stackContains(NioFile.class, "openWritable")));
}

@Test
public void testOpenReadableInvokedWhileWritableFileIsOpenCompletesAfterClosingIt() throws InterruptedException {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
WritableFile writableFile = file.openWritable();
Thread thread = inThread(file::openReadable);
writableFile.close();

thread.join();
}

@Test
public void testOpenWritableInvokedWhileReadableFileIsOpenCompletesAfterClosingIt() throws InterruptedException {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
ReadableFile readableFile = file.openReadable();
Thread thread = inThread(file::openWritable);
readableFile.close();

thread.join();
}

@Test
public void testOpenWritableInvokedWhileWritableFileIsOpenCompletesAfterClosingIt() throws InterruptedException {
File file = NioFileSystem.rootedAt(testFilesystem(file("fileName"))).file("fileName");
WritableFile writableFile = file.openWritable();
Thread thread = inThread(file::openWritable);
writableFile.close();

thread.join();
}

private Thread inThread(Runnable task) {
Thread thread = new Thread(task);
thread.start();
try {
// give thread time to execute work
Thread.sleep(100);
} catch (InterruptedException e) {
}
return thread;
}

private <T> T computeInThread(Supplier<T> computation) {
CompletableFuture<T> future = new CompletableFuture<>();
inThread(() -> {
future.complete(computation.get());
});
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}

}

private int signum(int value) {
if (value > 0) {
return 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class NioFolderIntegrationTest {
public class NioFolderTest {

@Rule
public ExpectedException thrown = ExpectedException.none();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ public Matcher<Path> withContent(byte[] value) {
return new IsFileWithContentMatcher(value);
}

public Matcher<Path> thatIsEmpty() {
return withContent(new byte[0]);
}

}

public static class IsFileWithContentMatcher extends TypeSafeDiagnosingMatcher<Path> {
Expand Down
Loading

0 comments on commit ff4448b

Please sign in to comment.