diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java index 3909cf1353..f56ef07987 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AccountCreator.java @@ -84,12 +84,14 @@ public class AccountCreator { db.accountSshKeys().insert(Collections.singleton(key)); - for (String n : groups) { - AccountGroup.NameKey k = new AccountGroup.NameKey(n); - AccountGroup g = groupCache.get(k); - AccountGroupMember m = - new AccountGroupMember(new AccountGroupMember.Key(id, g.getId())); - db.accountGroupMembers().insert(Collections.singleton(m)); + if (groups != null) { + for (String n : groups) { + AccountGroup.NameKey k = new AccountGroup.NameKey(n); + AccountGroup g = groupCache.get(k); + AccountGroupMember m = + new AccountGroupMember(new AccountGroupMember.Key(id, g.getId())); + db.accountGroupMembers().insert(Collections.singleton(m)); + } } sshKeyCache.evict(username); @@ -107,6 +109,11 @@ public class AccountCreator { return create(username, null, username, group); } + public TestAccount create(String username) + throws UnsupportedEncodingException, OrmException, JSchException { + return create(username, null, username, (String[]) null); + } + private AccountExternalId.Key getEmailKey(String email) { return new AccountExternalId.Key(AccountExternalId.SCHEME_MAILTO, email); } diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java index 5791fc87d8..929be84c71 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/RestSession.java @@ -20,6 +20,7 @@ import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; @@ -55,9 +56,13 @@ public class RestSession { return new RestResponse(getClient().execute(put)); } - public RestResponse post(String endPoint) { - // TODO - return null; + public RestResponse post(String endPoint, Object content) throws IOException { + HttpPost post = new HttpPost("http://localhost:8080/a" + endPoint); + if (content != null) { + post.addHeader(new BasicHeader("Content-Type", "application/json")); + post.setEntity(new StringEntity((new Gson()).toJson(content), HTTP.UTF_8)); + } + return new RestResponse(getClient().execute(post)); } public RestResponse delete(String endPoint) throws IOException { diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java new file mode 100644 index 0000000000..f788f7061e --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/AddRemoveGroupMembersIT.java @@ -0,0 +1,263 @@ +// Copyright (C) 2013 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.rest.group; + +import static com.google.gerrit.acceptance.rest.group.GroupAssert.assertGroupInfo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.AccountCreator; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.acceptance.RestSession; +import com.google.gerrit.acceptance.TestAccount; +import com.google.gerrit.reviewdb.client.Account; +import com.google.gerrit.reviewdb.client.AccountGroup; +import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid; +import com.google.gerrit.reviewdb.client.AccountGroupMember; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.account.GroupCache; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.gwtorm.server.OrmException; +import com.google.gwtorm.server.ResultSet; +import com.google.gwtorm.server.SchemaFactory; +import com.google.inject.Inject; + +import org.apache.http.HttpStatus; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class AddRemoveGroupMembersIT extends AbstractDaemonTest { + + @Inject + private AccountCreator accounts; + + @Inject + private SchemaFactory reviewDbProvider; + + @Inject + private GroupCache groupCache; + + private RestSession session; + private TestAccount admin; + private ReviewDb db; + + @Before + public void setUp() throws Exception { + admin = accounts.create("admin", "Administrators"); + session = new RestSession(admin); + db = reviewDbProvider.open(); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void addToNonExistingGroup_NotFound() throws IOException { + assertEquals(HttpStatus.SC_NOT_FOUND, + PUT("/groups/non-existing/members/admin").getStatusCode()); + } + + @Test + public void removeFromNonExistingGroup_NotFound() throws IOException { + assertEquals(HttpStatus.SC_NOT_FOUND, + DELETE("/groups/non-existing/members/admin")); + } + + @Test + public void addRemoveMember() throws Exception { + TestAccount u = accounts.create("user", "user@example.com", "Full Name"); + RestResponse r = PUT("/groups/Administrators/members/user"); + assertEquals(HttpStatus.SC_CREATED, r.getStatusCode()); + AccountInfo ai = (new Gson()).fromJson(r.getReader(), + new TypeToken() {}.getType()); + assertAccountInfo(u, ai); + assertMembers("Administrators", admin, u); + r.consume(); + + assertEquals(HttpStatus.SC_NO_CONTENT, + DELETE("/groups/Administrators/members/user")); + assertMembers("Administrators", admin); + } + + @Test + public void addExistingMember_OK() throws IOException { + assertEquals(HttpStatus.SC_OK, + PUT("/groups/Administrators/members/admin").getStatusCode()); + } + + @Test + public void addMultipleMembers() throws Exception { + group("users"); + TestAccount u1 = accounts.create("u1", "u1@example.com", "Full Name 1"); + TestAccount u2 = accounts.create("u2", "u2@example.com", "Full Name 2"); + MembersInput input = new MembersInput(); + input.members = Lists.newLinkedList(); + input.members.add(u1.username); + input.members.add(u2.username); + RestResponse r = POST("/groups/users/members", input); + List ai = (new Gson()).fromJson(r.getReader(), + new TypeToken>() {}.getType()); + assertMembers(ai, u1, u2); + } + + @Test + public void includeRemoveGroup() throws Exception { + group("newGroup"); + RestResponse r = PUT("/groups/Administrators/groups/newGroup"); + assertEquals(HttpStatus.SC_CREATED, r.getStatusCode()); + GroupInfo i = (new Gson()).fromJson(r.getReader(), new TypeToken() {}.getType()); + r.consume(); + assertGroupInfo(groupCache.get(new AccountGroup.NameKey("newGroup")), i); + assertIncludes("Administrators", "newGroup"); + + assertEquals(HttpStatus.SC_NO_CONTENT, + DELETE("/groups/Administrators/groups/newGroup")); + assertNoIncludes("Administrators"); + } + + @Test + public void includeExistingGroup_OK() throws Exception { + group("newGroup"); + PUT("/groups/Administrators/groups/newGroup").consume(); + assertEquals(HttpStatus.SC_OK, + PUT("/groups/Administrators/groups/newGroup").getStatusCode()); + } + + @Test + public void addMultipleIncludes() throws Exception { + group("newGroup1"); + group("newGroup2"); + GroupsInput input = new GroupsInput(); + input.groups = Lists.newLinkedList(); + input.groups.add("newGroup1"); + input.groups.add("newGroup2"); + RestResponse r = POST("/groups/Administrators/groups", input); + List gi = (new Gson()).fromJson(r.getReader(), + new TypeToken>() {}.getType()); + assertIncludes(gi, "newGroup1", "newGroup2"); + } + + private RestResponse PUT(String endpoint) throws IOException { + return session.put(endpoint); + } + + private int DELETE(String endpoint) throws IOException { + RestResponse r = session.delete(endpoint); + r.consume(); + return r.getStatusCode(); + } + + private RestResponse POST(String endPoint, MembersInput mi) throws IOException { + return session.post(endPoint, mi); + } + + private RestResponse POST(String endPoint, GroupsInput gi) throws IOException { + return session.post(endPoint, gi); + } + + private void group(String name) throws IOException { + GroupInput in = new GroupInput(); + session.put("/groups/" + name, in).consume(); + } + + private void assertAccountInfo(TestAccount a, AccountInfo ai) { + assertTrue(a.id.get() == ai._account_id); + assertEquals(a.fullName, ai.name); + assertEquals(a.email, ai.email); + } + + private void assertMembers(String group, TestAccount... members) + throws OrmException { + AccountGroup g = groupCache.get(new AccountGroup.NameKey(group)); + Set ids = Sets.newHashSet(); + ResultSet all = + db.accountGroupMembers().byGroup(g.getId()); + for (AccountGroupMember m : all) { + ids.add(m.getAccountId()); + } + assertTrue(ids.size() == members.length); + for (TestAccount a : members) { + assertTrue(ids.contains(a.id)); + } + } + + private void assertMembers(List ai, TestAccount... members) { + Map infoById = Maps.newHashMap(); + for (AccountInfo i : ai) { + infoById.put(i._account_id, i); + } + + for (TestAccount a : members) { + AccountInfo i = infoById.get(a.id.get()); + assertNotNull(i); + assertAccountInfo(a, i); + } + assertEquals(ai.size(), members.length); + } + + private void assertIncludes(String group, String... includes) + throws OrmException { + AccountGroup g = groupCache.get(new AccountGroup.NameKey(group)); + Set ids = Sets.newHashSet(); + ResultSet all = + db.accountGroupIncludesByUuid().byGroup(g.getId()); + for (AccountGroupIncludeByUuid m : all) { + ids.add(m.getIncludeUUID()); + } + assertTrue(ids.size() == includes.length); + for (String i : includes) { + AccountGroup.UUID id = groupCache.get( + new AccountGroup.NameKey(i)).getGroupUUID(); + assertTrue(ids.contains(id)); + } + } + + private void assertIncludes(List gi, String... includes) { + Map groupsByName = Maps.newHashMap(); + for (GroupInfo i : gi) { + groupsByName.put(i.name, i); + } + + for (String name : includes) { + GroupInfo i = groupsByName.get(name); + assertNotNull(i); + assertGroupInfo(groupCache.get(new AccountGroup.NameKey(name)), i); + } + assertEquals(gi.size(), includes.length); + } + + private void assertNoIncludes(String group) throws OrmException { + AccountGroup g = groupCache.get(new AccountGroup.NameKey(group)); + Iterator it = + db.accountGroupIncludesByUuid().byGroup(g.getId()).iterator(); + assertFalse(it.hasNext()); + } +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupsInput.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupsInput.java new file mode 100644 index 0000000000..1eceda92e0 --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/GroupsInput.java @@ -0,0 +1,21 @@ +// Copyright (C) 2013 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.rest.group; + +import java.util.List; + +public class GroupsInput { + List groups; +} diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/MembersInput.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/MembersInput.java new file mode 100644 index 0000000000..11779f4e2a --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/group/MembersInput.java @@ -0,0 +1,21 @@ +// Copyright (C) 2013 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.rest.group; + +import java.util.List; + +public class MembersInput { + List members; +}