Merge "Use Project.NameKey in submodule tests"
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java b/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
index 66a09f8..f306932 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractSubmoduleSubscription.java
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.RemoteRefUpdate;
 import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.junit.Before;
 
 public abstract class AbstractSubmoduleSubscription extends AbstractDaemonTest {
 
@@ -95,7 +96,7 @@
     return cfg;
   }
 
-  protected TestRepository<?> createProjectWithPush(
+  protected Project.NameKey createProjectForPush(
       String name,
       @Nullable Project.NameKey parent,
       boolean createEmptyCommit,
@@ -104,24 +105,40 @@
     Project.NameKey project = createProject(name, parent, createEmptyCommit, submitType);
     grant(project, "refs/heads/*", Permission.PUSH);
     grant(project, "refs/for/refs/heads/*", Permission.SUBMIT);
-    return cloneProject(project);
-  }
-
-  protected TestRepository<?> createProjectWithPush(String name, @Nullable Project.NameKey parent)
-      throws Exception {
-    return createProjectWithPush(name, parent, true, getSubmitType());
-  }
-
-  protected TestRepository<?> createProjectWithPush(String name, boolean createEmptyCommit)
-      throws Exception {
-    return createProjectWithPush(name, null, createEmptyCommit, getSubmitType());
+    return project;
   }
 
   protected TestRepository<?> createProjectWithPush(String name) throws Exception {
     return createProjectWithPush(name, null, true, getSubmitType());
   }
 
+  protected TestRepository<?> createProjectWithPush(
+      String name,
+      @Nullable Project.NameKey parent,
+      boolean createEmptyCommit,
+      SubmitType submitType)
+      throws Exception {
+    return cloneProject(createProjectForPush(name, parent, createEmptyCommit, submitType));
+  }
+
+  protected TestRepository<?> createProjectWithPush(String name, boolean createEmptyCommit)
+      throws Exception {
+    return cloneProject(createProjectForPush(name, null, createEmptyCommit, getSubmitType()));
+  }
+
   private static AtomicInteger contentCounter = new AtomicInteger(0);
+  protected TestRepository<?> superRepo;
+  protected Project.NameKey superKey;
+  protected TestRepository<?> subRepo;
+  protected Project.NameKey subKey;
+
+  @Before
+  public void setUp() throws Exception {
+    superKey = createProjectForPush("super", null, true, getSubmitType());
+    subKey = createProjectForPush("sub", null, true, getSubmitType());
+    superRepo = cloneProject(superKey);
+    subRepo = cloneProject(subKey);
+  }
 
   protected ObjectId pushChangeTo(
       TestRepository<?> repo, String ref, String file, String content, String message, String topic)
@@ -184,16 +201,31 @@
   protected void allowSubmoduleSubscription(
       String submodule, String subBranch, String superproject, String superBranch, boolean match)
       throws Exception {
-    Project.NameKey sub = new Project.NameKey(name(submodule));
-    Project.NameKey superName = new Project.NameKey(name(superproject));
-    try (MetaDataUpdate md = metaDataUpdateFactory.create(sub)) {
+    allowSubmoduleSubscription(
+        nameKey(submodule), subBranch, nameKey(superproject), superBranch, match);
+  }
+
+  protected void allowMatchingSubmoduleSubscription(
+      Project.NameKey submodule, String subBranch, Project.NameKey superproject, String superBranch)
+      throws Exception {
+    allowSubmoduleSubscription(submodule, subBranch, superproject, superBranch, true);
+  }
+
+  protected void allowSubmoduleSubscription(
+      Project.NameKey submodule,
+      String subBranch,
+      Project.NameKey superproject,
+      String superBranch,
+      boolean match)
+      throws Exception {
+    try (MetaDataUpdate md = metaDataUpdateFactory.create(submodule)) {
       md.setMessage("Added superproject subscription");
       SubscribeSection s;
       ProjectConfig pc = projectConfigFactory.read(md);
-      if (pc.getSubscribeSections().containsKey(superName)) {
-        s = pc.getSubscribeSections().get(superName);
+      if (pc.getSubscribeSections().containsKey(superproject)) {
+        s = pc.getSubscribeSections().get(superproject);
       } else {
-        s = new SubscribeSection(superName);
+        s = new SubscribeSection(superproject);
       }
       String refspec;
       if (superBranch == null) {
@@ -223,6 +255,15 @@
   protected void createSubmoduleSubscription(
       TestRepository<?> repo, String branch, String subscribeToRepo, String subscribeToBranch)
       throws Exception {
+    createSubmoduleSubscription(repo, branch, nameKey(subscribeToRepo), subscribeToBranch);
+  }
+
+  protected void createSubmoduleSubscription(
+      TestRepository<?> repo,
+      String branch,
+      Project.NameKey subscribeToRepo,
+      String subscribeToBranch)
+      throws Exception {
     Config config = new Config();
     prepareSubmoduleConfigEntry(config, subscribeToRepo, subscribeToBranch);
     pushSubmoduleConfig(repo, branch, config);
@@ -246,12 +287,20 @@
       String subscribeToRepoPrefix,
       String subscribeToRepo,
       String subscribeToBranch) {
-    subscribeToRepo = name(subscribeToRepo);
-    String url = subscribeToRepoPrefix + subscribeToRepo;
-    config.setString("submodule", subscribeToRepo, "path", subscribeToRepo);
-    config.setString("submodule", subscribeToRepo, "url", url);
+    prepareRelativeSubmoduleConfigEntry(
+        config, subscribeToRepoPrefix, nameKey(subscribeToRepo), subscribeToBranch);
+  }
+
+  protected void prepareRelativeSubmoduleConfigEntry(
+      Config config,
+      String subscribeToRepoPrefix,
+      Project.NameKey subscribeToRepo,
+      String subscribeToBranch) {
+    String url = subscribeToRepoPrefix + subscribeToRepo.get();
+    config.setString("submodule", subscribeToRepo.get(), "path", subscribeToRepo.get());
+    config.setString("submodule", subscribeToRepo.get(), "url", url);
     if (subscribeToBranch != null) {
-      config.setString("submodule", subscribeToRepo, "branch", subscribeToBranch);
+      config.setString("submodule", subscribeToRepo.get(), "branch", subscribeToBranch);
     }
   }
 
@@ -260,21 +309,41 @@
     // The submodule subscription module checks for gerrit.canonicalWebUrl to
     // detect if it's configured for automatic updates. It doesn't matter if
     // it serves from that URL.
+    prepareSubmoduleConfigEntry(
+        config, nameKey(subscribeToRepo), nameKey(subscribeToRepo), subscribeToBranch);
+  }
+
+  protected void prepareSubmoduleConfigEntry(
+      Config config, Project.NameKey subscribeToRepo, String subscribeToBranch) {
+    // The submodule subscription module checks for gerrit.canonicalWebUrl to
+    // detect if it's configured for automatic updates. It doesn't matter if
+    // it serves from that URL.
     prepareSubmoduleConfigEntry(config, subscribeToRepo, subscribeToRepo, subscribeToBranch);
   }
 
+  protected Project.NameKey nameKey(String s) {
+    return new Project.NameKey(name(s));
+  }
+
   protected void prepareSubmoduleConfigEntry(
       Config config, String subscribeToRepo, String subscribeToRepoPath, String subscribeToBranch) {
-    subscribeToRepo = name(subscribeToRepo);
-    subscribeToRepoPath = name(subscribeToRepoPath);
+    prepareSubmoduleConfigEntry(
+        config, nameKey(subscribeToRepo), nameKey(subscribeToRepoPath), subscribeToBranch);
+  }
+
+  protected void prepareSubmoduleConfigEntry(
+      Config config,
+      Project.NameKey subscribeToRepo,
+      Project.NameKey subscribeToRepoPath,
+      String subscribeToBranch) {
     // The submodule subscription module checks for gerrit.canonicalWebUrl to
     // detect if it's configured for automatic updates. It doesn't matter if
     // it serves from that URL.
     String url = cfg.getString("gerrit", null, "canonicalWebUrl") + "/" + subscribeToRepo;
-    config.setString("submodule", subscribeToRepoPath, "path", subscribeToRepoPath);
-    config.setString("submodule", subscribeToRepoPath, "url", url);
+    config.setString("submodule", subscribeToRepoPath.get(), "path", subscribeToRepoPath.get());
+    config.setString("submodule", subscribeToRepoPath.get(), "url", url);
     if (subscribeToBranch != null) {
-      config.setString("submodule", subscribeToRepoPath, "branch", subscribeToBranch);
+      config.setString("submodule", subscribeToRepoPath.get(), "branch", subscribeToBranch);
     }
   }
 
@@ -302,8 +371,17 @@
       TestRepository<?> subRepo,
       String subBranch)
       throws Exception {
+    expectToHaveSubmoduleState(repo, branch, nameKey(submodule), subRepo, subBranch);
+  }
 
-    submodule = name(submodule);
+  protected void expectToHaveSubmoduleState(
+      TestRepository<?> repo,
+      String branch,
+      Project.NameKey submodule,
+      TestRepository<?> subRepo,
+      String subBranch)
+      throws Exception {
+
     ObjectId commitId =
         repo.git()
             .fetch()
@@ -326,7 +404,7 @@
     rw.parseBody(c.getTree());
 
     RevTree tree = c.getTree();
-    RevObject actualId = repo.get(tree, submodule);
+    RevObject actualId = repo.get(tree, submodule.get());
 
     assertThat(actualId).isEqualTo(subHead);
   }
@@ -334,8 +412,12 @@
   protected void expectToHaveSubmoduleState(
       TestRepository<?> repo, String branch, String submodule, ObjectId expectedId)
       throws Exception {
+    expectToHaveSubmoduleState(repo, branch, nameKey(submodule), expectedId);
+  }
 
-    submodule = name(submodule);
+  protected void expectToHaveSubmoduleState(
+      TestRepository<?> repo, String branch, Project.NameKey submodule, ObjectId expectedId)
+      throws Exception {
     ObjectId commitId =
         repo.git()
             .fetch()
@@ -349,7 +431,7 @@
     rw.parseBody(c.getTree());
 
     RevTree tree = c.getTree();
-    RevObject actualId = repo.get(tree, submodule);
+    RevObject actualId = repo.get(tree, submodule.get());
 
     assertThat(actualId).isEqualTo(expectedId);
   }
@@ -410,8 +492,11 @@
 
   protected boolean hasSubmodule(TestRepository<?> repo, String branch, String submodule)
       throws Exception {
+    return hasSubmodule(repo, branch, new Project.NameKey(name(submodule)));
+  }
 
-    submodule = name(submodule);
+  protected boolean hasSubmodule(TestRepository<?> repo, String branch, Project.NameKey submodule)
+      throws Exception {
     Ref branchTip =
         repo.git().fetch().setRemote("origin").call().getAdvertisedRef("refs/heads/" + branch);
     if (branchTip == null) {
@@ -426,7 +511,7 @@
 
     RevTree tree = c.getTree();
     try {
-      repo.get(tree, submodule);
+      repo.get(tree, submodule.get());
       return true;
     } catch (AssertionError e) {
       return false;
@@ -446,7 +531,8 @@
 
     RevWalk rw = repo.getRevWalk();
     RevCommit c = rw.parseCommit(commitId);
-    assertThat(c.getFullMessage()).isEqualTo(expectedMessage);
+    String msg = c.getFullMessage();
+    assertThat(msg).isEqualTo(expectedMessage);
   }
 
   protected PersonIdent getAuthor(TestRepository<?> repo, String branch) throws Exception {
@@ -465,8 +551,13 @@
 
   protected void directUpdateSubmodule(String project, String refName, String path, AnyObjectId id)
       throws Exception {
-    path = name(path);
-    try (Repository serverRepo = repoManager.openRepository(new Project.NameKey(name(project)));
+    directUpdateSubmodule(nameKey(project), refName, nameKey(path), id);
+  }
+
+  protected void directUpdateSubmodule(
+      Project.NameKey project, String refName, Project.NameKey path, AnyObjectId id)
+      throws Exception {
+    try (Repository serverRepo = repoManager.openRepository(project);
         ObjectInserter ins = serverRepo.newObjectInserter();
         RevWalk rw = new RevWalk(serverRepo)) {
       Ref ref = serverRepo.exactRef(refName);
@@ -480,7 +571,7 @@
       b.finish();
       DirCacheEditor e = dc.editor();
       e.add(
-          new PathEdit(path) {
+          new PathEdit(path.get()) {
             @Override
             public void apply(DirCacheEntry ent) {
               ent.setFileMode(FileMode.GITLINK);
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
index 03b1165..d76b310 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsIT.java
@@ -25,6 +25,7 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.TestTimeUtil;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
@@ -47,198 +48,169 @@
   @Test
   @GerritConfig(name = "submodule.enableSuperProjectSubscriptions", value = "false")
   public void testSubscriptionWithoutGlobalServerSetting() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionWithoutSpecificSubscription() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionToEmptyRepo() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isTrue();
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD);
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isTrue();
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD);
   }
 
   @Test
   public void subscriptionToExistingRepo() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isTrue();
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD);
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isTrue();
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD);
   }
 
   @Test
   public void subscriptionWildcardACLForSingleBranch() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
     // master is allowed to be subscribed to master branch only:
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", null);
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, null);
     // create 'branch':
     pushChangeTo(superRepo, "branch");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
-    createSubmoduleSubscription(superRepo, "branch", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
+    createSubmoduleSubscription(superRepo, "branch", subKey, "master");
 
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD);
-    assertThat(hasSubmodule(superRepo, "branch", "subscribed-to-project")).isFalse();
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD);
+    assertThat(hasSubmodule(superRepo, "branch", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionWildcardACLForMissingProject() throws Exception {
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
     allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/*", "not-existing-super-project", "refs/heads/*");
+        subKey, "refs/heads/*", new Project.NameKey("not-existing-super-project"), "refs/heads/*");
     pushChangeTo(subRepo, "master");
   }
 
   @Test
   public void subscriptionWildcardACLForMissingBranch() throws Exception {
-    createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/*", "super-project", "refs/heads/*");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/*", superKey, "refs/heads/*");
     pushChangeTo(subRepo, "foo");
   }
 
   @Test
   public void subscriptionWildcardACLForMissingGitmodules() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/*", "super-project", "refs/heads/*");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/*", superKey, "refs/heads/*");
     pushChangeTo(superRepo, "master");
     pushChangeTo(subRepo, "master");
   }
 
   @Test
   public void subscriptionWildcardACLOneOnOneMapping() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
     // any branch is allowed to be subscribed to the same superprojects branch:
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/*", "super-project", "refs/heads/*");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/*", superKey, "refs/heads/*");
 
     // create 'branch' in both repos:
     pushChangeTo(superRepo, "branch");
     pushChangeTo(subRepo, "branch");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
-    createSubmoduleSubscription(superRepo, "branch", "subscribed-to-project", "branch");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
+    createSubmoduleSubscription(superRepo, "branch", subKey, "branch");
 
     ObjectId subHEAD1 = pushChangeTo(subRepo, "master");
     ObjectId subHEAD2 = pushChangeTo(subRepo, "branch");
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD1);
-    expectToHaveSubmoduleState(superRepo, "branch", "subscribed-to-project", subHEAD2);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD1);
+    expectToHaveSubmoduleState(superRepo, "branch", subKey, subHEAD2);
 
     // Now test that cross subscriptions do not work:
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "branch");
+    createSubmoduleSubscription(superRepo, "master", subKey, "branch");
     ObjectId subHEAD3 = pushChangeTo(subRepo, "branch");
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD1);
-    expectToHaveSubmoduleState(superRepo, "branch", "subscribed-to-project", subHEAD3);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD1);
+    expectToHaveSubmoduleState(superRepo, "branch", subKey, subHEAD3);
   }
 
   @Test
   public void subscriptionWildcardACLForManyBranches() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
 
     // Any branch is allowed to be subscribed to any superproject branch:
-    allowSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/*", "super-project", null, false);
+    allowSubmoduleSubscription(subKey, "refs/heads/*", superKey, null, false);
     pushChangeTo(superRepo, "branch");
     pushChangeTo(subRepo, "another-branch");
-    createSubmoduleSubscription(superRepo, "branch", "subscribed-to-project", "another-branch");
+    createSubmoduleSubscription(superRepo, "branch", subKey, "another-branch");
     ObjectId subHEAD = pushChangeTo(subRepo, "another-branch");
-    expectToHaveSubmoduleState(superRepo, "branch", "subscribed-to-project", subHEAD);
+    expectToHaveSubmoduleState(superRepo, "branch", subKey, subHEAD);
   }
 
   @Test
   public void subscriptionWildcardACLOneToManyBranches() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
 
     // Any branch is allowed to be subscribed to any superproject branch:
-    allowSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/*", false);
+    allowSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/*", false);
     pushChangeTo(superRepo, "branch");
-    createSubmoduleSubscription(superRepo, "branch", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "branch", subKey, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "branch", "subscribed-to-project", subHEAD);
+    expectToHaveSubmoduleState(superRepo, "branch", subKey, subHEAD);
 
-    createSubmoduleSubscription(superRepo, "branch", "subscribed-to-project", "branch");
+    createSubmoduleSubscription(superRepo, "branch", subKey, "branch");
     pushChangeTo(subRepo, "branch");
 
     // no change expected, as only master is subscribed:
-    expectToHaveSubmoduleState(superRepo, "branch", "subscribed-to-project", subHEAD);
+    expectToHaveSubmoduleState(superRepo, "branch", subKey, subHEAD);
   }
 
   @Test
   @GerritConfig(name = "submodule.verboseSuperprojectUpdate", value = "false")
   public void testSubmoduleShortCommitMessage() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     // The first update doesn't include any commit messages
     ObjectId subRepoId = pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subRepoId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepoId);
     expectToHaveCommitMessage(superRepo, "master", "Update git submodules\n\n");
 
     // Any following update also has a short message
     subRepoId = pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subRepoId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepoId);
     expectToHaveCommitMessage(superRepo, "master", "Update git submodules\n\n");
   }
 
   @Test
   @GerritConfig(name = "submodule.verboseSuperprojectUpdate", value = "SUBJECT_ONLY")
   public void testSubmoduleSubjectCommitMessage() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
 
     // The first update doesn't include the rev log
@@ -248,7 +220,7 @@
         "master",
         "Update git submodules\n\n"
             + "* Update "
-            + name("subscribed-to-project")
+            + subKey.get()
             + " from branch 'master'\n  to "
             + subHEAD.getName());
 
@@ -261,7 +233,7 @@
         "master",
         "Update git submodules\n\n"
             + "* Update "
-            + name("subscribed-to-project")
+            + subKey.get()
             + " from branch 'master'\n  to "
             + subHEAD.getName()
             + "\n  - "
@@ -270,13 +242,11 @@
 
   @Test
   public void submoduleCommitMessage() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
 
     // The first update doesn't include the rev log
@@ -286,7 +256,7 @@
         "master",
         "Update git submodules\n\n"
             + "* Update "
-            + name("subscribed-to-project")
+            + subKey.get()
             + " from branch 'master'\n  to "
             + subHEAD.getName());
 
@@ -299,7 +269,7 @@
         "master",
         "Update git submodules\n\n"
             + "* Update "
-            + name("subscribed-to-project")
+            + subKey.get()
             + " from branch 'master'\n  to "
             + subHEAD.getName()
             + "\n  - "
@@ -308,171 +278,151 @@
 
   @Test
   public void subscriptionUnsubscribe() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     pushChangeTo(subRepo, "master");
     ObjectId subHEADbeforeUnsubscribing = pushChangeTo(subRepo, "master");
 
     deleteAllSubscriptions(superRepo, "master");
-    expectToHaveSubmoduleState(
-        superRepo, "master", "subscribed-to-project", subHEADbeforeUnsubscribing);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEADbeforeUnsubscribing);
 
     pushChangeTo(superRepo, "refs/heads/master", "commit after unsubscribe", "");
     pushChangeTo(subRepo, "refs/heads/master", "commit after unsubscribe", "");
-    expectToHaveSubmoduleState(
-        superRepo, "master", "subscribed-to-project", subHEADbeforeUnsubscribing);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEADbeforeUnsubscribing);
   }
 
   @Test
   public void subscriptionUnsubscribeByDeletingGitModules() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     pushChangeTo(subRepo, "master");
     ObjectId subHEADbeforeUnsubscribing = pushChangeTo(subRepo, "master");
 
     deleteGitModulesFile(superRepo, "master");
-    expectToHaveSubmoduleState(
-        superRepo, "master", "subscribed-to-project", subHEADbeforeUnsubscribing);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEADbeforeUnsubscribing);
 
     pushChangeTo(superRepo, "refs/heads/master", "commit after unsubscribe", "");
     pushChangeTo(subRepo, "refs/heads/master", "commit after unsubscribe", "");
-    expectToHaveSubmoduleState(
-        superRepo, "master", "subscribed-to-project", subHEADbeforeUnsubscribing);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEADbeforeUnsubscribing);
   }
 
   @Test
   public void subscriptionToDifferentBranches() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/foo", "super-project", "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "foo");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/foo", superKey, "refs/heads/master");
+
+    createSubmoduleSubscription(superRepo, "master", subKey, "foo");
     ObjectId subFoo = pushChangeTo(subRepo, "foo");
     pushChangeTo(subRepo, "master");
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subFoo);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subFoo);
   }
 
   @Test
   public void branchCircularSubscription() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "super-project", "refs/heads/master", "subscribed-to-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(superKey, "refs/heads/master", subKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
     pushChangeTo(superRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
-    createSubmoduleSubscription(subRepo, "master", "super-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
+    createSubmoduleSubscription(subRepo, "master", superKey, "master");
 
     pushChangeTo(subRepo, "master");
     pushChangeTo(superRepo, "master");
 
-    assertThat(hasSubmodule(subRepo, "master", "super-project")).isFalse();
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(subRepo, "master", superKey)).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void projectCircularSubscription() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
 
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "super-project", "refs/heads/dev", "subscribed-to-project", "refs/heads/dev");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(superKey, "refs/heads/dev", subKey, "refs/heads/dev");
 
     pushChangeTo(subRepo, "master");
     pushChangeTo(superRepo, "master");
     pushChangeTo(subRepo, "dev");
     pushChangeTo(superRepo, "dev");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
-    createSubmoduleSubscription(subRepo, "dev", "super-project", "dev");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
+    createSubmoduleSubscription(subRepo, "dev", superKey, "dev");
 
     ObjectId subMasterHead = pushChangeTo(subRepo, "master");
     ObjectId superDevHead = pushChangeTo(superRepo, "dev");
 
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isTrue();
-    assertThat(hasSubmodule(subRepo, "dev", "super-project")).isTrue();
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subMasterHead);
-    expectToHaveSubmoduleState(subRepo, "dev", "super-project", superDevHead);
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isTrue();
+    assertThat(hasSubmodule(subRepo, "dev", superKey)).isTrue();
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subMasterHead);
+    expectToHaveSubmoduleState(subRepo, "dev", superKey, superDevHead);
   }
 
   @Test
   public void subscriptionFailOnMissingACL() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionFailOnWrongProjectACL() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
     allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "wrong-super-project", "refs/heads/master");
+        subKey,
+        "refs/heads/master",
+        new Project.NameKey("wrong-super-project"),
+        "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionFailOnWrongBranchACL() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
     allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/wrong-branch");
+        subKey, "refs/heads/master", superKey, "refs/heads/wrong-branch");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     pushChangeTo(subRepo, "master");
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionInheritACL() throws Exception {
-    createProjectWithPush("config-repo");
-    createProjectWithPush("config-repo2", new Project.NameKey(name("config-repo")));
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo =
-        createProjectWithPush("subscribed-to-project", new Project.NameKey(name("config-repo2")));
-    allowMatchingSubmoduleSubscription(
-        "config-repo", "refs/heads/*", "super-project", "refs/heads/*");
+    Project.NameKey configKey = createProjectForPush("config-repo", null, true, getSubmitType());
+    Project.NameKey config2Key =
+        createProjectForPush("config-repo2", configKey, true, getSubmitType());
+    cloneProject(config2Key);
+
+    subKey = createProjectForPush("subrepo", config2Key, true, getSubmitType());
+    subRepo = cloneProject(subKey);
+
+    allowMatchingSubmoduleSubscription(configKey, "refs/heads/*", superKey, "refs/heads/*");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     ObjectId subHEAD = pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subHEAD);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subHEAD);
   }
 
   @Test
   public void allowedButNotSubscribed() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
     subRepo
@@ -490,16 +440,16 @@
     assertThat(r.getRemoteUpdate("refs/heads/master").getStatus())
         .isEqualTo(RemoteRefUpdate.Status.OK);
 
-    assertThat(hasSubmodule(superRepo, "master", "subscribed-to-project")).isFalse();
+    assertThat(hasSubmodule(superRepo, "master", subKey)).isFalse();
   }
 
   @Test
   public void subscriptionDeepRelative() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("nested/subscribed-to-project");
+    Project.NameKey nest =
+        createProjectForPush("nested/subscribed-to-project", null, true, getSubmitType());
+    TestRepository<?> subRepo = cloneProject(nest);
     // master is allowed to be subscribed to any superprojects branch:
-    allowMatchingSubmoduleSubscription(
-        "nested/subscribed-to-project", "refs/heads/master", "super-project", null);
+    allowMatchingSubmoduleSubscription(nest, "refs/heads/master", superKey, null);
 
     pushChangeTo(subRepo, "master");
     createRelativeSubmoduleSubscription(
@@ -519,7 +469,9 @@
 
   @Test
   @GerritConfig(name = "submodule.verboseSuperprojectUpdate", value = "SUBJECT_ONLY")
-  @GerritConfig(name = "submodule.maxCombinedCommitMessageSize", value = "220")
+  // The value 195 must tuned to the test environment, and is sensitive to the
+  // length of the uniquified repository name.
+  @GerritConfig(name = "submodule.maxCombinedCommitMessageSize", value = "200")
   public void submoduleSubjectCommitMessageSizeLimit() throws Exception {
     assume().that(isSubmitWholeTopicEnabled()).isFalse();
     testSubmoduleSubjectCommitMessageAndExpectTruncation();
@@ -530,11 +482,10 @@
     // Make sure that the commit is created at an earlier timestamp than the submit timestamp.
     TestTimeUtil.resetWithClockStep(1, SECONDS);
     try {
-      TestRepository<?> superRepo = createProjectWithPush("super-project");
-      TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
+
       allowMatchingSubmoduleSubscription(
-          "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-      createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+          subKey, "refs/heads/master", superKey, "refs/heads/master");
+      createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
       PushOneCommit.Result pushResult =
           createChange(subRepo, "refs/heads/master", "Change", "a.txt", "some content", null);
@@ -561,18 +512,18 @@
     // is afterwards.
     TestTimeUtil.resetWithClockStep(1, SECONDS);
     try {
-      TestRepository<?> superRepo = createProjectWithPush("super-project");
-      TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-      TestRepository<?> subRepo2 = createProjectWithPush("subscribed-to-project-2");
 
+      Project.NameKey proj2 =
+          createProjectForPush("subscribed-to-project-2", null, true, getSubmitType());
+
+      TestRepository<?> subRepo2 = cloneProject(proj2);
       allowMatchingSubmoduleSubscription(
-          "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-      allowMatchingSubmoduleSubscription(
-          "subscribed-to-project-2", "refs/heads/master", "super-project", "refs/heads/master");
+          subKey, "refs/heads/master", superKey, "refs/heads/master");
+      allowMatchingSubmoduleSubscription(proj2, "refs/heads/master", superKey, "refs/heads/master");
 
       Config config = new Config();
-      prepareSubmoduleConfigEntry(config, "subscribed-to-project", "master");
-      prepareSubmoduleConfigEntry(config, "subscribed-to-project-2", "master");
+      prepareSubmoduleConfigEntry(config, subKey, subKey, "master");
+      prepareSubmoduleConfigEntry(config, proj2, proj2, "master");
       pushSubmoduleConfig(superRepo, "master", config);
 
       String topic = "foo";
@@ -610,21 +561,17 @@
     // is afterwards.
     TestTimeUtil.resetWithClockStep(1, SECONDS);
     try {
-      TestRepository<?> superRepo = createProjectWithPush("super-project");
-      TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-
-      createProjectWithPush("subscribed-to-project-2");
-      TestRepository<?> subRepo2 =
-          cloneProject(new Project.NameKey(name("subscribed-to-project-2")), user);
+      Project.NameKey proj2 =
+          createProjectForPush("subscribed-to-project-2", null, true, getSubmitType());
+      TestRepository<InMemoryRepository> repo2 = cloneProject(proj2, user);
 
       allowMatchingSubmoduleSubscription(
-          "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-      allowMatchingSubmoduleSubscription(
-          "subscribed-to-project-2", "refs/heads/master", "super-project", "refs/heads/master");
+          subKey, "refs/heads/master", superKey, "refs/heads/master");
+      allowMatchingSubmoduleSubscription(proj2, "refs/heads/master", superKey, "refs/heads/master");
 
       Config config = new Config();
-      prepareSubmoduleConfigEntry(config, "subscribed-to-project", "master");
-      prepareSubmoduleConfigEntry(config, "subscribed-to-project-2", "master");
+      prepareSubmoduleConfigEntry(config, subKey, subKey, "master");
+      prepareSubmoduleConfigEntry(config, proj2, proj2, "master");
       pushSubmoduleConfig(superRepo, "master", config);
 
       String topic = "foo";
@@ -636,7 +583,7 @@
 
       // Create change as user.
       PushOneCommit push =
-          pushFactory.create(db, user.getIdent(), subRepo2, "Change 2", "b.txt", "other content");
+          pushFactory.create(db, user.getIdent(), repo2, "Change 2", "b.txt", "other content");
       PushOneCommit.Result pushResult2 = push.to("refs/for/master/" + name(topic));
       approve(pushResult2.getChangeId());
 
@@ -659,14 +606,15 @@
 
   @Test
   public void updateOnlyRelevantSubmodules() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo1 = createProjectWithPush("subscribed-to-project-1");
-    TestRepository<?> subRepo2 = createProjectWithPush("subscribed-to-project-2");
+    Project.NameKey subkey1 =
+        createProjectForPush("subscribed-to-project-1", null, true, getSubmitType());
+    Project.NameKey subkey2 =
+        createProjectForPush("subscribed-to-project-2", null, true, getSubmitType());
+    TestRepository<?> subRepo1 = cloneProject(subkey1);
+    TestRepository<?> subRepo2 = cloneProject(subkey2);
 
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project-1", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project-2", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subkey1, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subkey2, "refs/heads/master", superKey, "refs/heads/master");
 
     Config config = new Config();
     prepareSubmoduleConfigEntry(config, "subscribed-to-project-1", "master");
@@ -689,41 +637,35 @@
 
   @Test
   public void skipUpdatingBrokenGitlinkPointer() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
 
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     // Push once to initialize submodule.
     ObjectId subTip = pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subTip);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subTip);
 
     // Write an invalid SHA-1 directly to the gitlink.
     ObjectId badId = ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
-    directUpdateSubmodule("super-project", "refs/heads/master", "subscribed-to-project", badId);
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", badId);
+    directUpdateSubmodule(superKey, "refs/heads/master", subKey, badId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, badId);
 
     // Push succeeds, but gitlink update is skipped.
     pushChangeTo(subRepo, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", badId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, badId);
   }
 
   private ObjectId directUpdateRef(String project, String ref) throws Exception {
-    try (Repository serverRepo = repoManager.openRepository(new Project.NameKey(name(project)))) {
+    try (Repository serverRepo = repoManager.openRepository(nameKey(project))) {
       return new TestRepository<>(serverRepo).branch(ref).commit().create().copy();
     }
   }
 
   private void testSubmoduleSubjectCommitMessageAndExpectTruncation() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     pushChangeTo(subRepo, "master");
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
     // The first update doesn't include the rev log, so we ignore it
     pushChangeTo(subRepo, "master");
 
@@ -736,6 +678,6 @@
         "master",
         String.format(
             "Update git submodules\n\n* Update %s from branch 'master'\n  to %s\n  - %s\n\n[...]",
-            name("subscribed-to-project"), subHEAD.getName(), subCommitMsg.getShortMessage()));
+            subKey.get(), subHEAD.getName(), subCommitMsg.getShortMessage()));
   }
 }
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
index eef3295..0b583bf 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/SubmoduleSubscriptionsWholeTopicMergeIT.java
@@ -68,12 +68,8 @@
 
   @Test
   public void subscriptionUpdateOfManyChanges() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     ObjectId subHEAD =
         subRepo
@@ -150,15 +146,13 @@
             .getAdvertisedRef("refs/heads/master")
             .getObjectId();
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subRepoId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepoId);
 
     // As the submodules have changed commits, the superproject tree will be
     // different, so we cannot directly compare the trees here, so make
     // assumptions only about the changed branches:
-    Project.NameKey p1 = new Project.NameKey(name("super-project"));
-    Project.NameKey p2 = new Project.NameKey(name("subscribed-to-project"));
-    assertThat(preview).containsKey(new Branch.NameKey(p1, "refs/heads/master"));
-    assertThat(preview).containsKey(new Branch.NameKey(p2, "refs/heads/master"));
+    assertThat(preview).containsKey(new Branch.NameKey(superKey, "refs/heads/master"));
+    assertThat(preview).containsKey(new Branch.NameKey(subKey, "refs/heads/master"));
 
     if ((getSubmitType() == SubmitType.CHERRY_PICK)
         || (getSubmitType() == SubmitType.REBASE_ALWAYS)) {
@@ -176,12 +170,9 @@
 
   @Test
   public void subscriptionUpdateIncludingChangeInSuperproject() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     ObjectId subHEAD =
         subRepo
@@ -274,27 +265,27 @@
             .getAdvertisedRef("refs/heads/master")
             .getObjectId();
 
-    expectToHaveSubmoduleState(superRepo, "master", "subscribed-to-project", subRepoId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepoId);
   }
 
   @Test
   public void updateManySubmodules() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub1 = createProjectWithPush("sub1");
-    TestRepository<?> sub2 = createProjectWithPush("sub2");
-    TestRepository<?> sub3 = createProjectWithPush("sub3");
+    Project.NameKey subKey1 = createProjectForPush("sub1", null, true, getSubmitType());
+    Project.NameKey subKey2 = createProjectForPush("sub2", null, true, getSubmitType());
+    Project.NameKey subKey3 = createProjectForPush("sub3", null, true, getSubmitType());
 
-    allowMatchingSubmoduleSubscription(
-        "sub1", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "sub2", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "sub3", "refs/heads/master", "super-project", "refs/heads/master");
+    TestRepository<?> sub1 = cloneProject(subKey1);
+    TestRepository<?> sub2 = cloneProject(subKey2);
+    TestRepository<?> sub3 = cloneProject(subKey3);
+
+    allowMatchingSubmoduleSubscription(subKey1, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey2, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey3, "refs/heads/master", superKey, "refs/heads/master");
 
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "sub1", "master");
-    prepareSubmoduleConfigEntry(config, "sub2", "master");
-    prepareSubmoduleConfigEntry(config, "sub3", "master");
+    prepareSubmoduleConfigEntry(config, subKey1, "master");
+    prepareSubmoduleConfigEntry(config, subKey2, "master");
+    prepareSubmoduleConfigEntry(config, subKey3, "master");
     pushSubmoduleConfig(superRepo, "master", config);
 
     ObjectId superPreviousId = pushChangeTo(superRepo, "master");
@@ -309,9 +300,9 @@
 
     gApi.changes().id(getChangeId(sub1, sub1Id).get()).current().submit();
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub1", sub1, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "sub2", sub2, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "sub3", sub3, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey1, sub1, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey2, sub2, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey3, sub3, "master");
 
     String sub1HEAD =
         sub1.git()
@@ -346,15 +337,15 @@
           "master",
           "Update git submodules\n\n"
               + "* Update "
-              + name("sub1")
+              + subKey1.get()
               + " from branch 'master'\n  to "
               + sub1HEAD
               + "\n\n* Update "
-              + name("sub2")
+              + subKey2.get()
               + " from branch 'master'\n  to "
               + sub2HEAD
               + "\n\n* Update "
-              + name("sub3")
+              + subKey3.get()
               + " from branch 'master'\n  to "
               + sub3HEAD);
     }
@@ -374,73 +365,74 @@
 
   @Test
   public void doNotUseFastForward() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project", false);
-    TestRepository<?> sub = createProjectWithPush("sub", false);
+    // like setup, but without empty commit
+    superKey = createProjectForPush("super-nc", null, false, getSubmitType());
+    subKey = createProjectForPush("sub-nc", null, false, getSubmitType());
+    superRepo = cloneProject(superKey);
+    subRepo = cloneProject(subKey);
 
-    allowMatchingSubmoduleSubscription(
-        "sub", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "sub", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
-    ObjectId subId = pushChangeTo(sub, "refs/for/master", "some message", "same-topic");
+    ObjectId subId = pushChangeTo(subRepo, "refs/for/master", "some message", "same-topic");
 
     ObjectId superId = pushChangeTo(superRepo, "refs/for/master", "some message", "same-topic");
 
-    String subChangeId = getChangeId(sub, subId).get();
+    String subChangeId = getChangeId(subRepo, subId).get();
     approve(subChangeId);
     approve(getChangeId(superRepo, superId).get());
 
     gApi.changes().id(subChangeId).current().submit();
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub", sub, "master");
-    RevCommit superHead = getRemoteHead(name("super-project"), "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepo, "master");
+    RevCommit superHead = getRemoteHead(superKey, "master");
     assertThat(superHead.getShortMessage()).contains("some message");
     assertThat(superHead.getId()).isNotEqualTo(superId);
   }
 
   @Test
   public void useFastForwardWhenNoSubmodule() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project", false);
-    TestRepository<?> sub = createProjectWithPush("sub", false);
+    // like setup, but without empty commit
+    superKey = createProjectForPush("super-nc", null, false, getSubmitType());
+    subKey = createProjectForPush("sub-nc", null, false, getSubmitType());
+    superRepo = cloneProject(superKey);
+    subRepo = cloneProject(subKey);
 
-    ObjectId subId = pushChangeTo(sub, "refs/for/master", "some message", "same-topic");
-
+    ObjectId subId = pushChangeTo(subRepo, "refs/for/master", "some message", "same-topic");
     ObjectId superId = pushChangeTo(superRepo, "refs/for/master", "some message", "same-topic");
 
-    String subChangeId = getChangeId(sub, subId).get();
+    String subChangeId = getChangeId(subRepo, subId).get();
     approve(subChangeId);
     approve(getChangeId(superRepo, superId).get());
 
     gApi.changes().id(subChangeId).current().submit();
 
-    RevCommit superHead = getRemoteHead(name("super-project"), "master");
+    RevCommit superHead = getRemoteHead(superKey, "master");
     assertThat(superHead.getShortMessage()).isEqualTo("some message");
     assertThat(superHead.getId()).isEqualTo(superId);
   }
 
   @Test
   public void sameProjectSameBranchDifferentPaths() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub = createProjectWithPush("sub");
-
-    allowMatchingSubmoduleSubscription(
-        "sub", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "sub", "master");
-    prepareSubmoduleConfigEntry(config, "sub", "sub-copy", "master");
+    prepareSubmoduleConfigEntry(config, subKey, "master");
+    Project.NameKey copyKey = nameKey("sub-copy");
+    prepareSubmoduleConfigEntry(config, subKey, copyKey, "master");
     pushSubmoduleConfig(superRepo, "master", config);
 
     ObjectId superPreviousId = pushChangeTo(superRepo, "master");
 
-    ObjectId subId = pushChangeTo(sub, "refs/for/master", "some message", "");
+    ObjectId subId = pushChangeTo(subRepo, "refs/for/master", "some message", "");
 
-    approve(getChangeId(sub, subId).get());
+    approve(getChangeId(subRepo, subId).get());
 
-    gApi.changes().id(getChangeId(sub, subId).get()).current().submit();
+    gApi.changes().id(getChangeId(subRepo, subId).get()).current().submit();
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub", sub, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "sub-copy", sub, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepo, "master");
+    expectToHaveSubmoduleState(superRepo, "master", copyKey, subRepo, "master");
 
     superRepo
         .git()
@@ -457,37 +449,33 @@
 
   @Test
   public void sameProjectDifferentBranchDifferentPaths() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub = createProjectWithPush("sub");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/dev", superKey, "refs/heads/master");
 
-    allowMatchingSubmoduleSubscription(
-        "sub", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "sub", "refs/heads/dev", "super-project", "refs/heads/master");
-
-    ObjectId devHead = pushChangeTo(sub, "dev");
+    ObjectId devHead = pushChangeTo(subRepo, "dev");
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "sub", "sub-master", "master");
-    prepareSubmoduleConfigEntry(config, "sub", "sub-dev", "dev");
+    prepareSubmoduleConfigEntry(config, subKey, nameKey("sub-master"), "master");
+    prepareSubmoduleConfigEntry(config, subKey, nameKey("sub-dev"), "dev");
     pushSubmoduleConfig(superRepo, "master", config);
 
     ObjectId subMasterId =
-        pushChangeTo(sub, "refs/for/master", "some message", "b.txt", "content b", "same-topic");
+        pushChangeTo(
+            subRepo, "refs/for/master", "some message", "b.txt", "content b", "same-topic");
 
-    sub.reset(devHead);
+    subRepo.reset(devHead);
     ObjectId subDevId =
         pushChangeTo(
-            sub, "refs/for/dev", "some message in dev", "b.txt", "content b", "same-topic");
+            subRepo, "refs/for/dev", "some message in dev", "b.txt", "content b", "same-topic");
 
-    approve(getChangeId(sub, subMasterId).get());
-    approve(getChangeId(sub, subDevId).get());
+    approve(getChangeId(subRepo, subMasterId).get());
+    approve(getChangeId(subRepo, subDevId).get());
 
     ObjectId superPreviousId = pushChangeTo(superRepo, "master");
 
-    gApi.changes().id(getChangeId(sub, subMasterId).get()).current().submit();
+    gApi.changes().id(getChangeId(subRepo, subMasterId).get()).current().submit();
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub-master", sub, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "sub-dev", sub, "dev");
+    expectToHaveSubmoduleState(superRepo, "master", nameKey("sub-master"), subRepo, "master");
+    expectToHaveSubmoduleState(superRepo, "master", nameKey("sub-dev"), subRepo, "dev");
 
     superRepo
         .git()
@@ -504,29 +492,27 @@
 
   @Test
   public void nonSubmoduleInSameTopic() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub = createProjectWithPush("sub");
-    TestRepository<?> standAlone = createProjectWithPush("standalone");
+    Project.NameKey standaloneKey = createProjectForPush("standalone", null, true, getSubmitType());
+    TestRepository<?> standAlone = cloneProject(standaloneKey);
 
-    allowMatchingSubmoduleSubscription(
-        "sub", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
 
-    createSubmoduleSubscription(superRepo, "master", "sub", "master");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
 
     ObjectId superPreviousId = pushChangeTo(superRepo, "master");
 
-    ObjectId subId = pushChangeTo(sub, "refs/for/master", "some message", "same-topic");
+    ObjectId subId = pushChangeTo(subRepo, "refs/for/master", "some message", "same-topic");
     ObjectId standAloneId =
         pushChangeTo(standAlone, "refs/for/master", "some message", "same-topic");
 
-    String subChangeId = getChangeId(sub, subId).get();
+    String subChangeId = getChangeId(subRepo, subId).get();
     String standAloneChangeId = getChangeId(standAlone, standAloneId).get();
     approve(subChangeId);
     approve(standAloneChangeId);
 
     gApi.changes().id(subChangeId).current().submit();
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub", sub, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey, subRepo, "master");
 
     ChangeStatus status = gApi.changes().id(standAloneChangeId).info().status;
     assertThat(status).isEqualTo(ChangeStatus.MERGED);
@@ -546,17 +532,18 @@
 
   @Test
   public void recursiveSubmodules() throws Exception {
-    TestRepository<?> topRepo = createProjectWithPush("top-project");
-    TestRepository<?> midRepo = createProjectWithPush("mid-project");
-    TestRepository<?> bottomRepo = createProjectWithPush("bottom-project");
+    Project.NameKey topKey = createProjectForPush("top-project", null, true, getSubmitType());
+    Project.NameKey midKey = createProjectForPush("mid-project", null, true, getSubmitType());
+    Project.NameKey botKey = createProjectForPush("bottom-project", null, true, getSubmitType());
+    TestRepository<?> topRepo = cloneProject(topKey);
+    TestRepository<?> midRepo = cloneProject(midKey);
+    TestRepository<?> bottomRepo = cloneProject(botKey);
 
-    allowMatchingSubmoduleSubscription(
-        "mid-project", "refs/heads/master", "top-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "bottom-project", "refs/heads/master", "mid-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(midKey, "refs/heads/master", topKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(botKey, "refs/heads/master", midKey, "refs/heads/master");
 
-    createSubmoduleSubscription(topRepo, "master", "mid-project", "master");
-    createSubmoduleSubscription(midRepo, "master", "bottom-project", "master");
+    createSubmoduleSubscription(topRepo, "master", midKey, "master");
+    createSubmoduleSubscription(midRepo, "master", botKey, "master");
 
     ObjectId bottomHead = pushChangeTo(bottomRepo, "refs/for/master", "some message", "same-topic");
     ObjectId topHead = pushChangeTo(topRepo, "refs/for/master", "some message", "same-topic");
@@ -569,27 +556,27 @@
 
     gApi.changes().id(id1).current().submit();
 
-    expectToHaveSubmoduleState(midRepo, "master", "bottom-project", bottomRepo, "master");
-    expectToHaveSubmoduleState(topRepo, "master", "mid-project", midRepo, "master");
+    expectToHaveSubmoduleState(midRepo, "master", botKey, bottomRepo, "master");
+    expectToHaveSubmoduleState(topRepo, "master", midKey, midRepo, "master");
   }
 
   @Test
   public void triangleSubmodules() throws Exception {
-    TestRepository<?> topRepo = createProjectWithPush("top-project");
-    TestRepository<?> midRepo = createProjectWithPush("mid-project");
-    TestRepository<?> bottomRepo = createProjectWithPush("bottom-project");
+    Project.NameKey topKey = createProjectForPush("top-project", null, true, getSubmitType());
+    Project.NameKey midKey = createProjectForPush("mid-project", null, true, getSubmitType());
+    Project.NameKey botKey = createProjectForPush("bottom-project", null, true, getSubmitType());
+    TestRepository<?> topRepo = cloneProject(topKey);
+    TestRepository<?> midRepo = cloneProject(midKey);
+    TestRepository<?> bottomRepo = cloneProject(botKey);
 
-    allowMatchingSubmoduleSubscription(
-        "mid-project", "refs/heads/master", "top-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "bottom-project", "refs/heads/master", "mid-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "bottom-project", "refs/heads/master", "top-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(midKey, "refs/heads/master", topKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(botKey, "refs/heads/master", midKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(botKey, "refs/heads/master", topKey, "refs/heads/master");
 
-    createSubmoduleSubscription(midRepo, "master", "bottom-project", "master");
+    createSubmoduleSubscription(midRepo, "master", botKey, "master");
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "bottom-project", "master");
-    prepareSubmoduleConfigEntry(config, "mid-project", "master");
+    prepareSubmoduleConfigEntry(config, botKey, "master");
+    prepareSubmoduleConfigEntry(config, midKey, "master");
     pushSubmoduleConfig(topRepo, "master", config);
 
     ObjectId bottomHead = pushChangeTo(bottomRepo, "refs/for/master", "some message", "same-topic");
@@ -603,26 +590,26 @@
 
     gApi.changes().id(id1).current().submit();
 
-    expectToHaveSubmoduleState(midRepo, "master", "bottom-project", bottomRepo, "master");
-    expectToHaveSubmoduleState(topRepo, "master", "mid-project", midRepo, "master");
-    expectToHaveSubmoduleState(topRepo, "master", "bottom-project", bottomRepo, "master");
+    expectToHaveSubmoduleState(midRepo, "master", botKey, bottomRepo, "master");
+    expectToHaveSubmoduleState(topRepo, "master", midKey, midRepo, "master");
+    expectToHaveSubmoduleState(topRepo, "master", botKey, bottomRepo, "master");
   }
 
   private String prepareBranchCircularSubscription() throws Exception {
-    TestRepository<?> topRepo = createProjectWithPush("top-project");
-    TestRepository<?> midRepo = createProjectWithPush("mid-project");
-    TestRepository<?> bottomRepo = createProjectWithPush("bottom-project");
+    Project.NameKey topKey = createProjectForPush("top-project", null, true, getSubmitType());
+    Project.NameKey midKey = createProjectForPush("mid-project", null, true, getSubmitType());
+    Project.NameKey botKey = createProjectForPush("bottom-project", null, true, getSubmitType());
+    TestRepository<?> topRepo = cloneProject(topKey);
+    TestRepository<?> midRepo = cloneProject(midKey);
+    TestRepository<?> bottomRepo = cloneProject(botKey);
 
-    createSubmoduleSubscription(midRepo, "master", "bottom-project", "master");
-    createSubmoduleSubscription(topRepo, "master", "mid-project", "master");
-    createSubmoduleSubscription(bottomRepo, "master", "top-project", "master");
+    createSubmoduleSubscription(midRepo, "master", botKey, "master");
+    createSubmoduleSubscription(topRepo, "master", midKey, "master");
+    createSubmoduleSubscription(bottomRepo, "master", topKey, "master");
 
-    allowMatchingSubmoduleSubscription(
-        "bottom-project", "refs/heads/master", "mid-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "mid-project", "refs/heads/master", "top-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "top-project", "refs/heads/master", "bottom-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(botKey, "refs/heads/master", midKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(midKey, "refs/heads/master", topKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(topKey, "refs/heads/master", botKey, "refs/heads/master");
 
     ObjectId bottomMasterHead = pushChangeTo(bottomRepo, "refs/for/master", "some message", "");
     String changeId = getChangeId(bottomRepo, bottomMasterHead).get();
@@ -649,19 +636,14 @@
 
   @Test
   public void projectCircularSubscriptionWholeTopic() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> subRepo = createProjectWithPush("subscribed-to-project");
-
-    allowMatchingSubmoduleSubscription(
-        "subscribed-to-project", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "super-project", "refs/heads/dev", "subscribed-to-project", "refs/heads/dev");
+    allowMatchingSubmoduleSubscription(subKey, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(superKey, "refs/heads/dev", subKey, "refs/heads/dev");
 
     pushChangeTo(subRepo, "dev");
     pushChangeTo(superRepo, "dev");
 
-    createSubmoduleSubscription(superRepo, "master", "subscribed-to-project", "master");
-    createSubmoduleSubscription(subRepo, "dev", "super-project", "dev");
+    createSubmoduleSubscription(superRepo, "master", subKey, "master");
+    createSubmoduleSubscription(subRepo, "dev", superKey, "dev");
 
     ObjectId subMasterHead =
         pushChangeTo(
@@ -672,15 +654,15 @@
     approve(getChangeId(superRepo, superDevHead).get());
 
     exception.expectMessage("Project level circular subscriptions detected");
-    exception.expectMessage("subscribed-to-project");
-    exception.expectMessage("super-project");
+    exception.expectMessage(subKey.get());
+    exception.expectMessage(superKey.get());
     gApi.changes().id(getChangeId(subRepo, subMasterHead).get()).current().submit();
   }
 
   @Test
   public void projectNoSubscriptionWholeTopic() throws Exception {
-    TestRepository<?> repoA = createProjectWithPush("project-a");
-    TestRepository<?> repoB = createProjectWithPush("project-b");
+    TestRepository<?> repoA = createProjectWithPush("project-a", null, true, getSubmitType());
+    TestRepository<?> repoB = createProjectWithPush("project-b", null, true, getSubmitType());
     // bootstrap the dev branch
     ObjectId a0 = pushChangeTo(repoA, "dev");
 
@@ -747,8 +729,8 @@
 
   @Test
   public void twoProjectsMultipleBranchesWholeTopic() throws Exception {
-    TestRepository<?> repoA = createProjectWithPush("project-a");
-    TestRepository<?> repoB = createProjectWithPush("project-b");
+    TestRepository<?> repoA = createProjectWithPush("project-a", null, true, getSubmitType());
+    TestRepository<?> repoB = createProjectWithPush("project-b", null, true, getSubmitType());
     // bootstrap the dev branch
     pushChangeTo(repoA, "dev");
 
@@ -796,18 +778,17 @@
   public void retrySubmitAfterTornTopicOnLockFailure() throws Exception {
     assume().that(notesMigration.disableChangeReviewDb()).isTrue();
 
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub1 = createProjectWithPush("sub1");
-    TestRepository<?> sub2 = createProjectWithPush("sub2");
+    Project.NameKey subKey1 = createProjectForPush("sub1", null, true, getSubmitType());
+    TestRepository<?> sub1 = cloneProject(subKey1);
+    Project.NameKey subKey2 = createProjectForPush("sub2", null, true, getSubmitType());
+    TestRepository<?> sub2 = cloneProject(subKey2);
 
-    allowMatchingSubmoduleSubscription(
-        "sub1", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "sub2", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey1, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey2, "refs/heads/master", superKey, "refs/heads/master");
 
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "sub1", "master");
-    prepareSubmoduleConfigEntry(config, "sub2", "master");
+    prepareSubmoduleConfigEntry(config, subKey1, "master");
+    prepareSubmoduleConfigEntry(config, subKey2, "master");
     pushSubmoduleConfig(superRepo, "master", config);
 
     ObjectId superPreviousId = pushChangeTo(superRepo, "master");
@@ -837,20 +818,20 @@
 
     sub1.git().fetch().call();
     RevWalk rw1 = sub1.getRevWalk();
-    RevCommit master1 = rw1.parseCommit(getRemoteHead(name("sub1"), "master"));
+    RevCommit master1 = rw1.parseCommit(getRemoteHead(subKey1.get(), "master"));
     RevCommit change1Ps = parseCurrentRevision(rw1, changeId1);
     assertThat(rw1.isMergedInto(change1Ps, master1)).isTrue();
 
     sub2.git().fetch().call();
     RevWalk rw2 = sub2.getRevWalk();
-    RevCommit master2 = rw2.parseCommit(getRemoteHead(name("sub2"), "master"));
+    RevCommit master2 = rw2.parseCommit(getRemoteHead(subKey2.get(), "master"));
     RevCommit change2Ps = parseCurrentRevision(rw2, changeId2);
     assertThat(rw2.isMergedInto(change2Ps, master2)).isTrue();
 
     assertThat(input.generateLockFailures).containsExactly(false);
 
-    expectToHaveSubmoduleState(superRepo, "master", "sub1", sub1, "master");
-    expectToHaveSubmoduleState(superRepo, "master", "sub2", sub2, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey1, sub1, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey2, sub2, "master");
 
     assertWithMessage("submodule subscription update should have made one commit")
         .that(superRepo.getRepository().resolve("origin/master^"))
@@ -859,24 +840,23 @@
 
   @Test
   public void skipUpdatingBrokenGitlinkPointer() throws Exception {
-    TestRepository<?> superRepo = createProjectWithPush("super-project");
-    TestRepository<?> sub1 = createProjectWithPush("sub1");
-    TestRepository<?> sub2 = createProjectWithPush("sub2");
+    Project.NameKey subKey1 = createProjectForPush("sub1", null, true, getSubmitType());
+    TestRepository<?> sub1 = cloneProject(subKey1);
+    Project.NameKey subKey2 = createProjectForPush("sub2", null, true, getSubmitType());
+    TestRepository<?> sub2 = cloneProject(subKey2);
 
-    allowMatchingSubmoduleSubscription(
-        "sub1", "refs/heads/master", "super-project", "refs/heads/master");
-    allowMatchingSubmoduleSubscription(
-        "sub2", "refs/heads/master", "super-project", "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey1, "refs/heads/master", superKey, "refs/heads/master");
+    allowMatchingSubmoduleSubscription(subKey2, "refs/heads/master", superKey, "refs/heads/master");
 
     Config config = new Config();
-    prepareSubmoduleConfigEntry(config, "sub1", "master");
-    prepareSubmoduleConfigEntry(config, "sub2", "master");
+    prepareSubmoduleConfigEntry(config, subKey1, "master");
+    prepareSubmoduleConfigEntry(config, subKey2, "master");
     pushSubmoduleConfig(superRepo, "master", config);
 
     // Write an invalid SHA-1 directly to one of the gitlinks.
     ObjectId badId = ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef");
-    directUpdateSubmodule("super-project", "refs/heads/master", "sub1", badId);
-    expectToHaveSubmoduleState(superRepo, "master", "sub1", badId);
+    directUpdateSubmodule(superKey, "refs/heads/master", subKey1, badId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey1, badId);
 
     String topic = "same-topic";
     ObjectId sub1Id = pushChangeTo(sub1, "refs/for/master", "some message", topic);
@@ -893,7 +873,7 @@
     assertThat(info(changeId2).status).isEqualTo(ChangeStatus.MERGED);
 
     // sub1 was skipped but sub2 succeeded.
-    expectToHaveSubmoduleState(superRepo, "master", "sub1", badId);
-    expectToHaveSubmoduleState(superRepo, "master", "sub2", sub2, "master");
+    expectToHaveSubmoduleState(superRepo, "master", subKey1, badId);
+    expectToHaveSubmoduleState(superRepo, "master", subKey2, sub2, "master");
   }
 }