Sfoglia il codice sorgente

Integrated BlacklistingFileSystem into ShorteningFileSystem

Markus Kreusch 9 anni fa
parent
commit
e57ee67208

+ 2 - 2
main/filesystem-invariants-tests/src/test/java/org/cryptomator/filesystem/invariants/FileSystemFactories.java

@@ -60,12 +60,12 @@ class FileSystemFactories implements Iterable<FileSystemFactory> {
 
 	private FileSystem createShorteningFileSystemNio() {
 		FileSystem delegate = createNioFileSystem();
-		return new ShorteningFileSystem(delegate.folder("d"), delegate.folder("m"), 3);
+		return new ShorteningFileSystem(delegate, "m", 3);
 	}
 
 	private FileSystem createShorteningFileSystemInMemory() {
 		FileSystem delegate = createInMemoryFileSystem();
-		return new ShorteningFileSystem(delegate.folder("d"), delegate.folder("m"), 3);
+		return new ShorteningFileSystem(delegate, "m", 3);
 	}
 
 	private void add(String name, FileSystemFactory factory) {

+ 0 - 20
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/blacklisting/BlacklistingFile.java

@@ -1,20 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import org.cryptomator.filesystem.File;
-import org.cryptomator.filesystem.delegating.DelegatingFile;
-
-class BlacklistingFile extends DelegatingFile<BlacklistingFolder> {
-
-	public BlacklistingFile(BlacklistingFolder parent, File delegate) {
-		super(parent, delegate);
-	}
-
-}

+ 0 - 28
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/blacklisting/BlacklistingFileSystem.java

@@ -1,28 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import java.util.function.Predicate;
-
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.Node;
-import org.cryptomator.filesystem.delegating.DelegatingFileSystem;
-
-class BlacklistingFileSystem extends BlacklistingFolder implements DelegatingFileSystem {
-
-	public BlacklistingFileSystem(Folder root, Predicate<Node> hiddenNodes) {
-		super(null, root, hiddenNodes);
-	}
-
-	@Override
-	public Folder getDelegate() {
-		return delegate;
-	}
-
-}

+ 0 - 30
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/blacklisting/BlacklistingFileSystemFactory.java

@@ -1,30 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import java.util.function.Predicate;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.cryptomator.filesystem.FileSystem;
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.Node;
-
-@Singleton
-public class BlacklistingFileSystemFactory {
-
-	@Inject
-	public BlacklistingFileSystemFactory() {
-	}
-
-	public FileSystem get(Folder root, Predicate<Node> hiddenFiles) {
-		return new BlacklistingFileSystem(root, hiddenFiles);
-	}
-}

+ 0 - 61
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/blacklisting/BlacklistingFolder.java

@@ -1,61 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import java.io.UncheckedIOException;
-import java.nio.file.FileAlreadyExistsException;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import org.cryptomator.filesystem.File;
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.Node;
-import org.cryptomator.filesystem.delegating.DelegatingFolder;
-
-class BlacklistingFolder extends DelegatingFolder<BlacklistingFolder, BlacklistingFile> {
-
-	private final Predicate<Node> hiddenNodes;
-
-	public BlacklistingFolder(BlacklistingFolder parent, Folder delegate, Predicate<Node> hiddenNodes) {
-		super(parent, delegate);
-		this.hiddenNodes = hiddenNodes;
-	}
-
-	@Override
-	public Stream<? extends Node> children() {
-		return Stream.concat(folders(), files());
-	}
-
-	@Override
-	public Stream<BlacklistingFolder> folders() {
-		return delegate.folders().filter(hiddenNodes.negate()).map(this::newFolder);
-	}
-
-	@Override
-	public Stream<BlacklistingFile> files() {
-		return delegate.files().filter(hiddenNodes.negate()).map(this::newFile);
-	}
-
-	@Override
-	protected BlacklistingFile newFile(File delegate) {
-		if (hiddenNodes.test(delegate)) {
-			throw new UncheckedIOException("'" + delegate.name() + "' is a reserved name.", new FileAlreadyExistsException(delegate.name()));
-		}
-		return new BlacklistingFile(this, delegate);
-	}
-
-	@Override
-	protected BlacklistingFolder newFolder(Folder delegate) {
-		if (hiddenNodes.test(delegate)) {
-			throw new UncheckedIOException("'" + delegate.name() + "' is a reserved name.", new FileAlreadyExistsException(delegate.name()));
-		}
-		return new BlacklistingFolder(this, delegate, hiddenNodes);
-	}
-
-}

+ 0 - 34
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/blacklisting/SamePathPredicate.java

@@ -1,34 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import java.util.Objects;
-import java.util.function.Predicate;
-
-import org.cryptomator.filesystem.Node;
-
-public class SamePathPredicate implements Predicate<Node> {
-
-	private final Node node;
-
-	private SamePathPredicate(Node node) {
-		Objects.requireNonNull(node);
-		this.node = node;
-	}
-
-	@Override
-	public boolean test(Node other) {
-		return node.parent().equals(other.parent()) && node.name().equals(other.name());
-	}
-
-	public static SamePathPredicate forNode(Node node) {
-		return new SamePathPredicate(node);
-	}
-
-}

+ 35 - 2
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystem.java

@@ -8,16 +8,49 @@
  *******************************************************************************/
 package org.cryptomator.filesystem.shortening;
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.stream.Stream;
+
 import org.cryptomator.filesystem.Folder;
+import org.cryptomator.filesystem.Node;
 import org.cryptomator.filesystem.delegating.DelegatingFileSystem;
 
 public class ShorteningFileSystem extends ShorteningFolder implements DelegatingFileSystem {
 
-	public ShorteningFileSystem(Folder root, Folder metadataRoot, int threshold) {
-		super(null, root, "", new FilenameShortener(metadataRoot, threshold));
+	private final String metadataFolderName;
+
+	public ShorteningFileSystem(Folder root, String metadataFolderName, int threshold) {
+		super(null, root, "", new FilenameShortener(root.resolveFolder(metadataFolderName), threshold));
+		this.metadataFolderName = metadataFolderName;
 		create();
 	}
 
+	@Override
+	public Stream<ShorteningFolder> folders() {
+		return super.folders().filter(this::nameIsNotNameOfMetadataFolder);
+	}
+
+	@Override
+	public ShorteningFile file(String name) throws UncheckedIOException {
+		if (metadataFolderName.equals(name)) {
+			throw new UncheckedIOException(new IOException("'" + name + "' is a reserved name."));
+		}
+		return super.file(name);
+	}
+
+	@Override
+	public ShorteningFolder folder(String name) throws UncheckedIOException {
+		if (metadataFolderName.equals(name)) {
+			throw new UncheckedIOException(new IOException("'" + name + "' is a reserved name."));
+		}
+		return super.folder(name);
+	}
+
+	private boolean nameIsNotNameOfMetadataFolder(Node node) {
+		return !metadataFolderName.equals(node.name());
+	}
+
 	@Override
 	public Folder getDelegate() {
 		return delegate;

+ 2 - 9
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemFactory.java

@@ -13,8 +13,6 @@ import javax.inject.Singleton;
 
 import org.cryptomator.filesystem.FileSystem;
 import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.blacklisting.BlacklistingFileSystemFactory;
-import org.cryptomator.filesystem.blacklisting.SamePathPredicate;
 
 @Singleton
 public class ShorteningFileSystemFactory {
@@ -22,16 +20,11 @@ public class ShorteningFileSystemFactory {
 	private static final int SHORTENING_THRESHOLD = 129; // 128 + "_"
 	private static final String METADATA_FOLDER_NAME = "m";
 
-	private final BlacklistingFileSystemFactory blacklistingFileSystemFactory;
-
 	@Inject
-	public ShorteningFileSystemFactory(BlacklistingFileSystemFactory blacklistingFileSystemFactory) {
-		this.blacklistingFileSystemFactory = blacklistingFileSystemFactory;
+	public ShorteningFileSystemFactory() {
 	}
 
 	public FileSystem get(Folder root) {
-		final Folder metadataFolder = root.folder(METADATA_FOLDER_NAME);
-		final FileSystem metadataHidingFs = blacklistingFileSystemFactory.get(root, SamePathPredicate.forNode(metadataFolder));
-		return new ShorteningFileSystem(metadataHidingFs, metadataFolder, SHORTENING_THRESHOLD);
+		return new ShorteningFileSystem(root, METADATA_FOLDER_NAME, SHORTENING_THRESHOLD);
 	}
 }

+ 0 - 67
main/filesystem-nameshortening/src/test/java/org/cryptomator/filesystem/blacklisting/BlacklistingFileSystemTest.java

@@ -1,67 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.WritableByteChannel;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-
-import org.cryptomator.filesystem.File;
-import org.cryptomator.filesystem.FileSystem;
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.Node;
-import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class BlacklistingFileSystemTest {
-
-	@Test(expected = UncheckedIOException.class)
-	public void testPreventCreationOfBlacklistedFolder() {
-		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Node blacklisted = underlyingFs.folder("qwe");
-		final FileSystem fs = new BlacklistingFileSystem(underlyingFs, SamePathPredicate.forNode(blacklisted));
-		fs.folder("qwe");
-	}
-
-	@Test(expected = UncheckedIOException.class)
-	public void testPreventCreationOBlacklistedFile() {
-		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Node blacklisted = underlyingFs.folder("qwe");
-		final FileSystem fs = new BlacklistingFileSystem(underlyingFs, SamePathPredicate.forNode(blacklisted));
-		fs.file("qwe");
-	}
-
-	@Test
-	public void testBlacklistingOfFilesAndFolders() throws IOException {
-		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder hiddenFolder = underlyingFs.folder("asd");
-		final File hiddenFile = underlyingFs.file("qwe");
-		final Folder visibleFolder = underlyingFs.folder("sdf");
-		final File visibleFile = underlyingFs.file("wer");
-		final Predicate<Node> hiddenPredicate = SamePathPredicate.forNode(hiddenFolder).or(SamePathPredicate.forNode(hiddenFile));
-		final FileSystem fs = new BlacklistingFileSystem(underlyingFs, hiddenPredicate);
-		hiddenFolder.create();
-		try (WritableByteChannel writable = hiddenFile.openWritable()) {
-			writable.write(ByteBuffer.allocate(0));
-		}
-		visibleFolder.create();
-		try (WritableByteChannel writable = visibleFile.openWritable()) {
-			writable.write(ByteBuffer.allocate(0));
-		}
-
-		Assert.assertArrayEquals(new String[] {"sdf"}, fs.folders().map(Node::name).collect(Collectors.toList()).toArray());
-		Assert.assertArrayEquals(new String[] {"wer"}, fs.files().map(Node::name).collect(Collectors.toList()).toArray());
-		Assert.assertArrayEquals(new String[] {"sdf", "wer"}, fs.children().map(Node::name).sorted().collect(Collectors.toList()).toArray());
-	}
-
-}

+ 0 - 44
main/filesystem-nameshortening/src/test/java/org/cryptomator/filesystem/blacklisting/SamePathPredicateTest.java

@@ -1,44 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2016 Sebastian Stenzel and others.
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- *
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- *******************************************************************************/
-package org.cryptomator.filesystem.blacklisting;
-
-import org.cryptomator.filesystem.File;
-import org.cryptomator.filesystem.FileSystem;
-import org.cryptomator.filesystem.Folder;
-import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class SamePathPredicateTest {
-
-	@Test
-	public void testFileAndFolderWithSameNameWithSameParentConsideredSame() {
-		FileSystem fs = new InMemoryFileSystem();
-		File file1 = fs.file("foo");
-		Folder folder1 = fs.folder("foo");
-		Assert.assertTrue(SamePathPredicate.forNode(file1).test(folder1));
-	}
-
-	@Test
-	public void testFilesWithDifferentParentConsideredDifferent() {
-		FileSystem fs = new InMemoryFileSystem();
-		File file1 = fs.file("foo");
-		File file2 = fs.folder("bar").file("foo");
-		Assert.assertFalse(SamePathPredicate.forNode(file1).test(file2));
-	}
-
-	@Test
-	public void testFilesWithDifferentNamesConsideredDifferent() {
-		FileSystem fs = new InMemoryFileSystem();
-		File file1 = fs.file("foo");
-		File file2 = fs.file("bar");
-		Assert.assertFalse(SamePathPredicate.forNode(file1).test(file2));
-	}
-
-}

+ 75 - 17
main/filesystem-nameshortening/src/test/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemTest.java

@@ -8,36 +8,93 @@
  *******************************************************************************/
 package org.cryptomator.filesystem.shortening;
 
+import static java.lang.String.format;
+import static java.util.stream.Collectors.toList;
+import static org.cryptomator.common.test.matcher.ContainsMatcher.contains;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 import java.time.Instant;
 import java.util.concurrent.TimeoutException;
 
+import org.cryptomator.common.test.matcher.PropertyMatcher;
 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.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.hamcrest.Matcher;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 public class ShorteningFileSystemTest {
 
+	@Rule
+	public ExpectedException thrown = ExpectedException.none();
+
+	private static final String METADATA_DIR_NAME = "m";
+	private static final int THRESHOLD = 10;
+	private static final String NAME_LONGER_THAN_THRESHOLD = "morethantenchars";
+
 	@Test
 	public void testImplicitCreationOfMetadataFolder() {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
-		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
-		fs.folder("morethantenchars").create();
+		final Folder metadataRoot = underlyingFs.folder(METADATA_DIR_NAME);
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
+		fs.folder(NAME_LONGER_THAN_THRESHOLD).create();
 		Assert.assertTrue(metadataRoot.exists());
 	}
 
+	@Test
+	public void testMetadataFolderIsNotIncludedInFolderListing() {
+		final FileSystem underlyingFs = new InMemoryFileSystem();
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
+		fs.folder(NAME_LONGER_THAN_THRESHOLD).create();
+
+		assertThat(fs.folders().collect(toList()), contains(folderWithName(NAME_LONGER_THAN_THRESHOLD)));
+	}
+
+	@Test
+	public void testMetadataFolderIsNotIncludedInChildrenListing() {
+		final FileSystem underlyingFs = new InMemoryFileSystem();
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
+		fs.folder(NAME_LONGER_THAN_THRESHOLD).create();
+
+		assertThat(fs.children().collect(toList()), contains(folderWithName(NAME_LONGER_THAN_THRESHOLD)));
+	}
+
+	@Test
+	public void testCanNotObtainFolderWithNameOfMetadataFolder() {
+		final FileSystem underlyingFs = new InMemoryFileSystem();
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
+
+		thrown.expect(UncheckedIOException.class);
+		thrown.expectMessage(format("'%s' is a reserved name", METADATA_DIR_NAME));
+
+		fs.folder(METADATA_DIR_NAME);
+	}
+
+	@Test
+	public void testCanNotObtainFileWithNameOfMetadataFolder() {
+		final FileSystem underlyingFs = new InMemoryFileSystem();
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
+
+		thrown.expect(UncheckedIOException.class);
+		thrown.expectMessage(format("'%s' is a reserved name", METADATA_DIR_NAME));
+
+		fs.file(METADATA_DIR_NAME);
+	}
+
 	@Test
 	public void testDeflate() {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
-		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final Folder metadataRoot = underlyingFs.folder(METADATA_DIR_NAME);
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, 10);
 		final Folder longNamedFolder = fs.folder("morethantenchars"); // base32(sha1(morethantenchars)) = QMJL5GQUETRX2YRV6XDTJQ6NNM7IEUHP
 		final File correspondingMetadataFile = metadataRoot.folder("QM").folder("JL").file("QMJL5GQUETRX2YRV6XDTJQ6NNM7IEUHP.lng");
 		longNamedFolder.create();
@@ -48,9 +105,9 @@ public class ShorteningFileSystemTest {
 	@Test
 	public void testMoveLongFolders() {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
+		final Folder metadataRoot = underlyingFs.folder(METADATA_DIR_NAME);
 		metadataRoot.create();
-		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 
 		final Folder shortNamedFolder = fs.folder("test");
 		shortNamedFolder.create();
@@ -64,9 +121,9 @@ public class ShorteningFileSystemTest {
 	@Test
 	public void testMoveLongFiles() throws UncheckedIOException, TimeoutException {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
+		final Folder metadataRoot = underlyingFs.folder(METADATA_DIR_NAME);
 		metadataRoot.create();
-		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 
 		final File shortNamedFolder = fs.file("test");
 		try (WritableFile file = shortNamedFolder.openWritable()) {
@@ -82,12 +139,11 @@ public class ShorteningFileSystemTest {
 	@Test
 	public void testDeflateAndInflateFolder() {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
-		final FileSystem fs1 = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs1 = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 		final Folder longNamedFolder1 = fs1.folder("morethantenchars");
 		longNamedFolder1.create();
 
-		final FileSystem fs2 = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs2 = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 		final Folder longNamedFolder2 = fs2.folder("morethantenchars");
 		Assert.assertTrue(longNamedFolder2.exists());
 	}
@@ -95,17 +151,16 @@ public class ShorteningFileSystemTest {
 	@Test
 	public void testDeflateAndInflateFolderAndFile() throws UncheckedIOException, TimeoutException {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
 
 		// write:
-		final FileSystem fs1 = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs1 = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 		fs1.folder("morethantenchars").create();
 		try (WritableFile file = fs1.folder("morethantenchars").file("morethanelevenchars.txt").openWritable()) {
 			file.write(ByteBuffer.wrap("hello world".getBytes()));
 		}
 
 		// read
-		final FileSystem fs2 = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs2 = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 		try (ReadableFile file = fs2.folder("morethantenchars").file("morethanelevenchars.txt").openReadable()) {
 			ByteBuffer buf = ByteBuffer.allocate(11);
 			file.read(buf);
@@ -116,8 +171,7 @@ public class ShorteningFileSystemTest {
 	@Test
 	public void testPassthroughShortNamedFiles() throws UncheckedIOException, TimeoutException, InterruptedException {
 		final FileSystem underlyingFs = new InMemoryFileSystem();
-		final Folder metadataRoot = underlyingFs.folder("m");
-		final FileSystem fs = new ShorteningFileSystem(underlyingFs, metadataRoot, 10);
+		final FileSystem fs = new ShorteningFileSystem(underlyingFs, METADATA_DIR_NAME, THRESHOLD);
 
 		final Instant testStart = Instant.now();
 
@@ -151,4 +205,8 @@ public class ShorteningFileSystemTest {
 		Assert.assertTrue(fs.folder("foo").file("test2.txt").lastModified().isAfter(testStart));
 	}
 
+	public static Matcher<Folder> folderWithName(String name) {
+		return new PropertyMatcher<>(Folder.class, Folder::name, "name", is(name));
+	}
+
 }