blob: 8d1d89f7e7f5a7f2ccc60225781b5f9181aa7adf [file] [log] [blame]
// Copyright (C) 2015 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.api.group;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.api.group.GroupAssert.assertGroupInfo;
import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfos;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.groups.GroupApi;
import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.GroupAuditEventInfo;
import com.google.gerrit.extensions.common.GroupAuditEventInfo.GroupMemberAuditEventInfo;
import com.google.gerrit.extensions.common.GroupAuditEventInfo.Type;
import com.google.gerrit.extensions.common.GroupAuditEventInfo.UserMemberAuditEventInfo;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.extensions.common.GroupOptionsInfo;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.group.SystemGroupBackend;
import org.junit.Test;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@NoHttpd
public class GroupsIT extends AbstractDaemonTest {
@Test
public void addToNonExistingGroup_NotFound() throws Exception {
exception.expect(ResourceNotFoundException.class);
gApi.groups().id("non-existing").addMembers("admin");
}
@Test
public void removeFromNonExistingGroup_NotFound() throws Exception {
exception.expect(ResourceNotFoundException.class);
gApi.groups().id("non-existing").removeMembers("admin");
}
@Test
public void addRemoveMember() throws Exception {
String g = createGroup("users");
gApi.groups().id(g).addMembers("user");
assertMembers(g, user);
gApi.groups().id(g).removeMembers("user");
assertNoMembers(g);
}
@Test
public void addExistingMember_OK() throws Exception {
String g = "Administrators";
assertMembers(g, admin);
gApi.groups().id("Administrators").addMembers("admin");
assertMembers(g, admin);
}
@Test
public void addNonExistingMember_UnprocessableEntity() throws Exception {
exception.expect(UnprocessableEntityException.class);
gApi.groups().id("Administrators").addMembers("non-existing");
}
@Test
public void addMultipleMembers() throws Exception {
String g = createGroup("users");
TestAccount u1 = accounts.create("u1", "u1@example.com", "Full Name 1");
TestAccount u2 = accounts.create("u2", "u2@example.com", "Full Name 2");
gApi.groups().id(g).addMembers(u1.username, u2.username);
assertMembers(g, u1, u2);
}
@Test
public void includeRemoveGroup() throws Exception {
String p = createGroup("parent");
String g = createGroup("newGroup");
gApi.groups().id(p).addGroups(g);
assertIncludes(p, g);
gApi.groups().id(p).removeGroups(g);
assertNoIncludes(p);
}
@Test
public void includeExistingGroup_OK() throws Exception {
String p = createGroup("parent");
String g = createGroup("newGroup");
gApi.groups().id(p).addGroups(g);
assertIncludes(p, g);
gApi.groups().id(p).addGroups(g);
assertIncludes(p, g);
}
@Test
public void addMultipleIncludes() throws Exception {
String p = createGroup("parent");
String g1 = createGroup("newGroup1");
String g2 = createGroup("newGroup2");
List<String> groups = Lists.newLinkedList();
groups.add(g1);
groups.add(g2);
gApi.groups().id(p).addGroups(g1, g2);
assertIncludes(p, g1, g2);
}
@Test
public void testCreateGroup() throws Exception {
String newGroupName = name("newGroup");
GroupInfo g = gApi.groups().create(newGroupName).get();
assertGroupInfo(getFromCache(newGroupName), g);
}
@Test
public void testCreateGroupWithProperties() throws Exception {
GroupInput in = new GroupInput();
in.name = name("newGroup");
in.description = "Test description";
in.visibleToAll = true;
in.ownerId = getFromCache("Administrators").getGroupUUID().get();
GroupInfo g = gApi.groups().create(in).detail();
assertThat(g.description).isEqualTo(in.description);
assertThat(g.options.visibleToAll).isEqualTo(in.visibleToAll);
assertThat(g.ownerId).isEqualTo(in.ownerId);
}
@Test
public void testCreateGroupWithoutCapability_Forbidden() throws Exception {
setApiUser(user);
exception.expect(AuthException.class);
gApi.groups().create(name("newGroup"));
}
@Test
public void testCreateGroupWhenGroupAlreadyExists_Conflict()
throws Exception {
exception.expect(ResourceConflictException.class);
gApi.groups().create("Administrators");
}
@Test
public void testGetGroup() throws Exception {
AccountGroup adminGroup = groupCache.get(new AccountGroup.NameKey("Administrators"));
testGetGroup(adminGroup.getGroupUUID().get(), adminGroup);
testGetGroup(adminGroup.getName(), adminGroup);
testGetGroup(adminGroup.getId().get(), adminGroup);
}
private void testGetGroup(Object id, AccountGroup expectedGroup)
throws Exception {
GroupInfo group = gApi.groups().id(id.toString()).get();
assertGroupInfo(expectedGroup, group);
}
@Test
public void testGroupName() throws Exception {
String name = name("group");
gApi.groups().create(name);
// get name
assertThat(gApi.groups().id(name).name()).isEqualTo(name);
// set name to same name
gApi.groups().id(name).name(name);
assertThat(gApi.groups().id(name).name()).isEqualTo(name);
// set name with name conflict
String other = name("other");
gApi.groups().create(other);
exception.expect(ResourceConflictException.class);
gApi.groups().id(name).name(other);
}
@Test
public void testGroupRename() throws Exception {
String name = name("group");
gApi.groups().create(name);
String newName = name("newName");
gApi.groups().id(name).name(newName);
assertThat(getFromCache(newName)).isNotNull();
assertThat(gApi.groups().id(newName).name()).isEqualTo(newName);
assertThat(getFromCache(name)).isNull();
exception.expect(ResourceNotFoundException.class);
gApi.groups().id(name).get();
}
@Test
public void testGroupDescription() throws Exception {
String name = name("group");
gApi.groups().create(name);
// get description
assertThat(gApi.groups().id(name).description()).isEmpty();
// set description
String desc = "New description for the group.";
gApi.groups().id(name).description(desc);
assertThat(gApi.groups().id(name).description()).isEqualTo(desc);
// set description to null
gApi.groups().id(name).description(null);
assertThat(gApi.groups().id(name).description()).isEmpty();
// set description to empty string
gApi.groups().id(name).description("");
assertThat(gApi.groups().id(name).description()).isEmpty();
}
@Test
public void testGroupOptions() throws Exception {
String name = name("group");
gApi.groups().create(name);
// get options
assertThat(gApi.groups().id(name).options().visibleToAll).isNull();
// set options
GroupOptionsInfo options = new GroupOptionsInfo();
options.visibleToAll = true;
gApi.groups().id(name).options(options);
assertThat(gApi.groups().id(name).options().visibleToAll).isTrue();
}
@Test
public void testGroupOwner() throws Exception {
String name = name("group");
GroupInfo info = gApi.groups().create(name).get();
String adminUUID = getFromCache("Administrators").getGroupUUID().get();
String registeredUUID = SystemGroupBackend.REGISTERED_USERS.get();
// get owner
assertThat(Url.decode(gApi.groups().id(name).owner().id))
.isEqualTo(info.id);
// set owner by name
gApi.groups().id(name).owner("Registered Users");
assertThat(Url.decode(gApi.groups().id(name).owner().id))
.isEqualTo(registeredUUID);
// set owner by UUID
gApi.groups().id(name).owner(adminUUID);
assertThat(Url.decode(gApi.groups().id(name).owner().id))
.isEqualTo(adminUUID);
// set non existing owner
exception.expect(UnprocessableEntityException.class);
gApi.groups().id(name).owner("Non-Existing Group");
}
@Test
public void listNonExistingGroupIncludes_NotFound() throws Exception {
exception.expect(ResourceNotFoundException.class);
gApi.groups().id("non-existing").includedGroups();
}
@Test
public void listEmptyGroupIncludes() throws Exception {
String gx = createGroup("gx");
assertThat(gApi.groups().id(gx).includedGroups()).isEmpty();
}
@Test
public void includeNonExistingGroup() throws Exception {
String gx = createGroup("gx");
exception.expect(UnprocessableEntityException.class);
gApi.groups().id(gx).addGroups("non-existing");
}
@Test
public void listNonEmptyGroupIncludes() throws Exception {
String gx = createGroup("gx");
String gy = createGroup("gy");
String gz = createGroup("gz");
gApi.groups().id(gx).addGroups(gy);
gApi.groups().id(gx).addGroups(gz);
assertIncludes(gApi.groups().id(gx).includedGroups(), gy, gz);
}
@Test
public void listOneIncludeMember() throws Exception {
String gx = createGroup("gx");
String gy = createGroup("gy");
gApi.groups().id(gx).addGroups(gy);
assertIncludes(gApi.groups().id(gx).includedGroups(), gy);
}
@Test
public void listNonExistingGroupMembers_NotFound() throws Exception {
exception.expect(ResourceNotFoundException.class);
gApi.groups().id("non-existing").members();
}
@Test
public void listEmptyGroupMembers() throws Exception {
String group = createGroup("empty");
assertThat(gApi.groups().id(group).members()).isEmpty();
}
@Test
public void listNonEmptyGroupMembers() throws Exception {
String group = createGroup("group");
String user1 = createAccount("user1", group);
String user2 = createAccount("user2", group);
assertMembers(gApi.groups().id(group).members(), user1, user2);
}
@Test
public void listOneGroupMember() throws Exception {
String group = createGroup("group");
String user = createAccount("user1", group);
assertMembers(gApi.groups().id(group).members(), user);
}
@Test
public void listGroupMembersRecursively() throws Exception {
String gx = createGroup("gx");
String ux = createAccount("ux", gx);
String gy = createGroup("gy");
String uy = createAccount("uy", gy);
String gz = createGroup("gz");
String uz = createAccount("uz", gz);
gApi.groups().id(gx).addGroups(gy);
gApi.groups().id(gy).addGroups(gz);
assertMembers(gApi.groups().id(gx).members(), ux);
assertMembers(gApi.groups().id(gx).members(true), ux, uy, uz);
}
@Test
public void defaultGroupsCreated() throws Exception {
Iterable<String> names = gApi.groups().list().getAsMap().keySet();
assertThat(names).containsAllOf("Administrators", "Non-Interactive Users")
.inOrder();
}
@Test
public void testListAllGroups() throws Exception {
List<String> expectedGroups = FluentIterable
.from(groupCache.all())
.transform(new Function<AccountGroup, String>() {
@Override
public String apply(AccountGroup group) {
return group.getName();
}
}).toSortedList(Ordering.natural());
assertThat(expectedGroups.size()).isAtLeast(2);
assertThat(gApi.groups().list().getAsMap().keySet())
.containsExactlyElementsIn(expectedGroups).inOrder();
}
@Test
public void testOnlyVisibleGroupsReturned() throws Exception {
String newGroupName = name("newGroup");
GroupInput in = new GroupInput();
in.name = newGroupName;
in.description = "a hidden group";
in.visibleToAll = false;
in.ownerId = getFromCache("Administrators").getGroupUUID().get();
gApi.groups().create(in);
setApiUser(user);
assertThat(gApi.groups().list().getAsMap())
.doesNotContainKey(newGroupName);
setApiUser(admin);
gApi.groups().id(newGroupName).addMembers(user.username);
setApiUser(user);
assertThat(gApi.groups().list().getAsMap()).containsKey(newGroupName);
}
@Test
public void testSuggestGroup() throws Exception {
Map<String, GroupInfo> groups = gApi.groups().list().withSuggest("adm").getAsMap();
assertThat(groups).containsKey("Administrators");
assertThat(groups).hasSize(1);
}
@Test
public void testAllGroupInfoFieldsSetCorrectly() throws Exception {
AccountGroup adminGroup = getFromCache("Administrators");
Map<String, GroupInfo> groups =
gApi.groups().list().addGroup(adminGroup.getName()).getAsMap();
assertThat(groups).hasSize(1);
assertThat(groups).containsKey("Administrators");
assertGroupInfo(adminGroup, Iterables.getOnlyElement(groups.values()));
}
@Test
public void getAuditLog() throws Exception {
GroupApi g = gApi.groups().create(name("group"));
List<? extends GroupAuditEventInfo> auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(1);
assertAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, admin.id);
g.addMembers(user.username);
auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(2);
assertAuditEvent(auditEvents.get(0), Type.ADD_USER, admin.id, user.id);
g.removeMembers(user.username);
auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(3);
assertAuditEvent(auditEvents.get(0), Type.REMOVE_USER, admin.id, user.id);
String otherGroup = name("otherGroup");
gApi.groups().create(otherGroup);
g.addGroups(otherGroup);
auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(4);
assertAuditEvent(auditEvents.get(0), Type.ADD_GROUP, admin.id, otherGroup);
g.removeGroups(otherGroup);
auditEvents = g.auditLog();
assertThat(auditEvents).hasSize(5);
assertAuditEvent(auditEvents.get(0), Type.REMOVE_GROUP, admin.id, otherGroup);
Timestamp lastDate = null;
for (GroupAuditEventInfo auditEvent : auditEvents) {
if (lastDate != null) {
assertThat(lastDate).isGreaterThan(auditEvent.date);
}
lastDate = auditEvent.date;
}
}
private void assertAuditEvent(GroupAuditEventInfo info, Type expectedType,
Account.Id expectedUser, Account.Id expectedMember) {
assertThat(info.user._accountId).isEqualTo(expectedUser.get());
assertThat(info.type).isEqualTo(expectedType);
assertThat(info).isInstanceOf(UserMemberAuditEventInfo.class);
assertThat(((UserMemberAuditEventInfo) info).member._accountId).isEqualTo(
expectedMember.get());
}
private void assertAuditEvent(GroupAuditEventInfo info, Type expectedType,
Account.Id expectedUser, String expectedMemberGroupName) {
assertThat(info.user._accountId).isEqualTo(expectedUser.get());
assertThat(info.type).isEqualTo(expectedType);
assertThat(info).isInstanceOf(GroupMemberAuditEventInfo.class);
assertThat(((GroupMemberAuditEventInfo) info).member.name).isEqualTo(
expectedMemberGroupName);
}
private void assertMembers(String group, TestAccount... expectedMembers)
throws Exception {
assertMembers(
gApi.groups().id(group).members(),
TestAccount.names(expectedMembers).toArray(String.class));
assertAccountInfos(
Arrays.asList(expectedMembers),
gApi.groups().id(group).members());
}
private void assertMembers(Iterable<AccountInfo> members,
String... expectedNames) {
Iterable<String> memberNames = Iterables.transform(members,
new Function<AccountInfo, String>() {
@Override
public String apply(@Nullable AccountInfo info) {
return info.name;
}
});
assertThat(memberNames)
.containsExactlyElementsIn(Arrays.asList(expectedNames)).inOrder();
}
private void assertNoMembers(String group) throws Exception {
assertThat(gApi.groups().id(group).members()).isEmpty();
}
private void assertIncludes(String group, String... expectedNames)
throws Exception {
assertIncludes(gApi.groups().id(group).includedGroups(), expectedNames);
}
private static void assertIncludes(
Iterable<GroupInfo> includes, String... expectedNames) {
Iterable<String> includeNames = Iterables.transform(
includes,
new Function<GroupInfo, String>() {
@Override
public String apply(@Nullable GroupInfo info) {
return info.name;
}
});
assertThat(includeNames)
.containsExactlyElementsIn(Arrays.asList(expectedNames)).inOrder();
}
private void assertNoIncludes(String group) throws Exception {
assertThat(gApi.groups().id(group).includedGroups()).isEmpty();
}
private AccountGroup getFromCache(String name) throws Exception {
return groupCache.get(new AccountGroup.NameKey(name));
}
private String createGroup(String name) throws Exception {
return createGroup(name, "Administrators");
}
private String createGroup(String name, String owner) throws Exception {
name = name(name);
GroupInput in = new GroupInput();
in.name = name;
in.ownerId = owner;
gApi.groups().create(in);
return name;
}
private String createAccount(String name, String group) throws Exception {
name = name(name);
accounts.create(name, group);
return name;
}
}