From: Teryk Bellahsene Date: Mon, 18 Jan 2016 11:12:39 +0000 (+0100) Subject: SONAR-7205 WS users/search with token count in response X-Git-Tag: 5.4-M8~3 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fpull%2F721%2Fhead;p=sonarqube.git SONAR-7205 WS users/search with token count in response --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java index c7f84c9d2b8..270a336fe3f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/SearchAction.java @@ -21,10 +21,12 @@ package org.sonar.server.user.ws; import com.google.common.base.Function; import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.sonar.api.server.ws.Request; @@ -32,14 +34,14 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.text.JsonWriter; -import org.sonar.db.DbSession; -import org.sonar.db.MyBatis; import org.sonar.db.DbClient; +import org.sonar.db.DbSession; import org.sonar.server.es.SearchOptions; import org.sonar.server.es.SearchResult; import org.sonar.server.user.index.UserDoc; import org.sonar.server.user.index.UserIndex; +import static com.google.common.base.Objects.firstNonNull; import static org.sonar.server.es.SearchOptions.MAX_LIMIT; public class SearchAction implements UsersWsAction { @@ -60,7 +62,7 @@ public class SearchAction implements UsersWsAction { .setDescription("Get a list of active users. Administer System permission is required to show the 'groups' field.") .setSince("3.6") .setHandler(this) - .setResponseExample(getClass().getResource("example-search.json")); + .setResponseExample(getClass().getResource("search-example.json")); action.addFieldsParam(UserJsonWriter.FIELDS); action.addPagingParams(50, MAX_LIMIT); @@ -77,31 +79,34 @@ public class SearchAction implements UsersWsAction { SearchResult result = userIndex.search(request.param(Param.TEXT_QUERY), options); Multimap groupsByLogin = ArrayListMultimap.create(); + Map tokenCountsByLogin = new HashMap<>(); DbSession dbSession = dbClient.openSession(false); try { - Collection logins = Collections2.transform(result.getDocs(), new Function() { + List logins = Lists.transform(result.getDocs(), new Function() { @Override public String apply(@Nonnull UserDoc input) { return input.login(); } }); groupsByLogin = dbClient.groupMembershipDao().selectGroupsByLogins(dbSession, logins); + tokenCountsByLogin = dbClient.userTokenDao().countTokensByLogins(dbSession, logins); } finally { - MyBatis.closeQuietly(dbSession); + dbClient.closeSession(dbSession); } JsonWriter json = response.newJsonWriter().beginObject(); options.writeJson(json, result.getTotal()); - writeUsers(json, result, fields, groupsByLogin); + writeUsers(json, result, groupsByLogin, tokenCountsByLogin, fields); json.endObject().close(); } - private void writeUsers(JsonWriter json, SearchResult result, @Nullable List fields, Multimap groupsByLogin) { + private void writeUsers(JsonWriter json, SearchResult result, Multimap groupsByLogin, Map tokenCountsByLogin, + @Nullable List fields) { json.name("users").beginArray(); for (UserDoc user : result.getDocs()) { Collection groups = groupsByLogin.get(user.login()); - userWriter.write(json, user, groups, fields); + userWriter.write(json, user, firstNonNull(tokenCountsByLogin.get(user.login()), 0), groups, fields); } json.endArray(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java index c9d730da357..e19fbdba8aa 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserJsonWriter.java @@ -40,6 +40,7 @@ public class UserJsonWriter { private static final String FIELD_SCM_ACCOUNTS = "scmAccounts"; private static final String FIELD_GROUPS = "groups"; private static final String FIELD_ACTIVE = "active"; + private static final String FIELD_TOKEN_COUNT = "tokenCount"; public static final Set FIELDS = ImmutableSet.of(FIELD_NAME, FIELD_EMAIL, FIELD_SCM_ACCOUNTS, FIELD_GROUPS, FIELD_ACTIVE); private static final Set CONCISE_FIELDS = ImmutableSet.of(FIELD_NAME, FIELD_EMAIL, FIELD_ACTIVE); @@ -53,7 +54,14 @@ public class UserJsonWriter { /** * Serializes a user to the passed JsonWriter. */ - public void write(JsonWriter json, User user, Collection groups, Collection fields) { + public void write(JsonWriter json, User user, Collection groups, @Nullable Collection fields) { + write(json, user, null, groups, fields); + } + + /** + * Serializes a user to the passed JsonWriter. + */ + public void write(JsonWriter json, User user, @Nullable Integer tokenCount, Collection groups, @Nullable Collection fields) { json.beginObject(); json.prop(FIELD_LOGIN, user.login()); writeIfNeeded(json, user.name(), FIELD_NAME, fields); @@ -61,6 +69,7 @@ public class UserJsonWriter { writeIfNeeded(json, user.active(), FIELD_ACTIVE, fields); writeGroupsIfNeeded(json, groups, fields); writeScmAccountsIfNeeded(json, fields, user); + writeTokenCount(json, tokenCount); json.endObject(); } @@ -93,4 +102,12 @@ public class UserJsonWriter { .endArray(); } } + + private static void writeTokenCount(JsonWriter json, @Nullable Integer tokenCount) { + if (tokenCount == null) { + return; + } + + json.prop(FIELD_TOKEN_COUNT, tokenCount); + } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-search.json deleted file mode 100644 index 39448ce788d..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/user/ws/example-search.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "users": [ - { - "login": "fmallet", - "name": "Freddy Mallet", - "active": true, - "email": "f@m.com", - "scmAccounts": [], - "groups": ["sonar-users", "sonar-administrators"] - }, - { - "login": "sbrandhof", - "name": "Simon", - "active": true, - "email": "s.brandhof@company.tld", - "scmAccounts": ["simon.brandhof", "s.brandhof@company.tld"], - "groups": ["sonar-users"] - } - ] -} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/user/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/user/ws/search-example.json new file mode 100644 index 00000000000..43f791d247f --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/user/ws/search-example.json @@ -0,0 +1,30 @@ +{ + "users": [ + { + "login": "fmallet", + "name": "Freddy Mallet", + "active": true, + "email": "f@m.com", + "scmAccounts": [], + "groups": [ + "sonar-users", + "sonar-administrators" + ], + "tokenCount": 1 + }, + { + "login": "sbrandhof", + "name": "Simon", + "active": true, + "email": "s.brandhof@company.tld", + "scmAccounts": [ + "simon.brandhof", + "s.brandhof@company.tld" + ], + "groups": [ + "sonar-users" + ], + "tokenCount": 3 + } + ] +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java index 50a89ef02d0..24689abde3d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/SearchActionTest.java @@ -20,136 +20,109 @@ package org.sonar.server.user.ws; import com.google.common.collect.Lists; -import java.util.Arrays; import java.util.List; -import org.junit.After; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.sonar.api.config.Settings; -import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.System2; import org.sonar.core.permission.GlobalPermissions; +import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.user.GroupDto; -import org.sonar.db.user.GroupMembershipDao; import org.sonar.db.user.UserDto; -import org.sonar.db.user.UserGroupDao; import org.sonar.db.user.UserGroupDto; -import org.sonar.server.db.DbClient; import org.sonar.server.es.EsTester; import org.sonar.server.tester.UserSessionRule; -import org.sonar.db.user.GroupDao; -import org.sonar.db.user.UserDao; import org.sonar.server.user.index.UserDoc; import org.sonar.server.user.index.UserIndex; import org.sonar.server.user.index.UserIndexDefinition; import org.sonar.server.ws.WsTester; import org.sonar.test.DbTests; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.user.UserTokenTesting.newUserToken; @Category(DbTests.class) public class SearchActionTest { - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - @ClassRule public static final EsTester esTester = new EsTester().addDefinitions(new UserIndexDefinition(new Settings())); - @Rule public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + DbClient dbClient = db.getDbClient(); + DbSession dbSession = db.getSession(); - WebService.Controller controller; - - WsTester tester; - + WsTester ws; UserIndex index; - DbClient dbClient; - - DbSession session; - @Before public void setUp() { - dbTester.truncateTables(); esTester.truncateIndices(); - - dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), - new GroupMembershipDao(dbTester.myBatis()), - new UserDao(dbTester.myBatis(), new System2()), - new GroupDao(new System2()), - new UserGroupDao()); - session = dbClient.openSession(false); - index = new UserIndex(esTester.client()); - tester = new WsTester(new UsersWs(new SearchAction(index, dbClient, new UserJsonWriter(userSession)))); - controller = tester.controller("api/users"); - } - - @After - public void tearDown() { - session.close(); + ws = new WsTester(new UsersWs(new SearchAction(index, dbClient, new UserJsonWriter(userSession)))); } @Test public void search_empty() throws Exception { - tester.newGetRequest("api/users", "search").execute().assertJson(getClass(), "empty.json"); + ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "empty.json"); } @Test public void search_without_parameters() throws Exception { injectUsers(5); - tester.newGetRequest("api/users", "search").execute().assertJson(getClass(), "five_users.json"); + ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "five_users.json"); } @Test public void search_with_query() throws Exception { injectUsers(5); - tester.newGetRequest("api/users", "search").setParam("q", "user-1").execute().assertJson(getClass(), "user_one.json"); + ws.newGetRequest("api/users", "search").setParam("q", "user-1").execute().assertJson(getClass(), "user_one.json"); } @Test public void search_with_paging() throws Exception { injectUsers(10); - tester.newGetRequest("api/users", "search").setParam(Param.PAGE_SIZE, "5").execute().assertJson(getClass(), "page_one.json"); - tester.newGetRequest("api/users", "search").setParam(Param.PAGE_SIZE, "5").setParam(Param.PAGE, "2").execute().assertJson(getClass(), "page_two.json"); + ws.newGetRequest("api/users", "search").setParam(Param.PAGE_SIZE, "5").execute().assertJson(getClass(), "page_one.json"); + ws.newGetRequest("api/users", "search").setParam(Param.PAGE_SIZE, "5").setParam(Param.PAGE, "2").execute().assertJson(getClass(), "page_two.json"); } @Test public void search_with_fields() throws Exception { injectUsers(1); - assertThat(tester.newGetRequest("api/users", "search").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").execute().outputAsString()) .contains("login") .contains("name") .contains("email") .contains("scmAccounts") .doesNotContain("groups"); - assertThat(tester.newGetRequest("api/users", "search").setParam(Param.FIELDS, "").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").setParam(Param.FIELDS, "").execute().outputAsString()) .contains("login") .contains("name") .contains("email") .contains("scmAccounts") .doesNotContain("groups"); - assertThat(tester.newGetRequest("api/users", "search").setParam(Param.FIELDS, "scmAccounts").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").setParam(Param.FIELDS, "scmAccounts").execute().outputAsString()) .contains("login") .doesNotContain("name") .doesNotContain("email") .contains("scmAccounts") .doesNotContain("groups"); - assertThat(tester.newGetRequest("api/users", "search").setParam(Param.FIELDS, "groups").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").setParam(Param.FIELDS, "groups").execute().outputAsString()) .contains("login") .doesNotContain("name") .doesNotContain("email") @@ -158,14 +131,14 @@ public class SearchActionTest { loginAsAdmin(); - assertThat(tester.newGetRequest("api/users", "search").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").execute().outputAsString()) .contains("login") .contains("name") .contains("email") .contains("scmAccounts") .contains("groups"); - assertThat(tester.newGetRequest("api/users", "search").setParam(Param.FIELDS, "groups").execute().outputAsString()) + assertThat(ws.newGetRequest("api/users", "search").setParam(Param.FIELDS, "groups").execute().outputAsString()) .contains("login") .doesNotContain("name") .doesNotContain("email") @@ -177,14 +150,14 @@ public class SearchActionTest { public void search_with_groups() throws Exception { List users = injectUsers(1); - GroupDto group1 = dbClient.groupDao().insert(session, new GroupDto().setName("sonar-users")); - GroupDto group2 = dbClient.groupDao().insert(session, new GroupDto().setName("sonar-admins")); - dbClient.userGroupDao().insert(session, new UserGroupDto().setGroupId(group1.getId()).setUserId(users.get(0).getId())); - dbClient.userGroupDao().insert(session, new UserGroupDto().setGroupId(group2.getId()).setUserId(users.get(0).getId())); - session.commit(); + GroupDto group1 = dbClient.groupDao().insert(dbSession, new GroupDto().setName("sonar-users")); + GroupDto group2 = dbClient.groupDao().insert(dbSession, new GroupDto().setName("sonar-admins")); + dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setGroupId(group1.getId()).setUserId(users.get(0).getId())); + dbClient.userGroupDao().insert(dbSession, new UserGroupDto().setGroupId(group2.getId()).setUserId(users.get(0).getId())); + dbSession.commit(); loginAsAdmin(); - tester.newGetRequest("api/users", "search").execute().assertJson(getClass(), "user_with_groups.json"); + ws.newGetRequest("api/users", "search").execute().assertJson(getClass(), "user_with_groups.json"); } private List injectUsers(int numberOfUsers) throws Exception { @@ -195,9 +168,9 @@ public class SearchActionTest { String email = String.format("user-%d@mail.com", index); String login = String.format("user-%d", index); String name = String.format("User %d", index); - List scmAccounts = Arrays.asList(String.format("user-%d", index)); + List scmAccounts = singletonList(String.format("user-%d", index)); - userDtos.add(dbClient.userDao().insert(session, new UserDto() + userDtos.add(dbClient.userDao().insert(dbSession, new UserDto() .setActive(true) .setCreatedAt(createdAt) .setEmail(email) @@ -214,8 +187,14 @@ public class SearchActionTest { .setName(name) .setScmAccounts(scmAccounts) .setUpdatedAt(createdAt); + + for (int tokenIndex = 0; tokenIndex < index; tokenIndex++) { + dbClient.userTokenDao().insert(dbSession, newUserToken() + .setLogin(login) + .setName(String.format("%s-%d", login, tokenIndex))); + } } - session.commit(); + dbSession.commit(); esTester.putDocuments(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER, users); return userDtos; } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/five_users.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/five_users.json index 88a6fec9ecb..576b41ad6ce 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/five_users.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/five_users.json @@ -9,7 +9,8 @@ "email": "user-0@mail.com", "scmAccounts": [ "user-0" - ] + ], + "tokenCount": 0 }, { "login": "user-1", @@ -17,7 +18,8 @@ "email": "user-1@mail.com", "scmAccounts": [ "user-1" - ] + ], + "tokenCount": 1 }, { "login": "user-2", @@ -25,7 +27,8 @@ "email": "user-2@mail.com", "scmAccounts": [ "user-2" - ] + ], + "tokenCount": 2 }, { "login": "user-3", @@ -33,7 +36,8 @@ "email": "user-3@mail.com", "scmAccounts": [ "user-3" - ] + ], + "tokenCount": 3 }, { "login": "user-4", @@ -41,7 +45,8 @@ "email": "user-4@mail.com", "scmAccounts": [ "user-4" - ] + ], + "tokenCount": 4 } ] } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/user_one.json b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/user_one.json index 3c5b27e9552..2f3d06e9ac6 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/user_one.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/user/ws/SearchActionTest/user_one.json @@ -9,7 +9,8 @@ "email": "user-1@mail.com", "scmAccounts": [ "user-1" - ] + ], + "tokenCount": 1 } ] } diff --git a/sonar-db/src/main/java/org/sonar/db/MyBatis.java b/sonar-db/src/main/java/org/sonar/db/MyBatis.java index 23065bfde9d..9cf94000504 100644 --- a/sonar-db/src/main/java/org/sonar/db/MyBatis.java +++ b/sonar-db/src/main/java/org/sonar/db/MyBatis.java @@ -126,6 +126,7 @@ import org.sonar.db.user.UserGroupDto; import org.sonar.db.user.UserGroupMapper; import org.sonar.db.user.UserMapper; import org.sonar.db.user.UserRoleDto; +import org.sonar.db.user.UserTokenCount; import org.sonar.db.user.UserTokenDto; import org.sonar.db.user.UserTokenMapper; import org.sonar.db.version.SchemaMigrationDto; @@ -216,6 +217,7 @@ public class MyBatis { confBuilder.loadAlias("CustomMeasure", CustomMeasureDto.class); confBuilder.loadAlias("ViewsSnapshot", ViewsSnapshotDto.class); confBuilder.loadAlias("UserToken", UserTokenDto.class); + confBuilder.loadAlias("UserTokenCount", UserTokenCount.class); // AuthorizationMapper has to be loaded before IssueMapper because this last one used it confBuilder.loadMapper("org.sonar.db.user.AuthorizationMapper"); diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserTokenCount.java b/sonar-db/src/main/java/org/sonar/db/user/UserTokenCount.java new file mode 100644 index 00000000000..44896754915 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/user/UserTokenCount.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program 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. + * + * This program 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.db.user; + +public class UserTokenCount { + private String login; + private Integer tokenCount; + + public String getLogin() { + return login; + } + + public UserTokenCount setLogin(String login) { + this.login = login; + return this; + } + + public Integer tokenCount() { + return tokenCount; + } + + public UserTokenCount setTokenCount(Integer tokenCount) { + this.tokenCount = tokenCount; + return this; + } +} diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserTokenDao.java b/sonar-db/src/main/java/org/sonar/db/user/UserTokenDao.java index eb494dc983d..ff6a69c0bed 100644 --- a/sonar-db/src/main/java/org/sonar/db/user/UserTokenDao.java +++ b/sonar-db/src/main/java/org/sonar/db/user/UserTokenDao.java @@ -19,9 +19,14 @@ */ package org.sonar.db.user; +import com.google.common.base.Function; import com.google.common.base.Optional; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; import org.sonar.db.Dao; +import org.sonar.db.DatabaseUtils; import org.sonar.db.DbSession; import org.sonar.db.RowNotFoundException; @@ -53,6 +58,22 @@ public class UserTokenDao implements Dao { return mapper(dbSession).selectByLogin(login); } + public Map countTokensByLogins(final DbSession dbSession, List logins) { + final Map result = new HashMap<>(); + DatabaseUtils.executeLargeInputs(logins, new Function, List>() { + @Override + public List apply(@Nonnull List input) { + List userTokenCounts = mapper(dbSession).countTokensByLogins(input); + for (UserTokenCount userTokenCount : userTokenCounts) { + result.put(userTokenCount.getLogin(), userTokenCount.tokenCount()); + } + return userTokenCounts; + } + }); + + return result; + } + public void deleteByLogin(DbSession dbSession, String login) { mapper(dbSession).deleteByLogin(login); } diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserTokenMapper.java b/sonar-db/src/main/java/org/sonar/db/user/UserTokenMapper.java index f8ace95818f..bb814b86e4c 100644 --- a/sonar-db/src/main/java/org/sonar/db/user/UserTokenMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/user/UserTokenMapper.java @@ -34,4 +34,6 @@ public interface UserTokenMapper { void deleteByLogin(String login); void deleteByLoginAndName(@Param("login") String login, @Param("name") String name); + + List countTokensByLogins(@Param("logins") List logins); } diff --git a/sonar-db/src/main/resources/org/sonar/db/user/UserTokenMapper.xml b/sonar-db/src/main/resources/org/sonar/db/user/UserTokenMapper.xml index 1b74df52c2a..3078c44137e 100644 --- a/sonar-db/src/main/resources/org/sonar/db/user/UserTokenMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/user/UserTokenMapper.xml @@ -35,6 +35,16 @@ FROM user_tokens t WHERE t.login=#{login} + + DELETE FROM user_tokens WHERE login=#{login} diff --git a/sonar-db/src/test/java/org/sonar/db/user/UserTokenDaoTest.java b/sonar-db/src/test/java/org/sonar/db/user/UserTokenDaoTest.java index 9b25fe6c28f..bfe27081188 100644 --- a/sonar-db/src/test/java/org/sonar/db/user/UserTokenDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/user/UserTokenDaoTest.java @@ -20,6 +20,7 @@ package org.sonar.db.user; import com.google.common.base.Optional; +import java.util.Map; import org.assertj.guava.api.Assertions; import org.junit.Before; import org.junit.Rule; @@ -32,6 +33,7 @@ import org.sonar.db.DbTester; import org.sonar.db.RowNotFoundException; import org.sonar.test.DbTests; +import static com.google.common.collect.Lists.newArrayList; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.db.user.UserTokenTesting.newUserToken; @@ -129,6 +131,17 @@ public class UserTokenDaoTest { Assertions.assertThat(underTest.selectByLoginAndName(dbSession, "another-login", "name")).isPresent(); } + @Test + public void count_tokens_by_login() { + insertToken(newUserToken().setLogin("login").setName("name")); + insertToken(newUserToken().setLogin("login").setName("another-name")); + + Map result = underTest.countTokensByLogins(dbSession, newArrayList("login")); + + assertThat(result.get("login")).isEqualTo(2); + assertThat(result.get("unknown-login")).isNull(); + } + private void insertToken(UserTokenDto userToken) { underTest.insert(dbSession, userToken); dbSession.commit();