Rollback of commit 2dddbeeac25ace6f53dd3ce6ac588111c239bdf0.

--
MOS_MIGRATED_REVID=131181548
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/junit4/JUnit4Runner.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/junit4/JUnit4Runner.java
index d9938c7..10447a7 100644
--- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/junit4/JUnit4Runner.java
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/junit4/JUnit4Runner.java
@@ -14,7 +14,9 @@
 
 package com.google.testing.junit.runner.junit4;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Supplier;
+import com.google.common.io.Files;
 import com.google.testing.junit.junit4.runner.SuiteTrimmingFilter;
 import com.google.testing.junit.runner.internal.Stdout;
 import com.google.testing.junit.runner.model.TestSuiteModel;
@@ -32,7 +34,6 @@
 import org.junit.runner.notification.RunNotifier;
 
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.util.Set;
@@ -129,10 +130,7 @@
   private static void exitFileActive(@Nullable File file) {
     if (file != null) {
       try {
-        // Overwrite file content.
-        FileOutputStream outputStream = new FileOutputStream(file, false);
-        outputStream.write(new byte[0]);
-        outputStream.close();
+        Files.write(new byte[0], file);
       } catch (IOException e) {
         throw new RuntimeException("Could not write exit file at " + file, e);
       }
@@ -150,7 +148,7 @@
     }
   }
 
-  // VisibleForTesting
+  @VisibleForTesting
   TestSuiteModel getModel() {
     return modelSupplier.get();
   }
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java
index 50cb8b7..74ab90b 100644
--- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestCaseNode.java
@@ -16,11 +16,15 @@
 
 import static com.google.testing.junit.runner.util.TestPropertyExporter.INITIAL_INDEX_FOR_REPEATED_PROPERTY;
 
+import com.google.common.collect.ConcurrentHashMultiset;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.Multiset;
 import com.google.testing.junit.runner.model.TestResult.Status;
 import com.google.testing.junit.runner.util.TestPropertyExporter;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Queue;
@@ -35,10 +39,10 @@
 class TestCaseNode extends TestNode implements TestPropertyExporter.Callback {
   private final TestSuiteNode parent;
   private final Map<String, String> properties = new ConcurrentHashMap<>();
-  private final Map<String, Integer> repeatedPropertyNamesToRepetitions = new HashMap<>();
+  private final Multiset<String> repeatedPropertyNames = ConcurrentHashMultiset.create();
   private final Queue<Throwable> globalFailures = new ConcurrentLinkedQueue<>();
-  private final ConcurrentHashMap<Description, List<Throwable>> dynamicTestToFailures =
-      new ConcurrentHashMap<>();
+  private final ListMultimap<Description, Throwable> dynamicTestToFailures =
+      Multimaps.synchronizedListMultimap(LinkedListMultimap.<Description, Throwable>create());
 
   @Nullable private volatile TestInterval runTimeInterval = null;
   private volatile State state = State.INITIAL;
@@ -113,12 +117,11 @@
   @Override
   public void dynamicTestFailure(Description test, Throwable throwable, long now) {
     compareAndSetState(State.INITIAL, State.FINISHED, now);
-    addThrowableToDynamicTestToFailures(test, throwable);
+    dynamicTestToFailures.put(test, throwable);
   }
 
   private String getRepeatedPropertyName(String name) {
-    int index = addNameToRepeatedPropertyNamesAndGetRepetitionsNr(name)
-        + INITIAL_INDEX_FOR_REPEATED_PROPERTY;
+    int index = repeatedPropertyNames.add(name, 1) + INITIAL_INDEX_FOR_REPEATED_PROPERTY;
     return name + index;
   }
 
@@ -127,25 +130,6 @@
     return true;
   }
 
-  private synchronized void addThrowableToDynamicTestToFailures(
-      Description test, Throwable throwable) {
-    List<Throwable> throwables = dynamicTestToFailures.get(test);
-    if (throwables == null) {
-      throwables = new ArrayList<Throwable>();
-      dynamicTestToFailures.put(test, throwables);
-    }
-    throwables.add(throwable);
-  }
-
-  private synchronized int addNameToRepeatedPropertyNamesAndGetRepetitionsNr(String name) {
-    Integer previousRepetitionsNr = repeatedPropertyNamesToRepetitions.get(name);
-    if (previousRepetitionsNr == null) {
-      previousRepetitionsNr = 0;
-    }
-    repeatedPropertyNamesToRepetitions.put(name, previousRepetitionsNr + 1);
-    return previousRepetitionsNr;
-  }
-
   private synchronized boolean compareAndSetState(State fromState, State toState, long now) {
     if (fromState == null || toState == null || state == null) {
       throw new NullPointerException();
diff --git a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java
index 543acfe..08be4ca 100644
--- a/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java
+++ b/src/java_tools/junitrunner/java/com/google/testing/junit/runner/model/TestSuiteModel.java
@@ -14,8 +14,13 @@
 
 package com.google.testing.junit.runner.model;
 
+import static com.google.common.base.Predicates.notNull;
+import static com.google.common.collect.Maps.filterValues;
+import static com.google.common.collect.Maps.transformValues;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
 import com.google.common.base.Ticker;
 import com.google.testing.junit.junit4.runner.DynamicTestException;
 import com.google.testing.junit.runner.sharding.ShardingEnvironment;
@@ -25,7 +30,6 @@
 import java.io.OutputStream;
 import java.io.StringWriter;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -265,9 +269,7 @@
     }
 
     public TestSuiteModel build(String suiteName, Description... topLevelSuites) {
-      if (buildWasCalled) {
-        throw new IllegalStateException("Builder.build() was already called");
-      }
+      Preconditions.checkState(!buildWasCalled, "Builder.build() was already called");
       buildWasCalled = true;
       if (shardingEnvironment.isShardingEnabled()) {
         shardingFilter = getShardingFilter(topLevelSuites);
@@ -315,9 +317,7 @@
     }
 
     private void addTestCase(TestSuiteNode parentSuite, Description testCaseDesc) {
-      if (!testCaseDesc.isTest()) {
-        throw new IllegalArgumentException();
-      }
+      Preconditions.checkArgument(testCaseDesc.isTest());
       if (!shardingFilter.shouldRun(testCaseDesc)) {
         return;
       }
@@ -327,19 +327,16 @@
     }
   }
 
-  /**
-   * Converts the values of the Map from {@link TestNode} to {@link TestCaseNode} filtering out null
-   * values.
-   */
   private static Map<Description, TestCaseNode> filterTestCases(Map<Description, TestNode> tests) {
-    Map<Description, TestCaseNode> filteredAndConvertedTests =
-        new HashMap<Description, TestCaseNode>();
-    for (Description key : tests.keySet()) {
-      TestNode testNode = tests.get(key);
-      if (testNode != null && testNode instanceof TestCaseNode) {
-        filteredAndConvertedTests.put(key, (TestCaseNode) testNode);
+    return filterValues(transformValues(tests, toTestCaseNode()), notNull());
+  }
+
+  private static Function<TestNode, TestCaseNode> toTestCaseNode() {
+    return new Function<TestNode, TestCaseNode>() {
+      @Override
+      public TestCaseNode apply(TestNode test) {
+        return test instanceof TestCaseNode ? (TestCaseNode) test : null;
       }
-    }
-    return filteredAndConvertedTests;
+    };
   }
 }