aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server
diff options
context:
space:
mode:
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>2015-05-18 17:46:33 +0200
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>2015-05-22 15:34:42 +0200
commit06cafc9839cb231a8f71e1d1c41da43ac1dc0139 (patch)
tree4d685986f5aeaa14b7351218f9406dc1d094ab54 /server/sonar-server
parente1712a805c75bd125942d114d5cdfe6908ae015c (diff)
downloadsonarqube-06cafc9839cb231a8f71e1d1c41da43ac1dc0139.tar.gz
sonarqube-06cafc9839cb231a8f71e1d1c41da43ac1dc0139.zip
SONAR-6471 Add new WS to search for user groups
Diffstat (limited to 'server/sonar-server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java27
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/package-info.java25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java127
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWs.java45
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsAction.java27
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java25
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-search.json19
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java70
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java175
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java61
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/select_by_query.xml9
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/customers.json10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/empty.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/five_groups.json12
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_1.json10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_2.json9
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_3.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/with_members.json12
19 files changed, 668 insertions, 10 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index f829d7ea3ba..a09daf2b385 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -277,6 +277,7 @@ import org.sonar.server.user.ws.CurrentAction;
import org.sonar.server.user.ws.FavoritesWs;
import org.sonar.server.user.ws.UserPropertiesWs;
import org.sonar.server.user.ws.UsersWs;
+import org.sonar.server.usergroups.ws.UserGroupsWs;
import org.sonar.server.util.BooleanTypeValidation;
import org.sonar.server.util.FloatTypeValidation;
import org.sonar.server.util.IntegerTypeValidation;
@@ -490,6 +491,8 @@ public class PlatformLevel4 extends PlatformLevel {
// groups
GroupMembershipService.class,
GroupMembershipFinder.class,
+ UserGroupsWs.class,
+ org.sonar.server.usergroups.ws.SearchAction.class,
// permissions
PermissionFacade.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java b/server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java
index e8ae651cc2f..eda1a1ad2a3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/db/GroupDao.java
@@ -20,20 +20,23 @@
package org.sonar.server.user.db;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ibatis.session.RowBounds;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.user.GroupDto;
import org.sonar.core.user.GroupMapper;
-import java.util.Date;
-import java.util.List;
-
/**
* @since 3.2
*/
public class GroupDao implements DaoComponent {
+ private static final String SQL_WILDCARD = "%";
private System2 system;
public GroupDao(System2 system) {
@@ -44,6 +47,14 @@ public class GroupDao implements DaoComponent {
return mapper(session).selectByKey(key);
}
+ public int countByQuery(DbSession session, @Nullable String query) {
+ return mapper(session).countByQuery(groupSearchToSql(query));
+ }
+
+ public List<GroupDto> selectByQuery(DbSession session, @Nullable String query, int offset, int limit) {
+ return mapper(session).selectByQuery(groupSearchToSql(query), new RowBounds(offset, limit));
+ }
+
public GroupDto insert(DbSession session, GroupDto item) {
Date createdAt = new Date(system.now());
item.setCreatedAt(createdAt)
@@ -59,4 +70,14 @@ public class GroupDao implements DaoComponent {
private GroupMapper mapper(DbSession session) {
return session.getMapper(GroupMapper.class);
}
+
+ private String groupSearchToSql(@Nullable String query) {
+ String sql = SQL_WILDCARD;
+ if (query != null) {
+ sql = StringUtils.replace(StringUtils.upperCase(query), SQL_WILDCARD, "/%");
+ sql = StringUtils.replace(sql, "_", "/_");
+ sql = SQL_WILDCARD + sql + SQL_WILDCARD;
+ }
+ return sql;
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/package-info.java
new file mode 100644
index 00000000000..d8a077df2fa
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.usergroups;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
new file mode 100644
index 00000000000..bcf1c97ca9d
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
@@ -0,0 +1,127 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.usergroups.ws;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.user.GroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+
+public class SearchAction implements UserGroupsWsAction {
+
+ private static final String FIELD_ID = "id";
+ private static final String FIELD_NAME = "name";
+ private static final String FIELD_DESCRIPTION = "description";
+ private static final String FIELD_MEMBERS_COUNT = "membersCount";
+ private static final List<String> ALL_FIELDS = Arrays.asList(FIELD_NAME, FIELD_DESCRIPTION, FIELD_MEMBERS_COUNT);
+
+ private DbClient dbClient;
+
+ public SearchAction(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void define(NewController context) {
+ context.createAction("search")
+ .setDescription("Search for user groups")
+ .setHandler(this)
+ .setResponseExample(getClass().getResource("example-search.json"))
+ .setSince("5.2")
+ .addFieldsParam(ALL_FIELDS)
+ .addPagingParams(100)
+ .addSearchQuery("sonar-users", "names");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ int page = request.mandatoryParamAsInt(Param.PAGE);
+ int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
+ SearchOptions options = new SearchOptions()
+ .setPage(page, pageSize);
+
+ String query = StringUtils.defaultIfBlank(request.param(Param.TEXT_QUERY), "");
+ Set<String> fields = neededFields(request);
+
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ int limit = dbClient.groupDao().countByQuery(dbSession, query);
+ List<GroupDto> groups = dbClient.groupDao().selectByQuery(dbSession, query, options.getOffset(), pageSize);
+ Collection<Long> groupIds = Collections2.transform(groups, new Function<GroupDto, Long>() {
+ @Override
+ public Long apply(@Nonnull GroupDto input) {
+ return input.getId();
+ }
+ });
+ Map<String, Integer> userCountByGroup = dbClient.groupMembershipDao().countUsersByGroups(dbSession, groupIds);
+
+ JsonWriter json = response.newJsonWriter().beginObject();
+ options.writeJson(json, limit);
+ writeGroups(json, groups, userCountByGroup, fields);
+ json.endObject().close();
+ } finally {
+ MyBatis.closeQuietly(dbSession);
+ }
+ }
+
+ private void writeGroups(JsonWriter json, List<GroupDto> groups, Map<String, Integer> userCountByGroup, Set<String> fields) {
+ json.name("groups").beginArray();
+ for (GroupDto group : groups) {
+ writeGroup(json, group, userCountByGroup.get(group.getName()), fields);
+ }
+ json.endArray();
+ }
+
+ private void writeGroup(JsonWriter json, GroupDto group, Integer memberCount, Set<String> fields) {
+ json.beginObject()
+ .prop(FIELD_ID, group.getId().toString())
+ .prop(FIELD_NAME, fields.contains(FIELD_NAME) ? group.getName() : null)
+ .prop(FIELD_DESCRIPTION, fields.contains(FIELD_DESCRIPTION) ? group.getDescription() : null)
+ .prop(FIELD_MEMBERS_COUNT, fields.contains(FIELD_MEMBERS_COUNT) ? memberCount : null)
+ .endObject();
+ }
+
+ private Set<String> neededFields(Request request) {
+ Set<String> fields = Sets.newHashSet();
+ List<String> fieldsFromRequest = request.paramAsStrings(Param.FIELDS);
+ if (fieldsFromRequest == null || fieldsFromRequest.isEmpty()) {
+ fields.addAll(ALL_FIELDS);
+ } else {
+ fields.addAll(fieldsFromRequest);
+ }
+ return fields;
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWs.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWs.java
new file mode 100644
index 00000000000..8ace6844681
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWs.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.usergroups.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class UserGroupsWs implements WebService {
+
+ private UserGroupsWsAction[] actions;
+
+ public UserGroupsWs(UserGroupsWsAction... actions) {
+ this.actions = actions;
+ }
+
+ @Override
+ public void define(Context context) {
+ NewController controller = context.createController("api/usergroups")
+ .setDescription("User groups management")
+ .setSince("5.2");
+
+ for (UserGroupsWsAction action : actions) {
+ action.define(controller);
+ }
+
+ controller.done();
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsAction.java
new file mode 100644
index 00000000000..4e0bbd731dc
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UserGroupsWsAction.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.usergroups.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface UserGroupsWsAction extends WsAction {
+
+ // Marker interface
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java
new file mode 100644
index 00000000000..66099e7017c
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.usergroups.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-search.json
new file mode 100644
index 00000000000..e7371e910ef
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/usergroups/ws/example-search.json
@@ -0,0 +1,19 @@
+{
+ "p": 1,
+ "ps": 100,
+ "total": 2,
+ "groups": [
+ {
+ "id": "1",
+ "name": "users",
+ "description": "Users",
+ "membersCount": 17
+ },
+ {
+ "id": "2",
+ "name": "administrators",
+ "description": "Administrators",
+ "membersCount": 2
+ }
+ ]
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java
index ca20818864c..bb0efb8baf1 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/db/GroupDaoTest.java
@@ -22,18 +22,25 @@ package org.sonar.server.user.db;
import org.junit.After;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Test;
+import org.junit.experimental.categories.Category;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
-import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
import org.sonar.core.user.GroupDto;
+import org.sonar.test.DbTests;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class GroupDaoTest extends AbstractDaoTestCase {
+@Category(DbTests.class)
+public class GroupDaoTest {
+
+ @ClassRule
+ public static final DbTester dbTester = new DbTester();
GroupDao dao;
DbSession session;
@@ -41,7 +48,8 @@ public class GroupDaoTest extends AbstractDaoTestCase {
@Before
public void setUp() {
- this.session = getMyBatis().openSession(false);
+ dbTester.truncateTables();
+ this.session = dbTester.myBatis().openSession(false);
this.system2 = mock(System2.class);
this.dao = new GroupDao(system2);
}
@@ -53,7 +61,7 @@ public class GroupDaoTest extends AbstractDaoTestCase {
@Test
public void select_by_key() {
- setupData("select_by_key");
+ dbTester.prepareDbUnit(getClass(), "select_by_key.xml");
GroupDto group = new GroupDao(system2).selectByKey(session, "sonar-users");
assertThat(group).isNotNull();
@@ -66,7 +74,7 @@ public class GroupDaoTest extends AbstractDaoTestCase {
@Test
public void find_by_user_login() {
- setupData("find_by_user_login");
+ dbTester.prepareDbUnit(getClass(), "find_by_user_login.xml");
assertThat(dao.findByUserLogin(session, "john")).hasSize(2);
assertThat(dao.findByUserLogin(session, "max")).isEmpty();
@@ -76,7 +84,7 @@ public class GroupDaoTest extends AbstractDaoTestCase {
public void insert() {
when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-08").getTime());
- setupData("empty");
+ dbTester.prepareDbUnit(getClass(), "empty.xml");
GroupDto dto = new GroupDto()
.setId(1L)
@@ -86,6 +94,54 @@ public class GroupDaoTest extends AbstractDaoTestCase {
dao.insert(session, dto);
session.commit();
- checkTables("insert", "groups");
+ dbTester.assertDbUnit(getClass(), "insert-result.xml", "groups");
+ }
+
+ @Test
+ public void select_by_query() {
+ dbTester.prepareDbUnit(getClass(), "select_by_query.xml");
+
+ /*
+ * Ordering and paging are not fully tested, case insensitive sort is broken on MySQL
+ */
+
+ // Null query
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 0, 10))
+ .hasSize(5)
+ .extracting("name").containsOnly("customers-group1", "customers-group2", "customers-group3", "SONAR-ADMINS", "sonar-users");
+
+ // Empty query
+ assertThat(new GroupDao(system2).selectByQuery(session, "", 0, 10))
+ .hasSize(5)
+ .extracting("name").containsOnly("customers-group1", "customers-group2", "customers-group3", "SONAR-ADMINS", "sonar-users");
+
+ // Filter on name
+ assertThat(new GroupDao(system2).selectByQuery(session, "sonar", 0, 10))
+ .hasSize(2)
+ .extracting("name").containsOnly("SONAR-ADMINS", "sonar-users");
+
+ // Pagination
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 0, 3))
+ .hasSize(3);
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 3, 3))
+ .hasSize(2);
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 6, 3)).isEmpty();
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 0, 5))
+ .hasSize(5);
+ assertThat(new GroupDao(system2).selectByQuery(session, null, 5, 5)).isEmpty();
+ }
+
+ @Test
+ public void count_by_query() {
+ dbTester.prepareDbUnit(getClass(), "select_by_query.xml");
+
+ // Null query
+ assertThat(new GroupDao(system2).countByQuery(session, null)).isEqualTo(5);
+
+ // Empty query
+ assertThat(new GroupDao(system2).countByQuery(session, "")).isEqualTo(5);
+
+ // Filter on name
+ assertThat(new GroupDao(system2).countByQuery(session, "sonar")).isEqualTo(2);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
new file mode 100644
index 00000000000..9ec90c7554c
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
@@ -0,0 +1,175 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.usergroups.ws;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.user.GroupDto;
+import org.sonar.core.user.GroupMembershipDao;
+import org.sonar.core.user.UserGroupDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.user.db.GroupDao;
+import org.sonar.server.user.db.UserGroupDao;
+import org.sonar.server.ws.WsTester;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class SearchActionTest {
+
+ @ClassRule
+ public static final DbTester dbTester = new DbTester();
+
+ private WsTester tester;
+
+ private GroupDao groupDao;
+
+ private GroupMembershipDao groupMembershipDao;
+
+ private UserGroupDao userGroupDao;
+
+ private DbSession session;
+
+ @Before
+ public void setUp() {
+ dbTester.truncateTables();
+
+ groupDao = new GroupDao(System2.INSTANCE);
+ groupMembershipDao = new GroupMembershipDao(dbTester.myBatis());
+ userGroupDao = new UserGroupDao();
+
+ DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), groupDao, groupMembershipDao);
+
+ tester = new WsTester(new UserGroupsWs(new SearchAction(dbClient)));
+
+ session = dbClient.openSession(false);
+ }
+
+ @After
+ public void after() {
+ session.close();
+ }
+
+ @Test
+ public void search_empty() throws Exception {
+ tester.newGetRequest("api/usergroups", "search").execute().assertJson(getClass(), "empty.json");
+ }
+
+ @Test
+ public void search_without_parameters() throws Exception {
+ insertGroups("users", "admins", "customer1", "customer2", "customer3");
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "search").execute().assertJson(getClass(), "five_groups.json");
+ }
+
+ @Test
+ public void search_with_members() throws Exception {
+ insertGroups("users", "admins", "customer1", "customer2", "customer3");
+ insertMembers("users", 5);
+ insertMembers("admins", 1);
+ insertMembers("customer2", 4);
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "search").execute().assertJson(getClass(), "with_members.json");
+ }
+
+ @Test
+ public void search_with_query() throws Exception {
+ insertGroups("users", "admins", "customer1", "customer2", "customer3");
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "search").setParam(Param.TEXT_QUERY, "custom").execute().assertJson(getClass(), "customers.json");
+ }
+
+ @Test
+ public void search_with_paging() throws Exception {
+ insertGroups("users", "admins", "customer1", "customer2", "customer3");
+ session.commit();
+
+ tester.newGetRequest("api/usergroups", "search")
+ .setParam(Param.PAGE_SIZE, "3").execute().assertJson(getClass(), "page_1.json");
+ tester.newGetRequest("api/usergroups", "search")
+ .setParam(Param.PAGE_SIZE, "3").setParam(Param.PAGE, "2").execute().assertJson(getClass(), "page_2.json");
+ tester.newGetRequest("api/usergroups", "search")
+ .setParam(Param.PAGE_SIZE, "3").setParam(Param.PAGE, "3").execute().assertJson(getClass(), "page_3.json");
+ }
+
+ @Test
+ public void search_with_fields() throws Exception {
+ insertGroups("sonar-users");
+ session.commit();
+
+ assertThat(tester.newGetRequest("api/usergroups", "search").execute().outputAsString())
+ .contains("id")
+ .contains("name")
+ .contains("description")
+ .contains("membersCount");
+
+ assertThat(tester.newGetRequest("api/usergroups", "search").setParam(Param.FIELDS, "").execute().outputAsString())
+ .contains("id")
+ .contains("name")
+ .contains("description")
+ .contains("membersCount");
+
+ assertThat(tester.newGetRequest("api/usergroups", "search").setParam(Param.FIELDS, "name").execute().outputAsString())
+ .contains("id")
+ .contains("name")
+ .doesNotContain("description")
+ .doesNotContain("membersCount");
+
+ assertThat(tester.newGetRequest("api/usergroups", "search").setParam(Param.FIELDS, "description").execute().outputAsString())
+ .contains("id")
+ .doesNotContain("name")
+ .contains("description")
+ .doesNotContain("membersCount");
+
+ assertThat(tester.newGetRequest("api/usergroups", "search").setParam(Param.FIELDS, "membersCount").execute().outputAsString())
+ .contains("id")
+ .doesNotContain("name")
+ .doesNotContain("description")
+ .contains("membersCount");
+ }
+
+ private void insertGroups(String... groupNames) {
+ for (String groupName : groupNames) {
+ groupDao.insert(session, new GroupDto()
+ .setName(groupName)
+ .setDescription(StringUtils.capitalize(groupName)));
+ }
+ }
+
+ private void insertMembers(String groupName, int count) {
+ long groupId = groupDao.selectByKey(session, groupName).getId();
+ for (int i = 0; i < count; i++) {
+ userGroupDao.insert(session, new UserGroupDto().setGroupId(groupId).setUserId((long) i + 1));
+ }
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
new file mode 100644
index 00000000000..ad4ff6c6bfc
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UserGroupsWsTest.java
@@ -0,0 +1,61 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.usergroups.ws;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class UserGroupsWsTest {
+ @Rule
+ public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ WebService.Controller controller;
+
+ @Before
+ public void setUp() {
+ WsTester tester = new WsTester(new UserGroupsWs(new SearchAction(mock(DbClient.class))));
+ controller = tester.controller("api/usergroups");
+ }
+
+ @Test
+ public void define_controller() {
+ assertThat(controller).isNotNull();
+ assertThat(controller.description()).isNotEmpty();
+ assertThat(controller.since()).isEqualTo("5.2");
+ assertThat(controller.actions()).hasSize(1);
+ }
+
+ @Test
+ public void define_search_action() {
+ WebService.Action action = controller.action("search");
+ assertThat(action).isNotNull();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params()).hasSize(4);
+ }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/select_by_query.xml b/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/select_by_query.xml
new file mode 100644
index 00000000000..983f6ad9980
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/user/db/GroupDaoTest/select_by_query.xml
@@ -0,0 +1,9 @@
+<dataset>
+
+ <groups id="1" name="sonar-users" description="Sonar Users" created_at="2014-09-07" updated_at="2014-09-08"/>
+ <groups id="2" name="SONAR-ADMINS" description="Sonar Admins" created_at="2014-09-07" updated_at="2014-09-08"/>
+ <groups id="3" name="customers-group1" description="Group 1" created_at="2014-09-07" updated_at="2014-09-08"/>
+ <groups id="4" name="customers-group2" description="Group 2" created_at="2014-09-07" updated_at="2014-09-08"/>
+ <groups id="5" name="customers-group3" description="Group 3" created_at="2014-09-07" updated_at="2014-09-08"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/customers.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/customers.json
new file mode 100644
index 00000000000..b94a0072af9
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/customers.json
@@ -0,0 +1,10 @@
+{
+ "p": 1,
+ "ps": 100,
+ "total": 3,
+ "groups": [
+ {"name": "customer1", "description": "Customer1", "membersCount": 0},
+ {"name": "customer2", "description": "Customer2", "membersCount": 0},
+ {"name": "customer3", "description": "Customer3", "membersCount": 0}
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/empty.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/empty.json
new file mode 100644
index 00000000000..ef5440a6563
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/empty.json
@@ -0,0 +1,6 @@
+{
+ "p": 1,
+ "ps": 100,
+ "total": 0,
+ "groups": []
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/five_groups.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/five_groups.json
new file mode 100644
index 00000000000..0bd50502fb5
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/five_groups.json
@@ -0,0 +1,12 @@
+{
+ "p": 1,
+ "ps": 100,
+ "total": 5,
+ "groups": [
+ {"name": "admins", "description": "Admins", "membersCount": 0},
+ {"name": "customer1", "description": "Customer1", "membersCount": 0},
+ {"name": "customer2", "description": "Customer2", "membersCount": 0},
+ {"name": "customer3", "description": "Customer3", "membersCount": 0},
+ {"name": "users", "description": "Users", "membersCount": 0}
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_1.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_1.json
new file mode 100644
index 00000000000..b9834b6865f
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_1.json
@@ -0,0 +1,10 @@
+{
+ "p": 1,
+ "ps": 3,
+ "total": 5,
+ "groups": [
+ {"name": "admins", "description": "Admins", "membersCount": 0},
+ {"name": "customer1", "description": "Customer1", "membersCount": 0},
+ {"name": "customer2", "description": "Customer2", "membersCount": 0}
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_2.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_2.json
new file mode 100644
index 00000000000..60e051d1278
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_2.json
@@ -0,0 +1,9 @@
+{
+ "p": 2,
+ "ps": 3,
+ "total": 5,
+ "groups": [
+ {"name": "customer3", "description": "Customer3", "membersCount": 0},
+ {"name": "users", "description": "Users", "membersCount": 0}
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_3.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_3.json
new file mode 100644
index 00000000000..c9775574e61
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/page_3.json
@@ -0,0 +1,6 @@
+{
+ "p": 3,
+ "ps": 3,
+ "total": 5,
+ "groups": []
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/with_members.json b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/with_members.json
new file mode 100644
index 00000000000..205c89e8603
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/usergroups/ws/SearchActionTest/with_members.json
@@ -0,0 +1,12 @@
+{
+ "p": 1,
+ "ps": 100,
+ "total": 5,
+ "groups": [
+ {"name": "admins", "description": "Admins", "membersCount": 1},
+ {"name": "customer1", "description": "Customer1", "membersCount": 0},
+ {"name": "customer2", "description": "Customer2", "membersCount": 4},
+ {"name": "customer3", "description": "Customer3", "membersCount": 0},
+ {"name": "users", "description": "Users", "membersCount": 5}
+ ]
+}