Make TestGroupBackend usable by other tests

Extract TestGroupBackend from Schema_166_to_167_WithGroupsInReviewDbTest
to its own module, so that it can be used in other tests.

Add a test to validate the behavior of the test backend.

Change-Id: I83a97ac53366cbd8a9a82f40d79df1d6f98cb7e9
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index 76b75b3a..acd5130a 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -73,6 +73,7 @@
         "//java/com/google/gerrit/pgm:daemon",
         "//java/com/google/gerrit/pgm/http/jetty",
         "//java/com/google/gerrit/pgm/util",
+        "//java/com/google/gerrit/server/group/testing",
         "//java/com/google/gerrit/server/project/testing:project-test-util",
         "//java/com/google/gerrit/testing:gerrit-test-util",
         "//lib:jimfs",
diff --git a/java/com/google/gerrit/server/group/testing/BUILD b/java/com/google/gerrit/server/group/testing/BUILD
index bde140b..134de78 100644
--- a/java/com/google/gerrit/server/group/testing/BUILD
+++ b/java/com/google/gerrit/server/group/testing/BUILD
@@ -5,6 +5,7 @@
     testonly = 1,
     srcs = glob(["*.java"]),
     deps = [
+        "//java/com/google/gerrit/common:server",
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
         "//lib:truth",
diff --git a/java/com/google/gerrit/server/group/testing/TestGroupBackend.java b/java/com/google/gerrit/server/group/testing/TestGroupBackend.java
new file mode 100644
index 0000000..c0efe2b
--- /dev/null
+++ b/java/com/google/gerrit/server/group/testing/TestGroupBackend.java
@@ -0,0 +1,123 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.group.testing;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.data.GroupDescription;
+import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.account.GroupMembership;
+import com.google.gerrit.server.project.ProjectState;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/** Implementation of GroupBackend for tests. */
+public class TestGroupBackend implements GroupBackend {
+  private static final String PREFIX = "testbackend:";
+
+  private final Map<AccountGroup.UUID, GroupDescription.Basic> groups = new HashMap<>();
+
+  /**
+   * Create a group by name.
+   *
+   * @param name the group name, optionally prefixed by "testbackend:".
+   * @return the created group
+   */
+  public GroupDescription.Basic create(String name) {
+    checkNotNull(name);
+    return create(new AccountGroup.UUID(name.startsWith(PREFIX) ? name : PREFIX + name));
+  }
+
+  /**
+   * Create a group by UUID.
+   *
+   * @param uuid the group UUID to add.
+   * @return the created group
+   */
+  public GroupDescription.Basic create(AccountGroup.UUID uuid) {
+    checkState(uuid.get().startsWith(PREFIX), "test group UUID must have prefix '" + PREFIX + "'");
+    if (groups.containsKey(uuid)) {
+      return groups.get(uuid);
+    }
+    GroupDescription.Basic group =
+        new GroupDescription.Basic() {
+          @Override
+          public AccountGroup.UUID getGroupUUID() {
+            return uuid;
+          }
+
+          @Override
+          public String getName() {
+            return uuid.get().substring(PREFIX.length());
+          }
+
+          @Override
+          public String getEmailAddress() {
+            return null;
+          }
+
+          @Override
+          public String getUrl() {
+            return null;
+          }
+        };
+    groups.put(uuid, group);
+    return group;
+  }
+
+  /**
+   * Remove a group. No-op if the group does not exist.
+   *
+   * @param uuid the group.
+   */
+  public void remove(AccountGroup.UUID uuid) {
+    groups.remove(uuid);
+  }
+
+  @Override
+  public boolean handles(AccountGroup.UUID uuid) {
+    if (uuid != null) {
+      String id = uuid.get();
+      return id != null && id.startsWith(PREFIX);
+    }
+    return false;
+  }
+
+  @Override
+  public GroupDescription.Basic get(AccountGroup.UUID uuid) {
+    return uuid == null ? null : groups.get(uuid);
+  }
+
+  @Override
+  public Collection<GroupReference> suggest(String name, ProjectState project) {
+    return ImmutableList.of();
+  }
+
+  @Override
+  public GroupMembership membershipsOf(IdentifiedUser user) {
+    return GroupMembership.EMPTY;
+  }
+
+  @Override
+  public boolean isVisibleToAll(AccountGroup.UUID uuid) {
+    return false;
+  }
+}
diff --git a/javatests/com/google/gerrit/acceptance/TestGroupBackendTest.java b/javatests/com/google/gerrit/acceptance/TestGroupBackendTest.java
new file mode 100644
index 0000000..f89baa5
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/TestGroupBackendTest.java
@@ -0,0 +1,70 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.acceptance;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.account.UniversalGroupBackend;
+import com.google.gerrit.server.group.testing.TestGroupBackend;
+import com.google.inject.Inject;
+import org.junit.Test;
+
+public class TestGroupBackendTest extends AbstractDaemonTest {
+  @Inject private DynamicSet<GroupBackend> groupBackends;
+  @Inject private UniversalGroupBackend universalGroupBackend;
+
+  private final TestGroupBackend testGroupBackend = new TestGroupBackend();
+  private final AccountGroup.UUID testUUID = new AccountGroup.UUID("testbackend:test");
+
+  @Test
+  public void handlesTestGroup() throws Exception {
+    assertThat(testGroupBackend.handles(testUUID)).isTrue();
+  }
+
+  @Test
+  public void universalGroupBackendHandlesTestGroup() throws Exception {
+    groupBackends.add(testGroupBackend);
+    assertThat(universalGroupBackend.handles(testUUID)).isTrue();
+  }
+
+  @Test
+  public void doesNotHandleLDAP() throws Exception {
+    assertThat(testGroupBackend.handles(new AccountGroup.UUID("ldap:1234"))).isFalse();
+  }
+
+  @Test
+  public void doesNotHandleNull() throws Exception {
+    assertThat(testGroupBackend.handles(null)).isFalse();
+  }
+
+  @Test
+  public void returnsNullWhenGroupDoesNotExist() throws Exception {
+    assertThat(testGroupBackend.get(testUUID)).isNull();
+  }
+
+  @Test
+  public void returnsNullForNullGroup() throws Exception {
+    assertThat(testGroupBackend.get(null)).isNull();
+  }
+
+  @Test
+  public void returnsKnownGroup() throws Exception {
+    testGroupBackend.create(testUUID);
+    assertThat(testGroupBackend.get(testUUID)).isNotNull();
+  }
+}
diff --git a/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java b/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
index 9cd57e0..6020325 100644
--- a/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
+++ b/javatests/com/google/gerrit/server/schema/Schema_166_to_167_WithGroupsInReviewDbTest.java
@@ -23,10 +23,7 @@
 import static com.google.gerrit.truth.OptionalSubject.assertThat;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.gerrit.common.TimeUtil;
-import com.google.gerrit.common.data.GroupDescription;
-import com.google.gerrit.common.data.GroupDescription.Basic;
 import com.google.gerrit.common.data.GroupReference;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.api.accounts.AccountInput;
@@ -52,7 +49,6 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.account.GroupBackend;
-import com.google.gerrit.server.account.GroupMembership;
 import com.google.gerrit.server.account.GroupUUID;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.config.GerritServerId;
@@ -65,7 +61,7 @@
 import com.google.gerrit.server.group.db.GroupNameNotes;
 import com.google.gerrit.server.group.db.GroupsConsistencyChecker;
 import com.google.gerrit.server.group.testing.InternalGroupSubject;
-import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.group.testing.TestGroupBackend;
 import com.google.gerrit.testing.InMemoryTestEnvironment;
 import com.google.gerrit.testing.TestTimeUtil;
 import com.google.gerrit.testing.TestTimeUtil.TempClockStep;
@@ -84,11 +80,9 @@
 import java.time.ZoneOffset;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
@@ -591,9 +585,9 @@
   public void logFormatWithExternalGroup() throws Exception {
     AccountGroup group = createInReviewDb("group");
 
-    backends.add(new TestGroupBackend());
-    AccountGroup.UUID subgroupUuid = TestGroupBackend.createUuuid("foo");
-
+    TestGroupBackend testGroupBackend = new TestGroupBackend();
+    backends.add(testGroupBackend);
+    AccountGroup.UUID subgroupUuid = testGroupBackend.create("test").getGroupUUID();
     assertThat(groupBackend.handles(subgroupUuid)).isTrue();
     addSubgroupsInReviewDb(group.getId(), subgroupUuid);
 
@@ -637,10 +631,10 @@
             "Update group\n"
                 + "\n"
                 + "Add-group: "
-                + TestGroupBackend.PREFIX
-                + "foo <"
-                + TestGroupBackend.PREFIX
-                + "foo>");
+                + subgroupUuid.get()
+                + " <"
+                + subgroupUuid.get()
+                + ">");
     assertThat(log.get(2)).author().name().isEqualTo(currentUser.getName());
     assertThat(log.get(2)).author().email().isEqualTo(currentUser.getAccountId() + "@" + serverId);
     assertThat(log.get(2)).committer().hasSameDateAs(log.get(2).author);
@@ -1128,77 +1122,4 @@
     groupInfo.options.visibleToAll = group.isVisibleToAll() ? true : null;
     return groupInfo;
   }
-
-  private static class TestGroupBackend implements GroupBackend {
-    static final String PREFIX = "testbackend:";
-
-    static AccountGroup.UUID createUuuid(String name) {
-      return new AccountGroup.UUID(PREFIX + name);
-    }
-
-    @Override
-    public Collection<GroupReference> suggest(String name, ProjectState project) {
-      return ImmutableSet.of();
-    }
-
-    @Override
-    public GroupMembership membershipsOf(IdentifiedUser user) {
-      return new GroupMembership() {
-        @Override
-        public Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> groupIds) {
-          return ImmutableSet.of();
-        }
-
-        @Override
-        public Set<AccountGroup.UUID> getKnownGroups() {
-          return ImmutableSet.of();
-        }
-
-        @Override
-        public boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds) {
-          return false;
-        }
-
-        @Override
-        public boolean contains(AccountGroup.UUID groupId) {
-          return false;
-        }
-      };
-    }
-
-    @Override
-    public boolean isVisibleToAll(AccountGroup.UUID uuid) {
-      return false;
-    }
-
-    @Override
-    public boolean handles(AccountGroup.UUID uuid) {
-      return uuid.get().startsWith(PREFIX);
-    }
-
-    @Override
-    public Basic get(AccountGroup.UUID uuid) {
-      return new GroupDescription.Basic() {
-        @Override
-        public AccountGroup.UUID getGroupUUID() {
-          return uuid;
-        }
-
-        @Override
-        public String getName() {
-          return uuid.get().substring(PREFIX.length());
-        }
-
-        @Override
-        public String getEmailAddress() {
-          return null;
-        }
-
-        @Override
-        public String getUrl() {
-          return null;
-        }
-      };
-    }
-  }
 }