Use distinct times for each TestRepository in acceptance tests

It is easy to create identical commits using e.g. PushOneCommit, which
uses a fixed commit message and tree contents by default. It uses
TestRepository's native commit timestamp ticking such that each new
commit gets a different commit timestamp, but this still causes
problems when multiple TestRepository instances are created in the
same process: each instance starts its clock at the same epoch.

The result is identical computed Change-Ids for completely unrelated
changes. Many tests (reasonably) assume that a Change-Id is unique
within the scope of that test, and this would violate that assumption
if we want to reuse a running server for multiple tests (and we do).

Work around this problem by giving each new TestRepository instance
(at least when created via GitUtil) its own 1-day window of
timestamps. There are some 8k 1-day windows until 2038 when JGit runs
out of 32-bit signed int timestamps, which should be enough for a
single test process. Likewise a 1-day window provides 86k ticks of the
clock before colliding with the next window, which should be enough
for a single test method.

Change-Id: Id86db8eb853d54bf2b88900274f595243e290fc4
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
index d90e459..2cd2579 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GitUtil.java
@@ -16,6 +16,7 @@
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
+import com.google.common.primitives.Ints;
 import com.google.gerrit.common.FooterConstants;
 import com.google.gerrit.reviewdb.client.Project;
 
@@ -31,6 +32,7 @@
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.FetchResult;
 import org.eclipse.jgit.transport.JschConfigSessionFactory;
@@ -43,8 +45,12 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class GitUtil {
+  private static final AtomicInteger testRepoCount = new AtomicInteger();
+  private static final int TEST_REPO_WINDOW_DAYS = 2;
 
   public static void initSsh(final TestAccount a) {
     final Properties config = new Properties();
@@ -68,6 +74,31 @@
     });
   }
 
+  /**
+   * Create a new {@link TestRepository} with a distinct commit clock.
+   * <p>
+   * It is very easy for tests to create commits with identical subjects and
+   * trees; if such commits also have identical authors/committers, then the
+   * computed Change-Id is identical as well. Tests may generally assume that
+   * Change-Ids are unique, so to ensure this, we provision TestRepository
+   * instances with non-overlapping commit clock times.
+   * <p>
+   * Space test repos 1 day apart, which allows for about 86k ticks per repo
+   * before overlapping, and about 8k instances per process before hitting
+   * JGit's year 2038 limit.
+   *
+   * @param repo repository to wrap.
+   * @return wrapped test repository with distinct commit time space.
+   */
+  public static <R extends Repository> TestRepository<R> newTestRepository(
+      R repo) throws IOException {
+    TestRepository<R> tr = new TestRepository<>(repo);
+    tr.tick(Ints.checkedCast(TimeUnit.SECONDS.convert(
+        testRepoCount.getAndIncrement() * TEST_REPO_WINDOW_DAYS,
+        TimeUnit.DAYS)));
+    return tr;
+  }
+
   public static TestRepository<InMemoryRepository> cloneProject(
       Project.NameKey project, String uri) throws Exception {
     InMemoryRepository dest = new InMemoryRepository.Builder()
@@ -81,13 +112,13 @@
     cfg.setString("remote", "origin", "url", uri);
     cfg.setString("remote", "origin", "fetch",
         "+refs/heads/*:refs/remotes/origin/*");
-    TestRepository<InMemoryRepository> testRepo = new TestRepository<>(dest);
+    TestRepository<InMemoryRepository> testRepo = newTestRepository(dest);
     FetchResult result = testRepo.git().fetch().setRemote("origin").call();
     String originMaster = "refs/remotes/origin/master";
     if (result.getTrackingRefUpdate(originMaster) != null) {
       testRepo.reset(originMaster);
     }
-    return new TestRepository<>(dest);
+    return testRepo;
   }
 
   public static TestRepository<InMemoryRepository> cloneProject(
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
index 8e627c4..038a208 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GetCommitIT.java
@@ -19,6 +19,7 @@
 
 import com.google.common.collect.Iterables;
 import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.GitUtil;
 import com.google.gerrit.acceptance.PushOneCommit;
 import com.google.gerrit.acceptance.RestResponse;
 import com.google.gerrit.common.data.AccessSection;
@@ -40,7 +41,7 @@
 
   @Before
   public void setUp() throws Exception {
-    repo = new TestRepository<>(repoManager.openRepository(project));
+    repo = GitUtil.newTestRepository(repoManager.openRepository(project));
 
     ProjectConfig pc = projectCache.checkedGet(allProjects).getConfig();
     for (AccessSection sec : pc.getAccessSections()) {