Merge changes I793ca9ff,I57d89795,I7064b198
* changes:
Support request tracing for REST calls by setting a header in the request
TraceIT: Remove redundant asertions for trace ID
TraceIT: Check that correct trace ID is returned as X_GERRIT_TRACE header
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 1d87880..69d603f 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -1487,12 +1487,7 @@
assertNotifyTo(expected.email, expected.fullName);
}
- protected void assertNotifyTo(
- com.google.gerrit.acceptance.testsuite.account.TestAccount expected) {
- assertNotifyTo(expected.preferredEmail().orElse(null), expected.fullname().orElse(null));
- }
-
- private void assertNotifyTo(String expectedEmail, String expectedFullname) {
+ protected void assertNotifyTo(String expectedEmail, String expectedFullname) {
Address expectedAddress = new Address(expectedFullname, expectedEmail);
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
@@ -1506,11 +1501,6 @@
assertNotifyCc(expected.emailAddress);
}
- protected void assertNotifyCc(
- com.google.gerrit.acceptance.testsuite.account.TestAccount expected) {
- assertNotifyCc(expected.preferredEmail().orElse(null), expected.fullname().orElse(null));
- }
-
protected void assertNotifyCc(String expectedEmail, String expectedFullname) {
Address expectedAddress = new Address(expectedFullname, expectedEmail);
assertNotifyCc(expectedAddress);
@@ -1533,13 +1523,10 @@
assertThat(m.headers().get("Cc").isEmpty()).isTrue();
}
- protected void assertNotifyBcc(
- com.google.gerrit.acceptance.testsuite.account.TestAccount expected) {
+ protected void assertNotifyBcc(String expectedEmail, String expectedFullName) {
assertThat(sender.getMessages()).hasSize(1);
Message m = sender.getMessages().get(0);
- assertThat(m.rcpt())
- .containsExactly(
- new Address(expected.fullname().orElse(null), expected.preferredEmail().orElse(null)));
+ assertThat(m.rcpt()).containsExactly(new Address(expectedFullName, expectedEmail));
assertThat(m.headers().get("To").isEmpty()).isTrue();
assertThat(m.headers().get("Cc").isEmpty()).isTrue();
}
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index 6e5424c..582c7cb 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -24,6 +24,8 @@
import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.account.AccountOperationsImpl;
+import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
+import com.google.gerrit.acceptance.testsuite.group.GroupOperationsImpl;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.lucene.LuceneIndexModule;
@@ -441,6 +443,7 @@
bindConstant().annotatedWith(SshEnabled.class).to(daemon.getEnableSshd());
bind(AccountCreator.class);
bind(AccountOperations.class).to(AccountOperationsImpl.class);
+ bind(GroupOperations.class).to(GroupOperationsImpl.class);
factory(PushOneCommit.Factory.class);
install(InProcessProtocol.module());
install(new NoSshModule());
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperations.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperations.java
index 58a00d0..61b7599 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperations.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperations.java
@@ -42,7 +42,7 @@
* <p>Example:
*
* <pre>
- * TestAccount createdAccount = accountOperations
+ * Account.Id createdAccountId = accountOperations
* .newAccount()
* .username("janedoe")
* .preferredEmail("janedoe@example.com")
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
index 94b511b..ebbcfe4 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
@@ -59,12 +59,12 @@
return TestAccountCreation.builder(this::createAccount);
}
- private TestAccount createAccount(TestAccountCreation accountCreation) throws Exception {
+ private Account.Id createAccount(TestAccountCreation accountCreation) throws Exception {
AccountsUpdate.AccountUpdater accountUpdater =
(account, updateBuilder) ->
fillBuilder(updateBuilder, accountCreation, account.getAccount().getId());
AccountState createdAccount = createAccount(accountUpdater);
- return toTestAccount(createdAccount);
+ return createdAccount.getAccount().getId();
}
private AccountState createAccount(AccountsUpdate.AccountUpdater accountUpdater)
@@ -85,17 +85,6 @@
accountCreation.active().ifPresent(builder::setActive);
}
- private static TestAccount toTestAccount(AccountState accountState) {
- Account createdAccount = accountState.getAccount();
- return TestAccount.builder()
- .accountId(createdAccount.getId())
- .preferredEmail(Optional.ofNullable(createdAccount.getPreferredEmail()))
- .fullname(Optional.ofNullable(createdAccount.getFullName()))
- .username(accountState.getUserName())
- .active(accountState.getAccount().isActive())
- .build();
- }
-
private static InternalAccountUpdate.Builder setPreferredEmail(
InternalAccountUpdate.Builder builder, Account.Id accountId, String preferredEmail) {
return builder
@@ -133,6 +122,17 @@
return toTestAccount(account);
}
+ private TestAccount toTestAccount(AccountState accountState) {
+ Account account = accountState.getAccount();
+ return TestAccount.builder()
+ .accountId(account.getId())
+ .preferredEmail(Optional.ofNullable(account.getPreferredEmail()))
+ .fullname(Optional.ofNullable(account.getFullName()))
+ .username(accountState.getUserName())
+ .active(accountState.getAccount().isActive())
+ .build();
+ }
+
@Override
public TestAccountUpdate.Builder forUpdate() {
return TestAccountUpdate.builder(this::updateAccount);
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/TestAccountCreation.java b/java/com/google/gerrit/acceptance/testsuite/account/TestAccountCreation.java
index a82d180..ab32409 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/TestAccountCreation.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/TestAccountCreation.java
@@ -16,6 +16,7 @@
import com.google.auto.value.AutoValue;
import com.google.gerrit.acceptance.testsuite.ThrowingFunction;
+import com.google.gerrit.reviewdb.client.Account;
import java.util.Optional;
@AutoValue
@@ -32,9 +33,9 @@
public abstract Optional<Boolean> active();
- abstract ThrowingFunction<TestAccountCreation, TestAccount> accountCreator();
+ abstract ThrowingFunction<TestAccountCreation, Account.Id> accountCreator();
- public static Builder builder(ThrowingFunction<TestAccountCreation, TestAccount> accountCreator) {
+ public static Builder builder(ThrowingFunction<TestAccountCreation, Account.Id> accountCreator) {
return new AutoValue_TestAccountCreation.Builder()
.accountCreator(accountCreator)
.httpPassword("http-pass");
@@ -83,11 +84,11 @@
}
abstract Builder accountCreator(
- ThrowingFunction<TestAccountCreation, TestAccount> accountCreator);
+ ThrowingFunction<TestAccountCreation, Account.Id> accountCreator);
abstract TestAccountCreation autoBuild();
- public TestAccount create() throws Exception {
+ public Account.Id create() throws Exception {
TestAccountCreation accountUpdate = autoBuild();
return accountUpdate.accountCreator().apply(accountUpdate);
}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/GroupOperations.java b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperations.java
new file mode 100644
index 0000000..f75ca2e
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperations.java
@@ -0,0 +1,97 @@
+// 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.testsuite.group;
+
+import com.google.gerrit.reviewdb.client.AccountGroup;
+
+/**
+ * An aggregation of operations on groups for test purposes.
+ *
+ * <p>To execute the operations, no Gerrit permissions are necessary.
+ *
+ * <p><strong>Note:</strong> This interface is not implemented using the REST or extension API.
+ * Hence, it cannot be used for testing those APIs.
+ */
+public interface GroupOperations {
+ /**
+ * Starts the fluent chain for querying or modifying a group. Please see the methods of {@link
+ * MoreGroupOperations} for details on possible operations.
+ *
+ * @return an aggregation of operations on a specific group
+ */
+ MoreGroupOperations group(AccountGroup.UUID groupUuid);
+
+ /**
+ * Starts the fluent chain to create a group. The returned builder can be used to specify the
+ * attributes of the new group. To create the group for real, {@link
+ * TestGroupCreation.Builder#create()} must be called.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * AccountGroup.UUID createdGroupUuid = groupOperations
+ * .newGroup()
+ * .name("verifiers")
+ * .description("All verifiers of this server")
+ * .create();
+ * </pre>
+ *
+ * <p><strong>Note:</strong> If another group with the provided name already exists, the creation
+ * of the group will fail.
+ *
+ * @return a builder to create the new group
+ */
+ TestGroupCreation.Builder newGroup();
+
+ /** An aggregation of methods on a specific group. */
+ interface MoreGroupOperations {
+
+ /**
+ * Checks whether the group exists.
+ *
+ * @return {@code true} if the group exists
+ */
+ boolean exists() throws Exception;
+
+ /**
+ * Retrieves the group.
+ *
+ * <p><strong>Note:</strong> This call will fail with an exception if the requested group
+ * doesn't exist. If you want to check for the existence of a group, use {@link #exists()}
+ * instead.
+ *
+ * @return the corresponding {@code TestGroup}
+ */
+ TestGroup get() throws Exception;
+
+ /**
+ * Starts the fluent chain to update a group. The returned builder can be used to specify how
+ * the attributes of the group should be modified. To update the group for real, {@link
+ * TestGroupUpdate.Builder#update()} must be called.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * groupOperations.forUpdate().description("Another description for this group").update();
+ * </pre>
+ *
+ * <p><strong>Note:</strong> The update will fail with an exception if the group to update
+ * doesn't exist. If you want to check for the existence of a group, use {@link #exists()}.
+ *
+ * @return a builder to update the group
+ */
+ TestGroupUpdate.Builder forUpdate();
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java
new file mode 100644
index 0000000..f9769c5
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImpl.java
@@ -0,0 +1,159 @@
+// 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.testsuite.group;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.gerrit.common.errors.NoSuchGroupException;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.gerrit.server.GerritPersonIdent;
+import com.google.gerrit.server.Sequences;
+import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.GroupUUID;
+import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.group.db.Groups;
+import com.google.gerrit.server.group.db.GroupsUpdate;
+import com.google.gerrit.server.group.db.InternalGroupCreation;
+import com.google.gerrit.server.group.db.InternalGroupUpdate;
+import com.google.gwtorm.server.OrmDuplicateKeyException;
+import com.google.gwtorm.server.OrmException;
+import com.google.inject.Inject;
+import java.io.IOException;
+import java.util.Optional;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.PersonIdent;
+
+/**
+ * The implementation of {@code GroupOperations}.
+ *
+ * <p>There is only one implementation of {@code GroupOperations}. Nevertheless, we keep the
+ * separation between interface and implementation to enhance clarity.
+ */
+public class GroupOperationsImpl implements GroupOperations {
+ private final Groups groups;
+ private final GroupsUpdate groupsUpdate;
+ private final Sequences seq;
+ private final PersonIdent serverIdent;
+
+ @Inject
+ public GroupOperationsImpl(
+ Groups groups,
+ @ServerInitiated GroupsUpdate groupsUpdate,
+ Sequences seq,
+ @GerritPersonIdent PersonIdent serverIdent) {
+ this.groups = groups;
+ this.groupsUpdate = groupsUpdate;
+ this.seq = seq;
+ this.serverIdent = serverIdent;
+ }
+
+ @Override
+ public MoreGroupOperations group(AccountGroup.UUID groupUuid) {
+ return new MoreGroupOperationsImpl(groupUuid);
+ }
+
+ @Override
+ public TestGroupCreation.Builder newGroup() {
+ return TestGroupCreation.builder(this::createNewGroup);
+ }
+
+ private AccountGroup.UUID createNewGroup(TestGroupCreation groupCreation)
+ throws ConfigInvalidException, IOException, OrmException {
+ InternalGroupCreation internalGroupCreation = toInternalGroupCreation(groupCreation);
+ InternalGroupUpdate internalGroupUpdate = toInternalGroupUpdate(groupCreation);
+ InternalGroup internalGroup =
+ groupsUpdate.createGroup(internalGroupCreation, internalGroupUpdate);
+ return internalGroup.getGroupUUID();
+ }
+
+ private InternalGroupCreation toInternalGroupCreation(TestGroupCreation groupCreation)
+ throws OrmException {
+ AccountGroup.Id groupId = new AccountGroup.Id(seq.nextGroupId());
+ String groupName = groupCreation.name().orElse("group-with-id-" + groupId.get());
+ AccountGroup.UUID groupUuid = GroupUUID.make(groupName, serverIdent);
+ AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName);
+ return InternalGroupCreation.builder()
+ .setId(groupId)
+ .setGroupUUID(groupUuid)
+ .setNameKey(nameKey)
+ .build();
+ }
+
+ private static InternalGroupUpdate toInternalGroupUpdate(TestGroupCreation groupCreation) {
+ InternalGroupUpdate.Builder builder = InternalGroupUpdate.builder();
+ groupCreation.description().ifPresent(builder::setDescription);
+ groupCreation.ownerGroupUuid().ifPresent(builder::setOwnerGroupUUID);
+ groupCreation.visibleToAll().ifPresent(builder::setVisibleToAll);
+ builder.setMemberModification(originalMembers -> groupCreation.members());
+ builder.setSubgroupModification(originalSubgroups -> groupCreation.subgroups());
+ return builder.build();
+ }
+
+ private class MoreGroupOperationsImpl implements MoreGroupOperations {
+ private final AccountGroup.UUID groupUuid;
+
+ MoreGroupOperationsImpl(AccountGroup.UUID groupUuid) {
+ this.groupUuid = groupUuid;
+ }
+
+ @Override
+ public boolean exists() throws Exception {
+ return groups.getGroup(groupUuid).isPresent();
+ }
+
+ @Override
+ public TestGroup get() throws Exception {
+ Optional<InternalGroup> group = groups.getGroup(groupUuid);
+ checkState(group.isPresent(), "Tried to get non-existing test group");
+ return toTestGroup(group.get());
+ }
+
+ private TestGroup toTestGroup(InternalGroup internalGroup) {
+ return TestGroup.builder()
+ .groupUuid(internalGroup.getGroupUUID())
+ .groupId(internalGroup.getId())
+ .nameKey(internalGroup.getNameKey())
+ .description(Optional.ofNullable(internalGroup.getDescription()))
+ .ownerGroupUuid(internalGroup.getOwnerGroupUUID())
+ .visibleToAll(internalGroup.isVisibleToAll())
+ .createdOn(internalGroup.getCreatedOn())
+ .members(internalGroup.getMembers())
+ .subgroups(internalGroup.getSubgroups())
+ .build();
+ }
+
+ @Override
+ public TestGroupUpdate.Builder forUpdate() {
+ return TestGroupUpdate.builder(this::updateGroup);
+ }
+
+ private void updateGroup(TestGroupUpdate groupUpdate)
+ throws OrmDuplicateKeyException, NoSuchGroupException, ConfigInvalidException, IOException {
+ InternalGroupUpdate internalGroupUpdate = toInternalGroupUpdate(groupUpdate);
+ groupsUpdate.updateGroup(groupUuid, internalGroupUpdate);
+ }
+
+ private InternalGroupUpdate toInternalGroupUpdate(TestGroupUpdate groupUpdate) {
+ InternalGroupUpdate.Builder builder = InternalGroupUpdate.builder();
+ groupUpdate.name().map(AccountGroup.NameKey::new).ifPresent(builder::setName);
+ groupUpdate.description().ifPresent(builder::setDescription);
+ groupUpdate.ownerGroupUuid().ifPresent(builder::setOwnerGroupUUID);
+ groupUpdate.visibleToAll().ifPresent(builder::setVisibleToAll);
+ builder.setMemberModification(groupUpdate.memberModification()::apply);
+ builder.setSubgroupModification(groupUpdate.subgroupModification()::apply);
+ return builder.build();
+ }
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/TestGroup.java b/java/com/google/gerrit/acceptance/testsuite/group/TestGroup.java
new file mode 100644
index 0000000..b450304
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/group/TestGroup.java
@@ -0,0 +1,78 @@
+// 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.testsuite.group;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import java.sql.Timestamp;
+import java.util.Optional;
+
+@AutoValue
+public abstract class TestGroup {
+
+ public abstract AccountGroup.UUID groupUuid();
+
+ public abstract AccountGroup.Id groupId();
+
+ public String name() {
+ return nameKey().get();
+ }
+
+ public abstract AccountGroup.NameKey nameKey();
+
+ public abstract Optional<String> description();
+
+ public abstract AccountGroup.UUID ownerGroupUuid();
+
+ public abstract boolean visibleToAll();
+
+ public abstract Timestamp createdOn();
+
+ public abstract ImmutableSet<Account.Id> members();
+
+ public abstract ImmutableSet<AccountGroup.UUID> subgroups();
+
+ static Builder builder() {
+ return new AutoValue_TestGroup.Builder();
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+
+ public abstract Builder groupUuid(AccountGroup.UUID groupUuid);
+
+ public abstract Builder groupId(AccountGroup.Id id);
+
+ public abstract Builder nameKey(AccountGroup.NameKey name);
+
+ public abstract Builder description(String description);
+
+ public abstract Builder description(Optional<String> description);
+
+ public abstract Builder ownerGroupUuid(AccountGroup.UUID ownerGroupUuid);
+
+ public abstract Builder visibleToAll(boolean visibleToAll);
+
+ public abstract Builder createdOn(Timestamp createdOn);
+
+ public abstract Builder members(ImmutableSet<Account.Id> members);
+
+ public abstract Builder subgroups(ImmutableSet<AccountGroup.UUID> subgroups);
+
+ abstract TestGroup build();
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/TestGroupCreation.java b/java/com/google/gerrit/acceptance/testsuite/group/TestGroupCreation.java
new file mode 100644
index 0000000..efed720
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/group/TestGroupCreation.java
@@ -0,0 +1,112 @@
+// 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.testsuite.group;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.gerrit.acceptance.testsuite.ThrowingFunction;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import java.util.Optional;
+import java.util.Set;
+
+@AutoValue
+public abstract class TestGroupCreation {
+
+ public abstract Optional<String> name();
+
+ public abstract Optional<String> description();
+
+ public abstract Optional<AccountGroup.UUID> ownerGroupUuid();
+
+ public abstract Optional<Boolean> visibleToAll();
+
+ public abstract ImmutableSet<Account.Id> members();
+
+ public abstract ImmutableSet<AccountGroup.UUID> subgroups();
+
+ abstract ThrowingFunction<TestGroupCreation, AccountGroup.UUID> groupCreator();
+
+ public static Builder builder(
+ ThrowingFunction<TestGroupCreation, AccountGroup.UUID> groupCreator) {
+ return new AutoValue_TestGroupCreation.Builder().groupCreator(groupCreator);
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public abstract Builder name(String name);
+
+ public abstract Builder description(String description);
+
+ public Builder clearDescription() {
+ return description("");
+ }
+
+ public abstract Builder ownerGroupUuid(AccountGroup.UUID ownerGroupUuid);
+
+ public abstract Builder visibleToAll(boolean visibleToAll);
+
+ public Builder clearMembers() {
+ return members(ImmutableSet.of());
+ }
+
+ public Builder members(Account.Id member1, Account.Id... otherMembers) {
+ return members(Sets.union(ImmutableSet.of(member1), ImmutableSet.copyOf(otherMembers)));
+ }
+
+ public abstract Builder members(Set<Account.Id> members);
+
+ abstract ImmutableSet.Builder<Account.Id> membersBuilder();
+
+ public Builder addMember(Account.Id member) {
+ membersBuilder().add(member);
+ return this;
+ }
+
+ public Builder clearSubgroups() {
+ return subgroups(ImmutableSet.of());
+ }
+
+ public Builder subgroups(AccountGroup.UUID subgroup1, AccountGroup.UUID... otherSubgroups) {
+ return subgroups(Sets.union(ImmutableSet.of(subgroup1), ImmutableSet.copyOf(otherSubgroups)));
+ }
+
+ public abstract Builder subgroups(Set<AccountGroup.UUID> subgroups);
+
+ abstract ImmutableSet.Builder<AccountGroup.UUID> subgroupsBuilder();
+
+ public Builder addSubgroup(AccountGroup.UUID subgroup) {
+ subgroupsBuilder().add(subgroup);
+ return this;
+ }
+
+ abstract Builder groupCreator(
+ ThrowingFunction<TestGroupCreation, AccountGroup.UUID> groupCreator);
+
+ abstract TestGroupCreation autoBuild();
+
+ /**
+ * Executes the group creation as specified.
+ *
+ * @return the UUID of the created group
+ */
+ public AccountGroup.UUID create() throws Exception {
+ TestGroupCreation groupCreation = autoBuild();
+ return groupCreation.groupCreator().apply(groupCreation);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/testsuite/group/TestGroupUpdate.java b/java/com/google/gerrit/acceptance/testsuite/group/TestGroupUpdate.java
new file mode 100644
index 0000000..095a270
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/testsuite/group/TestGroupUpdate.java
@@ -0,0 +1,134 @@
+// 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.testsuite.group;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.gerrit.acceptance.testsuite.ThrowingConsumer;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+
+@AutoValue
+public abstract class TestGroupUpdate {
+
+ public abstract Optional<String> name();
+
+ public abstract Optional<String> description();
+
+ public abstract Optional<AccountGroup.UUID> ownerGroupUuid();
+
+ public abstract Optional<Boolean> visibleToAll();
+
+ public abstract Function<ImmutableSet<Account.Id>, Set<Account.Id>> memberModification();
+
+ public abstract Function<ImmutableSet<AccountGroup.UUID>, Set<AccountGroup.UUID>>
+ subgroupModification();
+
+ abstract ThrowingConsumer<TestGroupUpdate> groupUpdater();
+
+ public static Builder builder(ThrowingConsumer<TestGroupUpdate> groupUpdater) {
+ return new AutoValue_TestGroupUpdate.Builder()
+ .groupUpdater(groupUpdater)
+ .memberModification(in -> in)
+ .subgroupModification(in -> in);
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public abstract Builder name(String name);
+
+ public abstract Builder description(String description);
+
+ public Builder clearDescription() {
+ return description("");
+ }
+
+ public abstract Builder ownerGroupUuid(AccountGroup.UUID ownerGroupUUID);
+
+ public abstract Builder visibleToAll(boolean visibleToAll);
+
+ abstract Builder memberModification(
+ Function<ImmutableSet<Account.Id>, Set<Account.Id>> memberModification);
+
+ abstract Function<ImmutableSet<Account.Id>, Set<Account.Id>> memberModification();
+
+ public Builder clearMembers() {
+ return memberModification(originalMembers -> ImmutableSet.of());
+ }
+
+ public Builder addMember(Account.Id member) {
+ Function<ImmutableSet<Account.Id>, Set<Account.Id>> previousModification =
+ memberModification();
+ memberModification(
+ originalMembers ->
+ Sets.union(previousModification.apply(originalMembers), ImmutableSet.of(member)));
+ return this;
+ }
+
+ public Builder removeMember(Account.Id member) {
+ Function<ImmutableSet<Account.Id>, Set<Account.Id>> previousModification =
+ memberModification();
+ memberModification(
+ originalMembers ->
+ Sets.difference(
+ previousModification.apply(originalMembers), ImmutableSet.of(member)));
+ return this;
+ }
+
+ abstract Builder subgroupModification(
+ Function<ImmutableSet<AccountGroup.UUID>, Set<AccountGroup.UUID>> subgroupModification);
+
+ abstract Function<ImmutableSet<AccountGroup.UUID>, Set<AccountGroup.UUID>>
+ subgroupModification();
+
+ public Builder clearSubgroups() {
+ return subgroupModification(originalMembers -> ImmutableSet.of());
+ }
+
+ public Builder addSubgroup(AccountGroup.UUID subgroup) {
+ Function<ImmutableSet<AccountGroup.UUID>, Set<AccountGroup.UUID>> previousModification =
+ subgroupModification();
+ subgroupModification(
+ originalSubgroups ->
+ Sets.union(previousModification.apply(originalSubgroups), ImmutableSet.of(subgroup)));
+ return this;
+ }
+
+ public Builder removeSubgroup(AccountGroup.UUID subgroup) {
+ Function<ImmutableSet<AccountGroup.UUID>, Set<AccountGroup.UUID>> previousModification =
+ subgroupModification();
+ subgroupModification(
+ originalSubgroups ->
+ Sets.difference(
+ previousModification.apply(originalSubgroups), ImmutableSet.of(subgroup)));
+ return this;
+ }
+
+ abstract Builder groupUpdater(ThrowingConsumer<TestGroupUpdate> groupUpdater);
+
+ abstract TestGroupUpdate autoBuild();
+
+ /** Executes the group update as specified. */
+ public void update() throws Exception {
+ TestGroupUpdate groupUpdater = autoBuild();
+ groupUpdater.groupUpdater().accept(groupUpdater);
+ }
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index b362b2b..7126354 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -526,9 +526,9 @@
@Test
public void validateAccountActivation() throws Exception {
- com.google.gerrit.acceptance.testsuite.account.TestAccount activatableAccount =
+ Account.Id activatableAccountId =
accountOperations.newAccount().inactive().preferredEmail("foo@activatable.com").create();
- com.google.gerrit.acceptance.testsuite.account.TestAccount deactivatableAccount =
+ Account.Id deactivatableAccountId =
accountOperations.newAccount().preferredEmail("foo@deactivatable.com").create();
RegistrationHandle registrationHandle =
accountActivationValidationListeners.add(
@@ -554,61 +554,56 @@
/* Test account that can be activated, but not deactivated */
// Deactivate account that is already inactive
try {
- gApi.accounts().id(activatableAccount.accountId().get()).setActive(false);
+ gApi.accounts().id(activatableAccountId.get()).setActive(false);
fail("Expected exception");
} catch (ResourceConflictException e) {
assertThat(e.getMessage()).isEqualTo("account not active");
}
- assertThat(accountOperations.account(activatableAccount.accountId()).get().active())
- .isFalse();
+ assertThat(accountOperations.account(activatableAccountId).get().active()).isFalse();
// Activate account that can be activated
- gApi.accounts().id(activatableAccount.accountId().get()).setActive(true);
- assertThat(accountOperations.account(activatableAccount.accountId()).get().active()).isTrue();
+ gApi.accounts().id(activatableAccountId.get()).setActive(true);
+ assertThat(accountOperations.account(activatableAccountId).get().active()).isTrue();
// Activate account that is already active
- gApi.accounts().id(activatableAccount.accountId().get()).setActive(true);
- assertThat(accountOperations.account(activatableAccount.accountId()).get().active()).isTrue();
+ gApi.accounts().id(activatableAccountId.get()).setActive(true);
+ assertThat(accountOperations.account(activatableAccountId).get().active()).isTrue();
// Try deactivating account that cannot be deactivated
try {
- gApi.accounts().id(activatableAccount.accountId().get()).setActive(false);
+ gApi.accounts().id(activatableAccountId.get()).setActive(false);
fail("Expected exception");
} catch (ResourceConflictException e) {
assertThat(e.getMessage()).isEqualTo("not allowed to deactive account");
}
- assertThat(accountOperations.account(activatableAccount.accountId()).get().active()).isTrue();
+ assertThat(accountOperations.account(activatableAccountId).get().active()).isTrue();
/* Test account that can be deactivated, but not activated */
// Activate account that is already inactive
- gApi.accounts().id(deactivatableAccount.accountId().get()).setActive(true);
- assertThat(accountOperations.account(deactivatableAccount.accountId()).get().active())
- .isTrue();
+ gApi.accounts().id(deactivatableAccountId.get()).setActive(true);
+ assertThat(accountOperations.account(deactivatableAccountId).get().active()).isTrue();
// Deactivate account that can be deactivated
- gApi.accounts().id(deactivatableAccount.accountId().get()).setActive(false);
- assertThat(accountOperations.account(deactivatableAccount.accountId()).get().active())
- .isFalse();
+ gApi.accounts().id(deactivatableAccountId.get()).setActive(false);
+ assertThat(accountOperations.account(deactivatableAccountId).get().active()).isFalse();
// Deactivate account that is already inactive
try {
- gApi.accounts().id(deactivatableAccount.accountId().get()).setActive(false);
+ gApi.accounts().id(deactivatableAccountId.get()).setActive(false);
fail("Expected exception");
} catch (ResourceConflictException e) {
assertThat(e.getMessage()).isEqualTo("account not active");
}
- assertThat(accountOperations.account(deactivatableAccount.accountId()).get().active())
- .isFalse();
+ assertThat(accountOperations.account(deactivatableAccountId).get().active()).isFalse();
// Try activating account that cannot be activated
try {
- gApi.accounts().id(deactivatableAccount.accountId().get()).setActive(true);
+ gApi.accounts().id(deactivatableAccountId.get()).setActive(true);
fail("Expected exception");
} catch (ResourceConflictException e) {
assertThat(e.getMessage()).isEqualTo("not allowed to active account");
}
- assertThat(accountOperations.account(deactivatableAccount.accountId()).get().active())
- .isFalse();
+ assertThat(accountOperations.account(deactivatableAccountId).get().active()).isFalse();
} finally {
registrationHandle.remove();
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index fe55115..b3a5e2d 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -68,7 +68,6 @@
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
-import com.google.gerrit.acceptance.testsuite.account.TestAccount;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.data.LabelFunction;
@@ -1688,7 +1687,7 @@
// create a group named "ab" with one user: testUser
String email = "abcd@test.com";
String fullname = "abcd";
- TestAccount testUser =
+ Account.Id accountIdOfTestUser =
accountOperations
.newAccount()
.username("abcd")
@@ -1721,7 +1720,7 @@
Collection<AccountInfo> reviewers = c.reviewers.get(REVIEWER);
assertThat(reviewers).isNotNull();
assertThat(reviewers).hasSize(1);
- assertThat(reviewers.iterator().next()._accountId).isEqualTo(testUser.accountId().get());
+ assertThat(reviewers.iterator().next()._accountId).isEqualTo(accountIdOfTestUser.get());
// Ensure ETag and lastUpdatedOn are updated.
rsrc = parseResource(r);
@@ -1748,7 +1747,7 @@
String myGroupUserEmail = "lee@test.com";
String myGroupUserFullname = "lee";
- TestAccount myGroupUser =
+ Account.Id accountIdOfGroupUser =
accountOperations
.newAccount()
.username("lee")
@@ -1785,7 +1784,7 @@
Collection<AccountInfo> reviewers = c.reviewers.get(REVIEWER);
assertThat(reviewers).isNotNull();
assertThat(reviewers).hasSize(1);
- assertThat(reviewers.iterator().next()._accountId).isEqualTo(myGroupUser.accountId().get());
+ assertThat(reviewers.iterator().next()._accountId).isEqualTo(accountIdOfGroupUser.get());
// Ensure ETag and lastUpdatedOn are updated.
rsrc = parseResource(r);
@@ -2215,13 +2214,12 @@
// notify unrelated account as TO
String email = "user2@example.com";
- TestAccount user2 =
- accountOperations
- .newAccount()
- .username("user2")
- .preferredEmail(email)
- .fullname("User2")
- .create();
+ accountOperations
+ .newAccount()
+ .username("user2")
+ .preferredEmail(email)
+ .fullname("User2")
+ .create();
setApiUser(user);
recommend(r.getChangeId());
setApiUser(admin);
@@ -2229,7 +2227,7 @@
in.notifyDetails = new HashMap<>();
in.notifyDetails.put(RecipientType.TO, new NotifyInfo(ImmutableList.of(email)));
gApi.changes().id(r.getChangeId()).reviewer(user.getId().toString()).deleteVote(in);
- assertNotifyTo(user2);
+ assertNotifyTo(email, "User2");
// notify unrelated account as CC
setApiUser(user);
@@ -2239,7 +2237,7 @@
in.notifyDetails = new HashMap<>();
in.notifyDetails.put(RecipientType.CC, new NotifyInfo(ImmutableList.of(email)));
gApi.changes().id(r.getChangeId()).reviewer(user.getId().toString()).deleteVote(in);
- assertNotifyCc(user2);
+ assertNotifyCc(email, "User2");
// notify unrelated account as BCC
setApiUser(user);
@@ -2249,7 +2247,7 @@
in.notifyDetails = new HashMap<>();
in.notifyDetails.put(RecipientType.BCC, new NotifyInfo(ImmutableList.of(email)));
gApi.changes().id(r.getChangeId()).reviewer(user.getId().toString()).deleteVote(in);
- assertNotifyBcc(user2);
+ assertNotifyBcc(email, "User2");
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index 8f1bdbc..d6be960 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -183,24 +183,23 @@
@Test
public void cachedGroupsForMemberAreUpdatedOnMemberAdditionAndRemoval() throws Exception {
String username = name("user");
- com.google.gerrit.acceptance.testsuite.account.TestAccount account =
- accountOperations.newAccount().username(username).create();
+ Account.Id accountId = accountOperations.newAccount().username(username).create();
// Fill the cache for the observed account.
- groupIncludeCache.getGroupsWithMember(account.accountId());
+ groupIncludeCache.getGroupsWithMember(accountId);
String groupName = createGroup("users");
AccountGroup.UUID groupUuid = new AccountGroup.UUID(gApi.groups().id(groupName).get().id);
gApi.groups().id(groupName).addMembers(username);
Collection<AccountGroup.UUID> groupsWithMemberAfterAddition =
- groupIncludeCache.getGroupsWithMember(account.accountId());
+ groupIncludeCache.getGroupsWithMember(accountId);
assertThat(groupsWithMemberAfterAddition).contains(groupUuid);
gApi.groups().id(groupName).removeMembers(username);
Collection<AccountGroup.UUID> groupsWithMemberAfterRemoval =
- groupIncludeCache.getGroupsWithMember(account.accountId());
+ groupIncludeCache.getGroupsWithMember(accountId);
assertThat(groupsWithMemberAfterRemoval).doesNotContain(groupUuid);
}
@@ -411,19 +410,17 @@
@Test
public void cachedGroupsForMemberAreUpdatedOnGroupCreation() throws Exception {
- com.google.gerrit.acceptance.testsuite.account.TestAccount account =
- accountOperations.newAccount().create();
+ Account.Id accountId = accountOperations.newAccount().create();
// Fill the cache for the observed account.
- groupIncludeCache.getGroupsWithMember(account.accountId());
+ groupIncludeCache.getGroupsWithMember(accountId);
GroupInput groupInput = new GroupInput();
groupInput.name = name("Users");
- groupInput.members = ImmutableList.of(String.valueOf(account.accountId().get()));
+ groupInput.members = ImmutableList.of(String.valueOf(accountId.get()));
GroupInfo group = gApi.groups().create(groupInput).get();
- Collection<AccountGroup.UUID> groups =
- groupIncludeCache.getGroupsWithMember(account.accountId());
+ Collection<AccountGroup.UUID> groups = groupIncludeCache.getGroupsWithMember(accountId);
assertThat(groups).containsExactly(new AccountGroup.UUID(group.id));
}
diff --git a/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java b/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
index 2b1416a..e4194a3 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/CheckAccessIT.java
@@ -20,16 +20,18 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.extensions.api.config.AccessCheckInfo;
import com.google.gerrit.extensions.api.config.AccessCheckInput;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
-import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.inject.Inject;
import java.util.List;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
@@ -39,35 +41,29 @@
public class CheckAccessIT extends AbstractDaemonTest {
+ @Inject private GroupOperations groupOperations;
+
private Project.NameKey normalProject;
private Project.NameKey secretProject;
private Project.NameKey secretRefProject;
private TestAccount privilegedUser;
- private InternalGroup privilegedGroup;
@Before
public void setUp() throws Exception {
normalProject = createProject("normal");
secretProject = createProject("secret");
secretRefProject = createProject("secretRef");
- privilegedGroup = group(createGroup("privilegedGroup"));
+ AccountGroup.UUID privilegedGroupUuid =
+ groupOperations.newGroup().name(name("privilegedGroup")).create();
privilegedUser = accountCreator.create("privilegedUser", "snowden@nsa.gov", "Ed Snowden");
- gApi.groups().id(privilegedGroup.getGroupUUID().get()).addMembers(privilegedUser.username);
+ groupOperations.group(privilegedGroupUuid).forUpdate().addMember(privilegedUser.id).update();
- assertThat(gApi.groups().id(privilegedGroup.getGroupUUID().get()).members().get(0).email)
- .contains("snowden");
-
- grant(secretProject, "refs/*", Permission.READ, false, privilegedGroup.getGroupUUID());
+ grant(secretProject, "refs/*", Permission.READ, false, privilegedGroupUuid);
block(secretProject, "refs/*", Permission.READ, SystemGroupBackend.REGISTERED_USERS);
deny(secretRefProject, "refs/*", Permission.READ, SystemGroupBackend.ANONYMOUS_USERS);
- grant(
- secretRefProject,
- "refs/heads/secret/*",
- Permission.READ,
- false,
- privilegedGroup.getGroupUUID());
+ grant(secretRefProject, "refs/heads/secret/*", Permission.READ, false, privilegedGroupUuid);
block(
secretRefProject,
"refs/heads/secret/*",
@@ -81,13 +77,8 @@
SystemGroupBackend.REGISTERED_USERS);
// Ref permission
- grant(
- normalProject,
- "refs/*",
- Permission.VIEW_PRIVATE_CHANGES,
- false,
- privilegedGroup.getGroupUUID());
- grant(normalProject, "refs/*", Permission.FORGE_SERVER, false, privilegedGroup.getGroupUUID());
+ grant(normalProject, "refs/*", Permission.VIEW_PRIVATE_CHANGES, false, privilegedGroupUuid);
+ grant(normalProject, "refs/*", Permission.FORGE_SERVER, false, privilegedGroupUuid);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImplTest.java b/javatests/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImplTest.java
new file mode 100644
index 0000000..954b0e6
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/testsuite/group/GroupOperationsImplTest.java
@@ -0,0 +1,656 @@
+// 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.testsuite.group;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth8.assertThat;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.truth.Correspondence;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
+import com.google.gerrit.extensions.api.groups.GroupInput;
+import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.GroupInfo;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import com.google.inject.Inject;
+import java.sql.Timestamp;
+import java.util.Objects;
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class GroupOperationsImplTest extends AbstractDaemonTest {
+
+ @Rule public ExpectedException expectedException = ExpectedException.none();
+
+ @Inject private AccountOperations accountOperations;
+
+ @Inject private GroupOperationsImpl groupOperations;
+
+ private int uniqueGroupNameIndex;
+
+ @Test
+ public void groupCanBeCreatedWithoutSpecifyingAnyParameters() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.id).isEqualTo(groupUuid.get());
+ assertThat(foundGroup.name).isNotEmpty();
+ }
+
+ @Test
+ public void twoGroupsWithoutAnyParametersDoNotClash() throws Exception {
+ AccountGroup.UUID groupUuid1 = groupOperations.newGroup().create();
+ AccountGroup.UUID groupUuid2 = groupOperations.newGroup().create();
+
+ TestGroup group1 = groupOperations.group(groupUuid1).get();
+ TestGroup group2 = groupOperations.group(groupUuid2).get();
+ assertThat(group1.groupUuid()).isNotEqualTo(group2.groupUuid());
+ }
+
+ @Test
+ public void groupCreatedByTestApiCanBeRetrievedViaOfficialApi() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().name("unique group created via test API").create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.id).isEqualTo(groupUuid.get());
+ assertThat(foundGroup.name).isEqualTo("unique group created via test API");
+ }
+
+ @Test
+ public void specifiedNameIsRespectedForGroupCreation() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().name("XYZ-123-this-name-must-be-unique").create();
+
+ GroupInfo group = getGroupFromServer(groupUuid);
+ assertThat(group.name).isEqualTo("XYZ-123-this-name-must-be-unique");
+ }
+
+ @Test
+ public void specifiedDescriptionIsRespectedForGroupCreation() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().description("All authenticated users").create();
+
+ GroupInfo group = getGroupFromServer(groupUuid);
+ assertThat(group.description).isEqualTo("All authenticated users");
+ }
+
+ @Test
+ public void requestingNoDescriptionIsPossibleForGroupCreation() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearDescription().create();
+
+ GroupInfo group = getGroupFromServer(groupUuid);
+ assertThat(group.description).isNull();
+ }
+
+ @Test
+ public void specifiedOwnerIsRespectedForGroupCreation() throws Exception {
+ AccountGroup.UUID ownerGroupUuid = groupOperations.newGroup().create();
+
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().ownerGroupUuid(ownerGroupUuid).create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.ownerId).isEqualTo(ownerGroupUuid.get());
+ }
+
+ @Test
+ public void specifiedVisibilityIsRespectedForGroupCreation() throws Exception {
+ AccountGroup.UUID group1Uuid = groupOperations.newGroup().visibleToAll(true).create();
+ AccountGroup.UUID group2Uuid = groupOperations.newGroup().visibleToAll(false).create();
+
+ GroupInfo foundGroup1 = getGroupFromServer(group1Uuid);
+ GroupInfo foundGroup2 = getGroupFromServer(group2Uuid);
+ assertThat(foundGroup1.options.visibleToAll).isTrue();
+ // False == null
+ assertThat(foundGroup2.options.visibleToAll).isNull();
+ }
+
+ @Test
+ public void specifiedMembersAreRespectedForGroupCreation() throws Exception {
+ Account.Id account1Id = accountOperations.newAccount().create();
+ Account.Id account2Id = accountOperations.newAccount().create();
+ Account.Id account3Id = accountOperations.newAccount().create();
+ Account.Id account4Id = accountOperations.newAccount().create();
+
+ AccountGroup.UUID groupUuid =
+ groupOperations
+ .newGroup()
+ .members(account1Id, account2Id)
+ .addMember(account3Id)
+ .addMember(account4Id)
+ .create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.members)
+ .comparingElementsUsing(getAccountToIdCorrespondence())
+ .containsExactly(account1Id, account2Id, account3Id, account4Id);
+ }
+
+ @Test
+ public void directlyAddingMembersIsPossibleForGroupCreation() throws Exception {
+ Account.Id account1Id = accountOperations.newAccount().create();
+ Account.Id account2Id = accountOperations.newAccount().create();
+
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().addMember(account1Id).addMember(account2Id).create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.members)
+ .comparingElementsUsing(getAccountToIdCorrespondence())
+ .containsExactly(account1Id, account2Id);
+ }
+
+ @Test
+ public void requestingNoMembersIsPossibleForGroupCreation() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearMembers().create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.members).isEmpty();
+ }
+
+ @Test
+ public void specifiedSubgroupsAreRespectedForGroupCreation() throws Exception {
+ AccountGroup.UUID group1Uuid = groupOperations.newGroup().create();
+ AccountGroup.UUID group2Uuid = groupOperations.newGroup().create();
+ AccountGroup.UUID group3Uuid = groupOperations.newGroup().create();
+ AccountGroup.UUID group4Uuid = groupOperations.newGroup().create();
+
+ AccountGroup.UUID groupUuid =
+ groupOperations
+ .newGroup()
+ .subgroups(group1Uuid, group2Uuid)
+ .addSubgroup(group3Uuid)
+ .addSubgroup(group4Uuid)
+ .create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.includes)
+ .comparingElementsUsing(getGroupToUuidCorrespondence())
+ .containsExactly(group1Uuid, group2Uuid, group3Uuid, group4Uuid);
+ }
+
+ @Test
+ public void directlyAddingSubgroupsIsPossibleForGroupCreation() throws Exception {
+ AccountGroup.UUID group1Uuid = groupOperations.newGroup().create();
+ AccountGroup.UUID group2Uuid = groupOperations.newGroup().create();
+
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().addSubgroup(group1Uuid).addSubgroup(group2Uuid).create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.includes)
+ .comparingElementsUsing(getGroupToUuidCorrespondence())
+ .containsExactly(group1Uuid, group2Uuid);
+ }
+
+ @Test
+ public void requestingNoSubgroupsIsPossibleForGroupCreation() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearSubgroups().create();
+
+ GroupInfo foundGroup = getGroupFromServer(groupUuid);
+ assertThat(foundGroup.includes).isEmpty();
+ }
+
+ @Test
+ public void existingGroupCanBeCheckedForExistence() throws Exception {
+ AccountGroup.UUID groupUuid = createGroupInServer(createArbitraryGroupInput());
+
+ boolean exists = groupOperations.group(groupUuid).exists();
+
+ assertThat(exists).isTrue();
+ }
+
+ @Test
+ public void notExistingGroupCanBeCheckedForExistence() throws Exception {
+ AccountGroup.UUID notExistingGroupUuid = new AccountGroup.UUID("not-existing-group");
+
+ boolean exists = groupOperations.group(notExistingGroupUuid).exists();
+
+ assertThat(exists).isFalse();
+ }
+
+ @Test
+ public void retrievingNotExistingGroupFails() throws Exception {
+ AccountGroup.UUID notExistingGroupUuid = new AccountGroup.UUID("not-existing-group");
+
+ expectedException.expect(IllegalStateException.class);
+ groupOperations.group(notExistingGroupUuid).get();
+ }
+
+ @Test
+ public void groupNotCreatedByTestApiCanBeRetrieved() throws Exception {
+ GroupInput input = createArbitraryGroupInput();
+ input.name = "unique group not created via test API";
+ AccountGroup.UUID groupUuid = createGroupInServer(input);
+
+ TestGroup foundGroup = groupOperations.group(groupUuid).get();
+
+ assertThat(foundGroup.groupUuid()).isEqualTo(groupUuid);
+ assertThat(foundGroup.name()).isEqualTo("unique group not created via test API");
+ }
+
+ @Test
+ public void uuidOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().create();
+
+ AccountGroup.UUID foundGroupUuid = groupOperations.group(groupUuid).get().groupUuid();
+
+ assertThat(foundGroupUuid).isEqualTo(groupUuid);
+ }
+
+ @Test
+ public void nameOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().name("ABC-789-this-name-must-be-unique").create();
+
+ String groupName = groupOperations.group(groupUuid).get().name();
+
+ assertThat(groupName).isEqualTo("ABC-789-this-name-must-be-unique");
+ }
+
+ @Test
+ public void nameKeyOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().name("ABC-789-this-name-must-be-unique").create();
+
+ AccountGroup.NameKey groupName = groupOperations.group(groupUuid).get().nameKey();
+
+ assertThat(groupName).isEqualTo(new AccountGroup.NameKey("ABC-789-this-name-must-be-unique"));
+ }
+
+ @Test
+ public void descriptionOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations
+ .newGroup()
+ .description("This is a very detailed description of this group.")
+ .create();
+
+ Optional<String> description = groupOperations.group(groupUuid).get().description();
+
+ assertThat(description).hasValue("This is a very detailed description of this group.");
+ }
+
+ @Test
+ public void emptyDescriptionOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearDescription().create();
+
+ Optional<String> description = groupOperations.group(groupUuid).get().description();
+
+ assertThat(description).isEmpty();
+ }
+
+ @Test
+ public void ownerGroupUuidOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID originalOwnerGroupUuid = new AccountGroup.UUID("owner group");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().ownerGroupUuid(originalOwnerGroupUuid).create();
+
+ AccountGroup.UUID ownerGroupUuid = groupOperations.group(groupUuid).get().ownerGroupUuid();
+
+ assertThat(ownerGroupUuid).isEqualTo(originalOwnerGroupUuid);
+ }
+
+ @Test
+ public void visibilityOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID visibleGroupUuid = groupOperations.newGroup().visibleToAll(true).create();
+ AccountGroup.UUID invisibleGroupUuid = groupOperations.newGroup().visibleToAll(false).create();
+
+ TestGroup visibleGroup = groupOperations.group(visibleGroupUuid).get();
+ TestGroup invisibleGroup = groupOperations.group(invisibleGroupUuid).get();
+
+ assertThat(visibleGroup.visibleToAll()).named("visibility of visible group").isTrue();
+ assertThat(invisibleGroup.visibleToAll()).named("visibility of invisible group").isFalse();
+ }
+
+ @Test
+ public void createdOnOfExistingGroupCanBeRetrieved() throws Exception {
+ GroupInfo group = gApi.groups().create(createArbitraryGroupInput()).detail();
+ AccountGroup.UUID groupUuid = new AccountGroup.UUID(group.id);
+
+ Timestamp createdOn = groupOperations.group(groupUuid).get().createdOn();
+
+ assertThat(createdOn).isEqualTo(group.createdOn);
+ }
+
+ @Test
+ public void membersOfExistingGroupCanBeRetrieved() throws Exception {
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ Account.Id memberId3 = new Account.Id(3000);
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().members(memberId1, memberId2, memberId3).create();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+
+ assertThat(members).containsExactly(memberId1, memberId2, memberId3);
+ }
+
+ @Test
+ public void emptyMembersOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearMembers().create();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+
+ assertThat(members).isEmpty();
+ }
+
+ @Test
+ public void subgroupsOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ AccountGroup.UUID subgroupUuid3 = new AccountGroup.UUID("subgroup 3");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().subgroups(subgroupUuid1, subgroupUuid2, subgroupUuid3).create();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+
+ assertThat(subgroups).containsExactly(subgroupUuid1, subgroupUuid2, subgroupUuid3);
+ }
+
+ @Test
+ public void emptySubgroupsOfExistingGroupCanBeRetrieved() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearSubgroups().create();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+
+ assertThat(subgroups).isEmpty();
+ }
+
+ @Test
+ public void updateWithoutAnyParametersIsANoop() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().create();
+ TestGroup originalGroup = groupOperations.group(groupUuid).get();
+
+ groupOperations.group(groupUuid).forUpdate().update();
+
+ TestGroup updatedGroup = groupOperations.group(groupUuid).get();
+ assertThat(updatedGroup).isEqualTo(originalGroup);
+ }
+
+ @Test
+ public void updateWritesToInternalGroupSystem() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().description("original description").create();
+
+ groupOperations.group(groupUuid).forUpdate().description("updated description").update();
+
+ String currentDescription = getGroupFromServer(groupUuid).description;
+ assertThat(currentDescription).isEqualTo("updated description");
+ }
+
+ @Test
+ public void nameCanBeUpdated() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().name("original name").create();
+
+ groupOperations.group(groupUuid).forUpdate().name("updated name").update();
+
+ String currentName = groupOperations.group(groupUuid).get().name();
+ assertThat(currentName).isEqualTo("updated name");
+ }
+
+ @Test
+ public void descriptionCanBeUpdated() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().description("original description").create();
+
+ groupOperations.group(groupUuid).forUpdate().description("updated description").update();
+
+ Optional<String> currentDescription = groupOperations.group(groupUuid).get().description();
+ assertThat(currentDescription).hasValue("updated description");
+ }
+
+ @Test
+ public void descriptionCanBeCleared() throws Exception {
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().description("original description").create();
+
+ groupOperations.group(groupUuid).forUpdate().clearDescription().update();
+
+ Optional<String> currentDescription = groupOperations.group(groupUuid).get().description();
+ assertThat(currentDescription).isEmpty();
+ }
+
+ @Test
+ public void ownerGroupUuidCanBeUpdated() throws Exception {
+ AccountGroup.UUID originalOwnerGroupUuid = new AccountGroup.UUID("original owner");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().ownerGroupUuid(originalOwnerGroupUuid).create();
+
+ AccountGroup.UUID updatedOwnerGroupUuid = new AccountGroup.UUID("updated owner");
+ groupOperations.group(groupUuid).forUpdate().ownerGroupUuid(updatedOwnerGroupUuid).update();
+
+ AccountGroup.UUID currentOwnerGroupUuid =
+ groupOperations.group(groupUuid).get().ownerGroupUuid();
+ assertThat(currentOwnerGroupUuid).isEqualTo(updatedOwnerGroupUuid);
+ }
+
+ @Test
+ public void visibilityCanBeUpdated() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().visibleToAll(true).create();
+
+ groupOperations.group(groupUuid).forUpdate().visibleToAll(false).update();
+
+ boolean visibleToAll = groupOperations.group(groupUuid).get().visibleToAll();
+ assertThat(visibleToAll).isFalse();
+ }
+
+ @Test
+ public void membersCanBeAdded() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearMembers().create();
+
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ groupOperations.group(groupUuid).forUpdate().addMember(memberId1).addMember(memberId2).update();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+ assertThat(members).containsExactly(memberId1, memberId2);
+ }
+
+ @Test
+ public void membersCanBeRemoved() throws Exception {
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().members(memberId1, memberId2).create();
+
+ groupOperations.group(groupUuid).forUpdate().removeMember(memberId2).update();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+ assertThat(members).containsExactly(memberId1);
+ }
+
+ @Test
+ public void memberAdditionAndRemovalCanBeMixed() throws Exception {
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().members(memberId1, memberId2).create();
+
+ Account.Id memberId3 = new Account.Id(3000);
+ groupOperations
+ .group(groupUuid)
+ .forUpdate()
+ .removeMember(memberId1)
+ .addMember(memberId3)
+ .update();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+ assertThat(members).containsExactly(memberId2, memberId3);
+ }
+
+ @Test
+ public void membersCanBeCleared() throws Exception {
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().members(memberId1, memberId2).create();
+
+ groupOperations.group(groupUuid).forUpdate().clearMembers().update();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+ assertThat(members).isEmpty();
+ }
+
+ @Test
+ public void furtherMembersCanBeAddedAfterClearingAll() throws Exception {
+ Account.Id memberId1 = new Account.Id(1000);
+ Account.Id memberId2 = new Account.Id(2000);
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().members(memberId1, memberId2).create();
+
+ Account.Id memberId3 = new Account.Id(3000);
+ groupOperations.group(groupUuid).forUpdate().clearMembers().addMember(memberId3).update();
+
+ ImmutableSet<Account.Id> members = groupOperations.group(groupUuid).get().members();
+ assertThat(members).containsExactly(memberId3);
+ }
+
+ @Test
+ public void subgroupsCanBeAdded() throws Exception {
+ AccountGroup.UUID groupUuid = groupOperations.newGroup().clearSubgroups().create();
+
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ groupOperations
+ .group(groupUuid)
+ .forUpdate()
+ .addSubgroup(subgroupUuid1)
+ .addSubgroup(subgroupUuid2)
+ .update();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+ assertThat(subgroups).containsExactly(subgroupUuid1, subgroupUuid2);
+ }
+
+ @Test
+ public void subgroupsCanBeRemoved() throws Exception {
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().subgroups(subgroupUuid1, subgroupUuid2).create();
+
+ groupOperations.group(groupUuid).forUpdate().removeSubgroup(subgroupUuid2).update();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+ assertThat(subgroups).containsExactly(subgroupUuid1);
+ }
+
+ @Test
+ public void subgroupAdditionAndRemovalCanBeMixed() throws Exception {
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().subgroups(subgroupUuid1, subgroupUuid2).create();
+
+ AccountGroup.UUID subgroupUuid3 = new AccountGroup.UUID("subgroup 3");
+ groupOperations
+ .group(groupUuid)
+ .forUpdate()
+ .removeSubgroup(subgroupUuid1)
+ .addSubgroup(subgroupUuid3)
+ .update();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+ assertThat(subgroups).containsExactly(subgroupUuid2, subgroupUuid3);
+ }
+
+ @Test
+ public void subgroupsCanBeCleared() throws Exception {
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().subgroups(subgroupUuid1, subgroupUuid2).create();
+
+ groupOperations.group(groupUuid).forUpdate().clearSubgroups().update();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+ assertThat(subgroups).isEmpty();
+ }
+
+ @Test
+ public void furtherSubgroupsCanBeAddedAfterClearingAll() throws Exception {
+ AccountGroup.UUID subgroupUuid1 = new AccountGroup.UUID("subgroup 1");
+ AccountGroup.UUID subgroupUuid2 = new AccountGroup.UUID("subgroup 2");
+ AccountGroup.UUID groupUuid =
+ groupOperations.newGroup().subgroups(subgroupUuid1, subgroupUuid2).create();
+
+ AccountGroup.UUID subgroupUuid3 = new AccountGroup.UUID("subgroup 3");
+ groupOperations
+ .group(groupUuid)
+ .forUpdate()
+ .clearSubgroups()
+ .addSubgroup(subgroupUuid3)
+ .update();
+
+ ImmutableSet<AccountGroup.UUID> subgroups = groupOperations.group(groupUuid).get().subgroups();
+ assertThat(subgroups).containsExactly(subgroupUuid3);
+ }
+
+ private GroupInput createArbitraryGroupInput() {
+ GroupInput groupInput = new GroupInput();
+ groupInput.name = name("verifiers-" + uniqueGroupNameIndex++);
+ return groupInput;
+ }
+
+ private GroupInfo getGroupFromServer(AccountGroup.UUID groupUuid) throws RestApiException {
+ return gApi.groups().id(groupUuid.get()).detail();
+ }
+
+ private AccountGroup.UUID createGroupInServer(GroupInput input) throws RestApiException {
+ GroupInfo group = gApi.groups().create(input).detail();
+ return new AccountGroup.UUID(group.id);
+ }
+
+ private static Correspondence<AccountInfo, Account.Id> getAccountToIdCorrespondence() {
+ return new Correspondence<AccountInfo, Account.Id>() {
+ @Override
+ public boolean compare(AccountInfo actualAccount, Account.Id expectedId) {
+ Account.Id accountId =
+ Optional.ofNullable(actualAccount)
+ .map(account -> account._accountId)
+ .map(Account.Id::new)
+ .orElse(null);
+ return Objects.equals(accountId, expectedId);
+ }
+
+ @Override
+ public String toString() {
+ return "has ID";
+ }
+ };
+ }
+
+ private static Correspondence<GroupInfo, AccountGroup.UUID> getGroupToUuidCorrespondence() {
+ return new Correspondence<GroupInfo, AccountGroup.UUID>() {
+ @Override
+ public boolean compare(GroupInfo actualGroup, AccountGroup.UUID expectedUuid) {
+ AccountGroup.UUID groupUuid =
+ Optional.ofNullable(actualGroup)
+ .map(group -> group.id)
+ .map(AccountGroup.UUID::new)
+ .orElse(null);
+ return Objects.equals(groupUuid, expectedUuid);
+ }
+
+ @Override
+ public String toString() {
+ return "has UUID";
+ }
+ };
+ }
+}