aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/java/com
diff options
context:
space:
mode:
authorGravatar tomlu <tomlu@google.com>2017-12-19 11:54:08 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2017-12-19 11:55:35 -0800
commit18291e570fc8823f13d1afd355cf57c0b68f8426 (patch)
treead23c9a379d858ab60321e6f394acdad3172a7f6 /src/test/java/com
parent246ee5601c28e99385a2a722b57c1977d5ef1aa8 (diff)
Add regression test for JavaIoFileSystem#createDirectory.
PiperOrigin-RevId: 179584358
Diffstat (limited to 'src/test/java/com')
-rw-r--r--src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java74
1 files changed, 68 insertions, 6 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java b/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java
index 80c1981fcd..056b5f0f1a 100644
--- a/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java
+++ b/src/test/java/com/google/devtools/build/lib/vfs/JavaIoFileSystemTest.java
@@ -15,11 +15,24 @@ package com.google.devtools.build.lib.vfs;
import static com.google.common.truth.Truth.assertThat;
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.testutil.TestUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
+import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -66,15 +79,64 @@ public class JavaIoFileSystemTest extends SymlinkAwareFileSystemTest {
@Override
protected boolean isHardLinked(Path a, Path b) throws IOException {
return Files.readAttributes(
- java.nio.file.Paths.get(a.toString()),
- BasicFileAttributes.class,
- LinkOption.NOFOLLOW_LINKS)
+ Paths.get(a.toString()), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)
.fileKey()
.equals(
Files.readAttributes(
- java.nio.file.Paths.get(b.toString()),
- BasicFileAttributes.class,
- LinkOption.NOFOLLOW_LINKS)
+ Paths.get(b.toString()), BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)
.fileKey());
}
+
+ /**
+ * This test has a large number of threads racing to create the same subdirectories.
+ *
+ * <p>We create N number of distinct directory trees, eg. the tree "0-0/0-1/0-2/0-3/0-4" followed
+ * by the tree "1-0/1-1/1-2/1-3/1-4" etc. If there is race we should quickly get a deadlock.
+ *
+ * <p>A timeout of this test is likely because of a deadlock.
+ */
+ @Test
+ public void testCreateDirectoriesThreadSafety() throws Exception {
+ int threadCount = 200;
+ int directoryCreationCount = 500; // We create this many sets of directories
+ int subDirectoryCount = 5; // Each directory tree is this deep
+ ListeningExecutorService executor =
+ MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(threadCount));
+ List<ListenableFuture<IOException>> futures = new ArrayList<>();
+ for (int threadIndex = 0; threadIndex < threadCount; ++threadIndex) {
+ futures.add(
+ executor.submit(
+ () -> {
+ try {
+ for (int loopi = 0; loopi < directoryCreationCount; ++loopi) {
+ List<Path> subDirs =
+ getSubDirectories(xEmptyDirectory, loopi, subDirectoryCount);
+ Path lastDir = Iterables.getLast(subDirs);
+ FileSystemUtils.createDirectoryAndParents(lastDir);
+ }
+ } catch (IOException e) {
+ return e;
+ }
+ return null;
+ }));
+ }
+ ListenableFuture<List<IOException>> all = Futures.allAsList(futures);
+ // If the test times out here then there's likely to be a deadlock
+ List<IOException> exceptions =
+ all.get(TestUtils.WAIT_TIMEOUT_MILLISECONDS, TimeUnit.MILLISECONDS);
+ Optional<IOException> error = exceptions.stream().filter(Objects::nonNull).findFirst();
+ if (error.isPresent()) {
+ throw error.get();
+ }
+ }
+
+ private static List<Path> getSubDirectories(Path base, int loopi, int subDirectoryCount) {
+ Path path = base;
+ List<Path> subDirs = new ArrayList<>();
+ for (int subDirIndex = 0; subDirIndex < subDirectoryCount; ++subDirIndex) {
+ path = path.getChild(String.format("%d-%d", loopi, subDirIndex));
+ subDirs.add(path);
+ }
+ return subDirs;
+ }
}