diff options
25 files changed, 480 insertions, 251 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/AppAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/AppAction.java index 1025d1cd68b..bf5684b918e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/AppAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/AppAction.java @@ -29,15 +29,15 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.db.issue.IssueFilterDto; import org.sonar.server.user.UserSession; +import static org.sonar.server.issue.filter.IssueFilterJsonWriter.writeWithName; + public class AppAction implements IssueFilterWsAction { private final IssueFilterService service; - private final IssueFilterJsonWriter issueFilterJsonWriter; private final UserSession userSession; - public AppAction(IssueFilterService service, IssueFilterJsonWriter issueFilterJsonWriter, UserSession userSession) { + public AppAction(IssueFilterService service, UserSession userSession) { this.service = service; - this.issueFilterJsonWriter = issueFilterJsonWriter; this.userSession = userSession; } @@ -72,7 +72,7 @@ public class AppAction implements IssueFilterWsAction { // Selected filter if (filter != null) { - issueFilterJsonWriter.writeWithName(json, filter, userSession); + writeWithName(json, filter, userSession); } // Favorite filters, if logged in diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterJsonWriter.java index 18a95ace3c2..272f4614acb 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterJsonWriter.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterJsonWriter.java @@ -21,31 +21,41 @@ package org.sonar.server.issue.filter; import org.apache.commons.lang.StringUtils; -import org.sonar.api.server.ServerSide; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.permission.GlobalPermissions; import org.sonar.db.issue.IssueFilterDto; import org.sonar.server.user.UserSession; -@ServerSide -public class IssueFilterJsonWriter { +import static com.google.common.base.Objects.firstNonNull; - void writeWithName(JsonWriter json, IssueFilterDto filter, UserSession userSession) { +class IssueFilterJsonWriter { + + private static final String DEFAULT_LOGIN = "[SonarQube]"; + + private IssueFilterJsonWriter() { + // static methods only + } + + static void writeWithName(JsonWriter json, IssueFilterDto filter, UserSession userSession) { json.name("filter"); - write(json, filter, userSession); + write(json, new IssueFilterWithFavourite(filter, null), userSession); } - void write(JsonWriter json, IssueFilterDto filter, UserSession userSession) { + static void write(JsonWriter json, IssueFilterWithFavourite issueFilterWithFavourite, UserSession userSession) { + IssueFilterDto issueFilter = issueFilterWithFavourite.issueFilter(); json .beginObject() - .prop("id", filter.getId()) - .prop("name", filter.getName()) - .prop("description", filter.getDescription()) - .prop("user", filter.getUserLogin()) - .prop("shared", filter.isShared()) - .prop("query", filter.getData()) - .prop("canModify", canModifyFilter(userSession, filter)) - .endObject(); + .prop("id", String.valueOf(issueFilter.getId())) + .prop("name", issueFilter.getName()) + .prop("description", issueFilter.getDescription()) + .prop("user", firstNonNull(issueFilter.getUserLogin(), DEFAULT_LOGIN)) + .prop("shared", issueFilter.isShared()) + .prop("query", issueFilter.getData()) + .prop("canModify", canModifyFilter(userSession, issueFilter)); + if (issueFilterWithFavourite.isFavourite() != null) { + json.prop("favourite", issueFilterWithFavourite.isFavourite()); + } + json.endObject(); } private static boolean canModifyFilter(UserSession userSession, IssueFilterDto filter) { diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java index 9fd4b46929c..c785ae18e11 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java @@ -31,6 +31,7 @@ import javax.annotation.Nonnull; import org.sonar.api.server.ServerSide; import org.sonar.api.utils.Paging; import org.sonar.core.permission.GlobalPermissions; +import org.sonar.db.DbClient; import org.sonar.db.issue.IssueFilterDao; import org.sonar.db.issue.IssueFilterDto; import org.sonar.db.issue.IssueFilterFavouriteDao; @@ -58,13 +59,11 @@ public class IssueFilterService { private final AuthorizationDao authorizationDao; private final IssueFilterSerializer serializer; - public IssueFilterService(IssueFilterDao filterDao, IssueFilterFavouriteDao favouriteDao, - IssueIndex issueIndex, AuthorizationDao authorizationDao, - IssueFilterSerializer serializer) { - this.filterDao = filterDao; - this.favouriteDao = favouriteDao; + public IssueFilterService(DbClient dbClient, IssueIndex issueIndex, IssueFilterSerializer serializer) { + this.filterDao = dbClient.issueFilterDao(); + this.favouriteDao = dbClient.issueFilterFavouriteDao(); + this.authorizationDao = dbClient.authorizationDao(); this.issueIndex = issueIndex; - this.authorizationDao = authorizationDao; this.serializer = serializer; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterWithFavourite.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterWithFavourite.java new file mode 100644 index 00000000000..b0dc2b05245 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterWithFavourite.java @@ -0,0 +1,43 @@ +/* + * 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.issue.filter; + +import javax.annotation.Nullable; +import org.sonar.db.issue.IssueFilterDto; + +public class IssueFilterWithFavourite { + private final IssueFilterDto issueFilter; + private final Boolean isFavourite; + + public IssueFilterWithFavourite(IssueFilterDto issueFilter, Boolean isFavourite) { + this.issueFilter = issueFilter; + this.isFavourite = isFavourite; + } + + public IssueFilterDto issueFilter() { + return issueFilter; + } + + @Nullable + public Boolean isFavourite() { + return isFavourite; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/SearchAction.java index 7d36b7e6bad..71ee8891613 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/SearchAction.java @@ -20,27 +20,32 @@ package org.sonar.server.issue.filter; +import com.google.common.base.Function; import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.io.Resources; +import com.google.common.collect.Maps; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nonnull; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.issue.IssueFilterDao; import org.sonar.db.issue.IssueFilterDto; +import org.sonar.db.issue.IssueFilterFavouriteDto; import org.sonar.server.user.UserSession; public class SearchAction implements IssueFilterWsAction { - private final IssueFilterService service; - private final IssueFilterJsonWriter issueFilterJsonWriter; + private final DbClient dbClient; private final UserSession userSession; - public SearchAction(IssueFilterService service, IssueFilterJsonWriter issueFilterJsonWriter, UserSession userSession) { - this.service = service; - this.issueFilterJsonWriter = issueFilterJsonWriter; + public SearchAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; this.userSession = userSession; } @@ -48,35 +53,61 @@ public class SearchAction implements IssueFilterWsAction { public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("search"); action - .setDescription("Get the list of favorite issue filters.") - .setInternal(false) + .setDescription("List of current user issue filters and shared issue filters.") .setHandler(this) .setSince("5.2") - .setResponseExample(Resources.getResource(this.getClass(), "example-search.json")); + .setResponseExample(getClass().getResource("search-example.json")); } @Override public void handle(Request request, Response response) throws Exception { + userSession.checkLoggedIn(); + + DbSession dbSession = dbClient.openSession(false); + try { + Set<IssueFilterDto> issueFilters = searchIssueFilters(dbSession); + Map<Long, IssueFilterFavouriteDto> userFavouritesByFilterId = searchUserFavouritesByFilterId(dbSession); + writeResponse(response, issueFilters, userFavouritesByFilterId); + } finally { + dbClient.closeSession(dbSession); + } + } + + private void writeResponse(Response response, Set<IssueFilterDto> issueFilters, Map<Long, IssueFilterFavouriteDto> userFavouritesByFilterId) { JsonWriter json = response.newJsonWriter(); json.beginObject(); - - // Favorite filters, if logged in - if (userSession.isLoggedIn()) { - List<IssueFilterDto> filters = service.findFavoriteFilters(userSession); - List<IssueFilterDto> sharedFiltersWithoutUserFilters = service.findSharedFiltersWithoutUserFilters(userSession); - filters.addAll(sharedFiltersWithoutUserFilters); - ImmutableSortedSet<IssueFilterDto> allUniqueIssueFilters = FluentIterable.from(filters).toSortedSet(IssueFilterDtoIdComparator.INSTANCE); - json.name("issueFilters").beginArray(); - for (IssueFilterDto favorite : allUniqueIssueFilters) { - issueFilterJsonWriter.write(json, favorite, userSession); - } - json.endArray(); + json.name("issueFilters").beginArray(); + for (IssueFilterDto issueFilter : issueFilters) { + IssueFilterJsonWriter.write(json, new IssueFilterWithFavourite(issueFilter, isFavourite(issueFilter, userFavouritesByFilterId)), userSession); } + json.endArray(); json.endObject(); json.close(); } + private static boolean isFavourite(IssueFilterDto issueFilter, Map<Long, IssueFilterFavouriteDto> userFavouritesByFilterId) { + return userFavouritesByFilterId.get(issueFilter.getId()) != null; + } + + /** + * @return all the current user issue filters and all the shared filters + */ + private Set<IssueFilterDto> searchIssueFilters(DbSession dbSession) { + IssueFilterDao issueFilterDao = dbClient.issueFilterDao(); + + List<IssueFilterDto> filters = issueFilterDao.selectByUser(dbSession, userSession.getLogin()); + List<IssueFilterDto> sharedFilters = issueFilterDao.selectSharedFilters(dbSession); + filters.addAll(sharedFilters); + + return FluentIterable.from(filters).toSortedSet(IssueFilterDtoIdComparator.INSTANCE); + } + + private Map<Long, IssueFilterFavouriteDto> searchUserFavouritesByFilterId(DbSession dbSession) { + List<IssueFilterFavouriteDto> favouriteFilters = dbClient.issueFilterFavouriteDao().selectByUser(dbSession, userSession.getLogin()); + return Maps.uniqueIndex(favouriteFilters, IssueFilterFavouriteDToIssueFilterId.INSTANCE); + } + private enum IssueFilterDtoIdComparator implements Comparator<IssueFilterDto> { INSTANCE; @@ -85,4 +116,13 @@ public class SearchAction implements IssueFilterWsAction { return o1.getId().intValue() - o2.getId().intValue(); } } + + private enum IssueFilterFavouriteDToIssueFilterId implements Function<IssueFilterFavouriteDto, Long> { + INSTANCE; + + @Override + public Long apply(@Nonnull IssueFilterFavouriteDto filterFavourite) { + return filterFavourite.getIssueFilterId(); + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/ShowAction.java index b9fdfe884fc..2bbdfabe898 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/filter/ShowAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/filter/ShowAction.java @@ -28,15 +28,15 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.db.issue.IssueFilterDto; import org.sonar.server.user.UserSession; +import static org.sonar.server.issue.filter.IssueFilterJsonWriter.writeWithName; + public class ShowAction implements IssueFilterWsAction { private final IssueFilterService service; - private final IssueFilterJsonWriter issueFilterJsonWriter; private final UserSession userSession; - public ShowAction(IssueFilterService service, IssueFilterJsonWriter issueFilterJsonWriter, UserSession userSession) { + public ShowAction(IssueFilterService service, UserSession userSession) { this.service = service; - this.issueFilterJsonWriter = issueFilterJsonWriter; this.userSession = userSession; } @@ -59,7 +59,7 @@ public class ShowAction implements IssueFilterWsAction { JsonWriter json = response.newJsonWriter(); json.beginObject(); - issueFilterJsonWriter.writeWithName(json, filter, userSession); + writeWithName(json, filter, userSession); json.endObject(); json.close(); } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-app.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-app.json index 982d0ef6460..995830aa84b 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-app.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-app.json @@ -2,7 +2,7 @@ "canManageFilters": true, "canBulkChange": true, "filter": { - "id": 8, + "id": "8", "name": "My Issues To Fix", "description": "", "user": "john.snow", @@ -12,11 +12,11 @@ }, "favorites": [ { - "id": 8, + "id": "8", "name": "My Issues To Fix" }, { - "id": 22, + "id": "22", "name": "SonarQube Issues" } ] diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-search.json deleted file mode 100644 index ff666a72a78..00000000000 --- a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-search.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "issueFilters": [ - { - "id": 3, - "name": "My Unresolved Issues", - "shared": true, - "query": "resolved=false|assignees=__me__", - "canModify": true - }, - { - "id": 2, - "name": "False Positive and Won't Fix Issues", - "shared": true, - "query": "resolutions=FALSE-POSITIVE,WONTFIX", - "canModify": true - }, - { - "id": 1, - "name": "Unresolved Issues", - "shared": true, - "query": "resolved=false", - "canModify": true - } - ] -} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-show.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-show.json index e7f6e7a691f..aba2f2f6670 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-show.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/example-show.json @@ -1,6 +1,6 @@ { "filter": { - "id": 1, + "id": "1", "name": "My Filter", "user": "admin", "shared": true, diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/search-example.json new file mode 100644 index 00000000000..cb981b8211d --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/filter/search-example.json @@ -0,0 +1,40 @@ +{ + "issueFilters": [ + { + "id": "3", + "name": "My Unresolved Issues", + "shared": true, + "query": "resolved=false|assignees=__me__", + "user": "[SonarQube]", + "canModify": false, + "favourite": true + }, + { + "id": "2", + "name": "False Positive and Won't Fix Issues", + "shared": true, + "query": "resolutions=FALSE-POSITIVE,WONTFIX", + "user": "[SonarQube]", + "canModify": false, + "favourite": false + }, + { + "id": "12", + "name": "Unresolved Issues", + "shared": true, + "query": "resolved=false", + "user": "grace.hopper", + "canModify": true, + "favourite": false + }, + { + "id": "54", + "name": "My Custom Filter", + "shared": false, + "query": "resolved=false|statuses=OPEN,REOPENED|assignees=__me__", + "user": "grace.hopper", + "canModify": true, + "favourite": true + } + ] +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/AppActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/AppActionTest.java index aacca7a8d28..19cd9c085e7 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/AppActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/AppActionTest.java @@ -42,28 +42,25 @@ public class AppActionTest { @Mock IssueFilterService service; - IssueFilterJsonWriter writer = new IssueFilterJsonWriter(); - - AppAction action; - - WsTester tester; + AppAction underTest; + WsTester ws; @Before public void setUp() { - action = new AppAction(service, writer, userSessionRule); - tester = new WsTester(new IssueFilterWs(action, mock(ShowAction.class), mock(SearchAction.class), mock(FavoritesAction.class))); + underTest = new AppAction(service, userSessionRule); + ws = new WsTester(new IssueFilterWs(underTest, mock(ShowAction.class), mock(SearchAction.class), mock(FavoritesAction.class))); } @Test public void anonymous_app() throws Exception { userSessionRule.anonymous(); - tester.newGetRequest("api/issue_filters", "app").execute().assertJson(getClass(), "anonymous_page.json"); + ws.newGetRequest("api/issue_filters", "app").execute().assertJson(getClass(), "anonymous_page.json"); } @Test public void logged_in_app() throws Exception { userSessionRule.login("eric").setUserId(123); - tester.newGetRequest("api/issue_filters", "app").execute() + ws.newGetRequest("api/issue_filters", "app").execute() .assertJson(getClass(), "logged_in_page.json"); } @@ -74,7 +71,7 @@ public class AppActionTest { new IssueFilterDto().setId(6L).setName("My issues"), new IssueFilterDto().setId(13L).setName("Blocker issues") )); - tester.newGetRequest("api/issue_filters", "app").execute() + ws.newGetRequest("api/issue_filters", "app").execute() .assertJson(getClass(), "logged_in_page_with_favorites.json"); } @@ -85,7 +82,7 @@ public class AppActionTest { new IssueFilterDto().setId(13L).setName("Blocker issues").setData("severity=BLOCKER").setUserLogin("eric") ); - tester.newGetRequest("api/issue_filters", "app").setParam("id", "13").execute() + ws.newGetRequest("api/issue_filters", "app").setParam("id", "13").execute() .assertJson(getClass(), "logged_in_page_with_selected_filter.json"); } @@ -97,7 +94,7 @@ public class AppActionTest { new IssueFilterDto().setId(13L).setName("Blocker issues").setData("severity=BLOCKER").setUserLogin("simon").setShared(true) ); - tester.newGetRequest("api/issue_filters", "app").setParam("id", "13").execute() + ws.newGetRequest("api/issue_filters", "app").setParam("id", "13").execute() .assertJson(getClass(), "selected_filter_can_not_be_modified.json"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterJsonWriterTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterJsonWriterTest.java index cbda9f431e8..5c88efc83c9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterJsonWriterTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterJsonWriterTest.java @@ -34,8 +34,6 @@ import static org.sonar.test.JsonAssert.assertJson; public class IssueFilterJsonWriterTest { - IssueFilterJsonWriter writer = new IssueFilterJsonWriter(); - @Test public void write_filter() { test(new AnonymousMockUserSession(), @@ -47,7 +45,7 @@ public class IssueFilterJsonWriterTest { .setUserLogin("simon") .setData("severity=BLOCKER"), "{\"filter\":{\n" + - " \"id\":13,\n" + + " \"id\":\"13\",\n" + " \"name\":\"Blocker issues\",\n" + " \"description\":\"All Blocker Issues\",\n" + " \"shared\":true,\n" + @@ -68,7 +66,7 @@ public class IssueFilterJsonWriterTest { .setUserLogin("simon") .setData("severity=BLOCKER"), "{\"filter\":{\n" + - " \"id\":13,\n" + + " \"id\":\"13\",\n" + " \"name\":\"Blocker issues\",\n" + " \"description\":\"All Blocker Issues\",\n" + " \"shared\":true,\n" + @@ -90,7 +88,7 @@ public class IssueFilterJsonWriterTest { .setUserLogin("julien") .setData("severity=BLOCKER"), "{\"filter\":{\n" + - " \"id\":13,\n" + + " \"id\":\"13\",\n" + " \"name\":\"Blocker issues\",\n" + " \"description\":\"All Blocker Issues\",\n" + " \"shared\":true,\n" + @@ -104,7 +102,9 @@ public class IssueFilterJsonWriterTest { StringWriter output = new StringWriter(); JsonWriter jsonWriter = JsonWriter.of(output); jsonWriter.beginObject(); - writer.writeWithName(jsonWriter, filter, userSession); + + IssueFilterJsonWriter.writeWithName(jsonWriter, filter, userSession); + jsonWriter.endObject(); assertJson(output.toString()).isSimilarTo(expected); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java index 670e429c3db..14f6cee6728 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java @@ -21,17 +21,22 @@ package org.sonar.server.issue.filter; import com.google.common.collect.Lists; +import java.util.Collections; +import java.util.List; +import java.util.Map; import org.apache.commons.lang.ObjectUtils; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; +import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.sonar.api.web.UserRole; +import org.sonar.core.permission.GlobalPermissions; +import org.sonar.db.DbClient; import org.sonar.db.issue.IssueFilterDao; import org.sonar.db.issue.IssueFilterDto; import org.sonar.db.issue.IssueFilterFavouriteDao; import org.sonar.db.issue.IssueFilterFavouriteDto; -import org.sonar.core.permission.GlobalPermissions; import org.sonar.db.user.AuthorizationDao; import org.sonar.server.es.SearchOptions; import org.sonar.server.es.SearchResult; @@ -46,33 +51,49 @@ import org.sonar.server.tester.AnonymousMockUserSession; import org.sonar.server.tester.MockUserSession; import org.sonar.server.user.UserSession; -import java.util.Collections; -import java.util.List; -import java.util.Map; - import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; import static org.junit.Assert.fail; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyMap; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class IssueFilterServiceTest { + DbClient dbClient = mock(DbClient.class); IssueFilterDao issueFilterDao = mock(IssueFilterDao.class); IssueFilterFavouriteDao issueFilterFavouriteDao = mock(IssueFilterFavouriteDao.class); - IssueIndex issueIndex = mock(IssueIndex.class); AuthorizationDao authorizationDao = mock(AuthorizationDao.class); + IssueIndex issueIndex = mock(IssueIndex.class); IssueFilterSerializer issueFilterSerializer = mock(IssueFilterSerializer.class); UserSession userSession = new MockUserSession("john"); - IssueFilterService service = new IssueFilterService(issueFilterDao, issueFilterFavouriteDao, issueIndex, authorizationDao, issueFilterSerializer); + + IssueFilterService underTest; + + @Before + public void setUp() { + when(dbClient.issueFilterDao()).thenReturn(issueFilterDao); + when(dbClient.issueFilterFavouriteDao()).thenReturn(issueFilterFavouriteDao); + when(dbClient.authorizationDao()).thenReturn(authorizationDao); + + underTest = new IssueFilterService(dbClient, issueIndex, issueFilterSerializer); + } @Test public void should_find_by_id() { IssueFilterDto dto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john"); when(issueFilterDao.selectById(1L)).thenReturn(dto); - IssueFilterDto issueFilter = service.findById(1L); + IssueFilterDto issueFilter = underTest.findById(1L); assertThat(issueFilter).isNotNull(); assertThat(issueFilter.getId()).isEqualTo(1L); } @@ -82,7 +103,7 @@ public class IssueFilterServiceTest { IssueFilterDto issueFilterDto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john"); when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto); - IssueFilterDto issueFilter = service.find(1L, userSession); + IssueFilterDto issueFilter = underTest.find(1L, userSession); assertThat(issueFilter).isNotNull(); assertThat(issueFilter.getId()).isEqualTo(1L); } @@ -92,7 +113,7 @@ public class IssueFilterServiceTest { IssueFilterDto issueFilterDto = new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("arthur").setShared(true); when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto); - IssueFilterDto issueFilter = service.find(1L, userSession); + IssueFilterDto issueFilter = underTest.find(1L, userSession); assertThat(issueFilter).isNotNull(); assertThat(issueFilter.getId()).isEqualTo(1L); } @@ -101,7 +122,7 @@ public class IssueFilterServiceTest { public void should_not_find_by_id_on_not_existing_issue() { when(issueFilterDao.selectById(1L)).thenReturn(null); try { - service.find(1L, userSession); + underTest.find(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Filter not found: 1"); @@ -111,7 +132,7 @@ public class IssueFilterServiceTest { @Test public void should_not_find_by_id_if_not_logged() { try { - service.find(1L, new AnonymousMockUserSession()); + underTest.find(1L, new AnonymousMockUserSession()); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(UnauthorizedException.class).hasMessage("User is not logged in"); @@ -125,7 +146,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(issueFilterDto); try { // John is not authorized to see eric filters - service.find(1L, userSession); + underTest.find(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User is not authorized to read this filter"); @@ -136,7 +157,7 @@ public class IssueFilterServiceTest { public void should_find_by_user() { when(issueFilterDao.selectByUser("john")).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john"))); - List<IssueFilterDto> issueFilter = service.findByUser(userSession); + List<IssueFilterDto> issueFilter = underTest.findByUser(userSession); assertThat(issueFilter).hasSize(1); assertThat(issueFilter.get(0).getId()).isEqualTo(1L); } @@ -144,7 +165,7 @@ public class IssueFilterServiceTest { @Test public void should_not_find_by_user_if_not_logged() { try { - service.findByUser(new AnonymousMockUserSession()); + underTest.findByUser(new AnonymousMockUserSession()); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(UnauthorizedException.class).hasMessage("User is not logged in"); @@ -154,7 +175,7 @@ public class IssueFilterServiceTest { @Test public void should_save() { IssueFilterDto issueFilter = new IssueFilterDto().setName("My Issue"); - IssueFilterDto result = service.save(issueFilter, userSession); + IssueFilterDto result = underTest.save(issueFilter, userSession); assertThat(result.getName()).isEqualTo("My Issue"); assertThat(result.getUserLogin()).isEqualTo("john"); @@ -164,7 +185,7 @@ public class IssueFilterServiceTest { @Test public void should_add_favorite_on_save() { IssueFilterDto issueFilter = new IssueFilterDto().setName("My Issue"); - service.save(issueFilter, userSession); + underTest.save(issueFilter, userSession); verify(issueFilterDao).insert(any(IssueFilterDto.class)); verify(issueFilterFavouriteDao).insert(any(IssueFilterFavouriteDto.class)); @@ -174,7 +195,7 @@ public class IssueFilterServiceTest { public void should_not_save_if_not_logged() { try { IssueFilterDto issueFilter = new IssueFilterDto().setName("My Issue"); - service.save(issueFilter, new AnonymousMockUserSession()); + underTest.save(issueFilter, new AnonymousMockUserSession()); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(UnauthorizedException.class).hasMessage("User is not logged in"); @@ -187,7 +208,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectByUser(eq("john"))).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue"))); try { IssueFilterDto issueFilter = new IssueFilterDto().setName("My Issue"); - service.save(issueFilter, userSession); + underTest.save(issueFilter, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Name already exists"); @@ -201,7 +222,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectSharedFilters()).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("henry").setShared(true))); IssueFilterDto issueFilter = new IssueFilterDto().setName("My Issue").setShared(true); try { - service.save(issueFilter, userSession); + underTest.save(issueFilter, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Other users already share filters with the same name"); @@ -213,7 +234,7 @@ public class IssueFilterServiceTest { public void should_update() { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Old Filter").setUserLogin("john")); - IssueFilterDto result = service.update(new IssueFilterDto().setId(1L).setName("My New Filter").setUserLogin("john"), userSession); + IssueFilterDto result = underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter").setUserLogin("john"), userSession); assertThat(result.getName()).isEqualTo("My New Filter"); verify(issueFilterDao).update(any(IssueFilterDto.class)); @@ -224,7 +245,7 @@ public class IssueFilterServiceTest { when(authorizationDao.selectGlobalPermissions("john")).thenReturn(newArrayList(GlobalPermissions.DASHBOARD_SHARING)); when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Filter").setShared(false).setUserLogin("john")); - IssueFilterDto result = service.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true).setUserLogin("john"), userSession); + IssueFilterDto result = underTest.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true).setUserLogin("john"), userSession); assertThat(result.isShared()).isTrue(); verify(issueFilterDao).update(any(IssueFilterDto.class)); @@ -236,7 +257,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Filter").setShared(false).setUserLogin("john")); try { - service.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true).setUserLogin("john"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true).setUserLogin("john"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User cannot own this filter because of insufficient rights"); @@ -250,7 +271,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Filter").setShared(false)); try { - service.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("My Filter").setShared(true), userSession); failBecauseExceptionWasNotThrown(ForbiddenException.class); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("Only owner of a filter can change sharing"); @@ -265,7 +286,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("Arthur Filter").setShared(true).setUserLogin("arthur")); try { - service.update(new IssueFilterDto().setId(1L).setName("Arthur Filter").setShared(false).setUserLogin("john"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("Arthur Filter").setShared(false).setUserLogin("john"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("Only owner of a filter can change sharing"); @@ -279,7 +300,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(dto); when(issueFilterDao.selectByUser("john")).thenReturn(newArrayList(dto)); - IssueFilterDto result = service.update(new IssueFilterDto().setId(1L).setName("My Filter").setUserLogin("john"), userSession); + IssueFilterDto result = underTest.update(new IssueFilterDto().setId(1L).setName("My Filter").setUserLogin("john"), userSession); assertThat(result.getName()).isEqualTo("My Filter"); verify(issueFilterDao).update(any(IssueFilterDto.class)); @@ -292,7 +313,7 @@ public class IssueFilterServiceTest { IssueFilterFavouriteDto otherFavouriteDto = new IssueFilterFavouriteDto().setId(11L).setUserLogin("arthur").setIssueFilterId(1L); when(issueFilterFavouriteDao.selectByFilterId(1L)).thenReturn(newArrayList(userFavouriteDto, otherFavouriteDto)); - IssueFilterDto result = service.update(new IssueFilterDto().setId(1L).setName("My New Filter").setUserLogin("john").setShared(false), userSession); + IssueFilterDto result = underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter").setUserLogin("john").setShared(false), userSession); assertThat(result.getName()).isEqualTo("My New Filter"); verify(issueFilterDao).update(any(IssueFilterDto.class)); @@ -307,7 +328,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)) .thenReturn(new IssueFilterDto().setId(1L).setName("My Old Filter").setDescription("Old description").setUserLogin("arthur").setShared(true)); - IssueFilterDto result = service.update(new IssueFilterDto().setId(1L).setName("My New Filter").setDescription("New description").setShared(true).setUserLogin("arthur"), + IssueFilterDto result = underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter").setDescription("New description").setShared(true).setUserLogin("arthur"), userSession); assertThat(result.getName()).isEqualTo("My New Filter"); assertThat(result.getDescription()).isEqualTo("New description"); @@ -323,7 +344,7 @@ public class IssueFilterServiceTest { .thenReturn(new IssueFilterDto().setId(1L).setName("My Old Filter").setDescription("Old description").setUserLogin("arthur").setShared(true)); try { - service.update(new IssueFilterDto().setId(1L).setName("My New Filter").setDescription("New description").setShared(true).setUserLogin("arthur"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter").setDescription("New description").setShared(true).setUserLogin("arthur"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User cannot own this filter because of insufficient rights"); @@ -336,7 +357,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(null); try { - service.update(new IssueFilterDto().setId(1L).setName("My New Filter"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Filter not found: 1"); @@ -350,7 +371,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Old Filter").setUserLogin("arthur").setShared(true)); try { - service.update(new IssueFilterDto().setId(1L).setName("My New Filter"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setName("My New Filter"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User is not authorized to modify this filter"); @@ -364,7 +385,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectByUser(eq("john"))).thenReturn(newArrayList(new IssueFilterDto().setId(2L).setName("My Issue"))); try { - service.update(new IssueFilterDto().setId(1L).setUserLogin("john").setName("My Issue"), userSession); + underTest.update(new IssueFilterDto().setId(1L).setUserLogin("john").setName("My Issue"), userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("Name already exists"); @@ -380,7 +401,7 @@ public class IssueFilterServiceTest { Map<String, Object> data = newHashMap(); data.put("componentRoots", "struts"); - IssueFilterDto result = service.updateFilterQuery(1L, data, userSession); + IssueFilterDto result = underTest.updateFilterQuery(1L, data, userSession); assertThat(result.getData()).isEqualTo("componentRoots=struts"); verify(issueFilterDao).update(any(IssueFilterDto.class)); @@ -399,7 +420,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectSharedFilters()).thenReturn(Lists.newArrayList(sharedFilter)); IssueFilterDto issueFilter = new IssueFilterDto().setId(1L).setName("My filter").setShared(true).setUserLogin("new.owner"); - service.update(issueFilter, userSession); + underTest.update(issueFilter, userSession); verify(issueFilterDao).update(argThat(Matches.filter(expectedDto))); } @@ -414,7 +435,7 @@ public class IssueFilterServiceTest { try { IssueFilterDto issueFilter = new IssueFilterDto().setId(1L).setName("My filter").setShared(true).setUserLogin("new.owner"); - service.update(issueFilter, new MockUserSession(currentUser).setUserId(1)); + underTest.update(issueFilter, new MockUserSession(currentUser).setUserId(1)); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User is not authorized to change the owner of this filter"); @@ -427,7 +448,7 @@ public class IssueFilterServiceTest { public void should_delete() { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john")); - service.delete(1L, userSession); + underTest.delete(1L, userSession); verify(issueFilterDao).delete(1L); } @@ -437,7 +458,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john")); when(issueFilterFavouriteDao.selectByFilterId(1L)).thenReturn(newArrayList(new IssueFilterFavouriteDto().setId(10L).setUserLogin("john").setIssueFilterId(1L))); - service.delete(1L, userSession); + underTest.delete(1L, userSession); verify(issueFilterDao).delete(1L); verify(issueFilterFavouriteDao).deleteByFilterId(1L); @@ -448,7 +469,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(null); try { - service.delete(1L, userSession); + underTest.delete(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Filter not found: 1"); @@ -461,7 +482,7 @@ public class IssueFilterServiceTest { when(authorizationDao.selectGlobalPermissions("john")).thenReturn(newArrayList(GlobalPermissions.SYSTEM_ADMIN)); when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("arthur").setShared(true)); - service.delete(1L, userSession); + underTest.delete(1L, userSession); verify(issueFilterDao).delete(1L); } @@ -472,7 +493,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("arthur").setShared(false)); try { - service.delete(1L, userSession); + underTest.delete(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User is not authorized to read this filter"); @@ -486,7 +507,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("arthur").setShared(true)); try { - service.delete(1L, userSession); + underTest.delete(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(ForbiddenException.class).hasMessage("User is not authorized to modify this filter"); @@ -499,7 +520,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john").setData("componentRoots=struts")); IssueFilterDto issueFilter = new IssueFilterDto().setName("Copy Of My Issue"); - IssueFilterDto result = service.copy(1L, issueFilter, userSession); + IssueFilterDto result = underTest.copy(1L, issueFilter, userSession); assertThat(result.getName()).isEqualTo("Copy Of My Issue"); assertThat(result.getUserLogin()).isEqualTo("john"); assertThat(result.getData()).isEqualTo("componentRoots=struts"); @@ -512,7 +533,7 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("arthur").setShared(true)); IssueFilterDto issueFilter = new IssueFilterDto().setName("Copy Of My Issue"); - IssueFilterDto result = service.copy(1L, issueFilter, userSession); + IssueFilterDto result = underTest.copy(1L, issueFilter, userSession); assertThat(result.getName()).isEqualTo("Copy Of My Issue"); assertThat(result.getUserLogin()).isEqualTo("john"); assertThat(result.isShared()).isFalse(); @@ -524,7 +545,7 @@ public class IssueFilterServiceTest { public void should_add_favorite_on_copy() { when(issueFilterDao.selectById(1L)).thenReturn(new IssueFilterDto().setId(1L).setName("My Issues").setUserLogin("john").setData("componentRoots=struts")); IssueFilterDto issueFilter = new IssueFilterDto().setName("Copy Of My Issue"); - service.copy(1L, issueFilter, userSession); + underTest.copy(1L, issueFilter, userSession); verify(issueFilterDao).insert(any(IssueFilterDto.class)); verify(issueFilterFavouriteDao).insert(any(IssueFilterFavouriteDto.class)); @@ -540,7 +561,7 @@ public class IssueFilterServiceTest { when(result.getTotal()).thenReturn(100L); when(issueIndex.search(issueQuery, searchOptions)).thenReturn(result); - IssueFilterService.IssueFilterResult issueFilterResult = service.execute(issueQuery, searchOptions); + IssueFilterService.IssueFilterResult issueFilterResult = underTest.execute(issueQuery, searchOptions); assertThat(issueFilterResult.issues()).hasSize(1); assertThat(issueFilterResult.paging().total()).isEqualTo(100); assertThat(issueFilterResult.paging().pageIndex()).isEqualTo(2); @@ -552,9 +573,9 @@ public class IssueFilterServiceTest { when(issueFilterDao.selectSharedFilters()).thenReturn(newArrayList( new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john").setShared(true), new IssueFilterDto().setId(2L).setName("Project Issues").setUserLogin("arthur").setShared(true) - )); + )); - List<IssueFilterDto> results = service.findSharedFiltersWithoutUserFilters(userSession); + List<IssueFilterDto> results = underTest.findSharedFiltersWithoutUserFilters(userSession); assertThat(results).hasSize(1); IssueFilterDto filter = results.get(0); assertThat(filter.getName()).isEqualTo("Project Issues"); @@ -564,14 +585,14 @@ public class IssueFilterServiceTest { public void should_find_favourite_issue_filter() { when(issueFilterDao.selectFavoriteFiltersByUser("john")).thenReturn(newArrayList(new IssueFilterDto().setId(1L).setName("My Issue").setUserLogin("john"))); - List<IssueFilterDto> results = service.findFavoriteFilters(userSession); + List<IssueFilterDto> results = underTest.findFavoriteFilters(userSession); assertThat(results).hasSize(1); } @Test public void should_not_find_favourite_issue_filter_if_not_logged() { try { - service.findFavoriteFilters(new AnonymousMockUserSession()); + underTest.findFavoriteFilters(new AnonymousMockUserSession()); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(UnauthorizedException.class).hasMessage("User is not logged in"); @@ -585,7 +606,7 @@ public class IssueFilterServiceTest { when(issueFilterFavouriteDao.selectByFilterId(1L)).thenReturn(Collections.<IssueFilterFavouriteDto>emptyList()); ArgumentCaptor<IssueFilterFavouriteDto> issueFilterFavouriteDtoCaptor = ArgumentCaptor.forClass(IssueFilterFavouriteDto.class); - boolean result = service.toggleFavouriteIssueFilter(1L, userSession); + boolean result = underTest.toggleFavouriteIssueFilter(1L, userSession); assertThat(result).isTrue(); verify(issueFilterFavouriteDao).insert(issueFilterFavouriteDtoCaptor.capture()); @@ -601,7 +622,7 @@ public class IssueFilterServiceTest { when(issueFilterFavouriteDao.selectByFilterId(1L)).thenReturn(Collections.<IssueFilterFavouriteDto>emptyList()); ArgumentCaptor<IssueFilterFavouriteDto> issueFilterFavouriteDtoCaptor = ArgumentCaptor.forClass(IssueFilterFavouriteDto.class); - boolean result = service.toggleFavouriteIssueFilter(1L, userSession); + boolean result = underTest.toggleFavouriteIssueFilter(1L, userSession); assertThat(result).isTrue(); verify(issueFilterFavouriteDao).insert(issueFilterFavouriteDtoCaptor.capture()); @@ -616,7 +637,7 @@ public class IssueFilterServiceTest { // The filter is in the favorite list --> remove favorite when(issueFilterFavouriteDao.selectByFilterId(1L)).thenReturn(newArrayList(new IssueFilterFavouriteDto().setId(10L).setUserLogin("john").setIssueFilterId(1L))); - boolean result = service.toggleFavouriteIssueFilter(1L, userSession); + boolean result = underTest.toggleFavouriteIssueFilter(1L, userSession); assertThat(result).isFalse(); verify(issueFilterFavouriteDao).delete(10L); } @@ -625,7 +646,7 @@ public class IssueFilterServiceTest { public void should_not_toggle_favourite_filter_if_filter_not_found() { when(issueFilterDao.selectById(1L)).thenReturn(null); try { - service.toggleFavouriteIssueFilter(1L, userSession); + underTest.toggleFavouriteIssueFilter(1L, userSession); fail(); } catch (Exception e) { assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Filter not found: 1"); @@ -639,7 +660,7 @@ public class IssueFilterServiceTest { props.put("componentRoots", "struts"); props.put("statuses", "OPEN"); props.put("unkwown", "JOHN"); - service.serializeFilterQuery(props); + underTest.serializeFilterQuery(props); Map<String, Object> expected = newHashMap(); expected.put("componentRoots", "struts"); @@ -650,7 +671,7 @@ public class IssueFilterServiceTest { @Test public void should_deserialize_filter_query() { IssueFilterDto issueFilter = new IssueFilterDto().setData("componentRoots=struts"); - service.deserializeIssueFilterQuery(issueFilter); + underTest.deserializeIssueFilterQuery(issueFilter); verify(issueFilterSerializer).deserialize("componentRoots=struts"); } @@ -658,13 +679,13 @@ public class IssueFilterServiceTest { public void user_can_share_filter_if_logged_and_own_sharing_permission() { when(authorizationDao.selectGlobalPermissions("john")).thenReturn(newArrayList(GlobalPermissions.DASHBOARD_SHARING)); UserSession userSession = new MockUserSession("john"); - assertThat(service.canShareFilter(userSession)).isTrue(); + assertThat(underTest.canShareFilter(userSession)).isTrue(); - assertThat(service.canShareFilter(new AnonymousMockUserSession())).isFalse(); + assertThat(underTest.canShareFilter(new AnonymousMockUserSession())).isFalse(); when(authorizationDao.selectGlobalPermissions("john")).thenReturn(Collections.<String>emptyList()); userSession = new MockUserSession("john"); - assertThat(service.canShareFilter(userSession)).isFalse(); + assertThat(underTest.canShareFilter(userSession)).isFalse(); } @Test @@ -673,7 +694,7 @@ public class IssueFilterServiceTest { ArgumentCaptor<IssueFilterDto> filterCaptor = ArgumentCaptor.forClass(IssueFilterDto.class); String savedData = "my super filter"; - service.save(new IssueFilterDto().setData(savedData)); + underTest.save(new IssueFilterDto().setData(savedData)); verify(issueFilterDao).insert(filterCaptor.capture()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterWsTest.java index 1e9e082df35..c8aa30fccef 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterWsTest.java @@ -22,39 +22,36 @@ package org.sonar.server.issue.filter; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; import org.sonar.api.server.ws.WebService; +import org.sonar.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; -@RunWith(MockitoJUnitRunner.class) public class IssueFilterWsTest { @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); + public UserSessionRule userSession = UserSessionRule.standalone(); - @Mock - IssueFilterService service; - - @Mock - IssueFilterJsonWriter issueFilterJsonWriter; - - IssueFilterWs ws; - - WsTester tester; + IssueFilterWs underTest; + WsTester ws; @Before public void setUp() { - ws = new IssueFilterWs(new AppAction(service, issueFilterJsonWriter, userSessionRule), new ShowAction(service, issueFilterJsonWriter, userSessionRule), new SearchAction(service, issueFilterJsonWriter, userSessionRule), new FavoritesAction(service, userSessionRule)); - tester = new WsTester(ws); + IssueFilterService service = mock(IssueFilterService.class); + DbClient dbClient = mock(DbClient.class); + underTest = new IssueFilterWs( + new AppAction(service, userSession), + new ShowAction(service, userSession), + new SearchAction(dbClient, userSession), + new FavoritesAction(service, userSession)); + ws = new WsTester(underTest); } @Test public void define_ws() { - WebService.Controller controller = tester.controller("api/issue_filters"); + WebService.Controller controller = ws.controller("api/issue_filters"); assertThat(controller).isNotNull(); assertThat(controller.description()).isNotEmpty(); assertThat(controller.since()).isEqualTo("4.2"); @@ -71,6 +68,10 @@ public class IssueFilterWsTest { WebService.Action favorites = controller.action("favorites"); assertThat(favorites).isNotNull(); assertThat(favorites.params()).isEmpty(); + + WebService.Action search = controller.action("search"); + assertThat(search).isNotNull(); + assertThat(search.params()).isEmpty(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/SearchActionTest.java index cd4e9045eab..3b3a4c7cd04 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/SearchActionTest.java @@ -23,72 +23,110 @@ package org.sonar.server.issue.filter; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; import org.sonar.db.issue.IssueFilterDto; +import org.sonar.db.issue.IssueFilterFavouriteDto; +import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.WsTester; +import org.sonar.server.ws.TestResponse; +import org.sonar.server.ws.WsActionTester; +import org.sonar.test.DbTests; -import static com.google.common.collect.Lists.newArrayList; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.sonar.test.JsonAssert.assertJson; +@Category(DbTests.class) public class SearchActionTest { - static final String EMPTY_JSON = "{}"; static final String EMPTY_ISSUE_FILTERS_JSON = "{" + " \"issueFilters\": []" + "}"; @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone(); + public DbTester db = DbTester.create(System2.INSTANCE); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); - IssueFilterService service = mock(IssueFilterService.class); - IssueFilterJsonWriter writer = new IssueFilterJsonWriter(); - WsTester ws; + WsActionTester ws; + DbClient dbClient; + DbSession dbSession; @Before public void setUp() { - ws = new WsTester(new IssueFilterWs(new SearchAction(service, writer, userSessionRule))); + dbClient = db.getDbClient(); + dbSession = db.getSession(); + userSession.login(); + + ws = new WsActionTester(new SearchAction(dbClient, userSession)); } @Test - public void anonymous_app() throws Exception { - userSessionRule.anonymous(); - WsTester.Result result = ws.newGetRequest("api/issue_filters", "search").execute(); + public void empty_response() throws Exception { + TestResponse result = newRequest(); - assertJson(result.outputAsString()).isSimilarTo(EMPTY_JSON); + assertJson(result.getInput()).isSimilarTo(EMPTY_ISSUE_FILTERS_JSON); } @Test - public void logged_in_app() throws Exception { - userSessionRule.login("eric").setUserId(123); - WsTester.Result result = ws.newGetRequest("api/issue_filters", "search").execute(); + public void issue_filter_with_all_cases() { + userSession.login("grace.hopper"); + IssueFilterDto myUnresolvedIssues = insertIssueFilter(new IssueFilterDto() + .setName("My Unresolved Issues") + .setShared(true) + .setData("resolved=false|assignees=__me__")); + IssueFilterDto falsePositiveAndWontFixIssues = insertIssueFilter(new IssueFilterDto() + .setName("False Positive and Won't Fix Issues") + .setShared(true) + .setData("resolutions=FALSE-POSITIVE,WONTFIX")); + IssueFilterDto unresolvedIssues = insertIssueFilter(new IssueFilterDto() + .setName("Unresolved Issues") + .setShared(true) + .setUserLogin("grace.hopper") + .setData("resolved=false")); + IssueFilterDto myCustomFilter = insertIssueFilter(new IssueFilterDto() + .setName("My Custom Filter") + .setShared(false) + .setUserLogin("grace.hopper") + .setData("resolved=false|statuses=OPEN,REOPENED|assignees=__me__")); + linkFilterToUser(myUnresolvedIssues.getId(), "grace.hopper"); + linkFilterToUser(myCustomFilter.getId(), "grace.hopper"); + linkFilterToUser(falsePositiveAndWontFixIssues.getId(), "another-login"); + linkFilterToUser(unresolvedIssues.getId(), "yet-another-login"); + commit(); + + TestResponse result = newRequest(); - assertJson(result.outputAsString()).isSimilarTo(EMPTY_ISSUE_FILTERS_JSON); + assertJson(result.getInput()).isSimilarTo(getClass().getResource("SearchActionTest/search.json")); } @Test - public void logged_in_app_with_all_issue_filters() throws Exception { - userSessionRule.login("eric").setUserId(123); - when(service.findFavoriteFilters(userSessionRule)).thenReturn(newArrayList( - new IssueFilterDto() - .setId(3L) - .setName("My Unresolved Issues") - .setShared(true) - .setData("resolved=false|assignees=__me__"), - new IssueFilterDto() - .setId(2L) - .setName("False Positive and Won't Fix Issues") - .setShared(false) - .setData("resolutions=FALSE-POSITIVE,WONTFIX") - )); - when(service.findSharedFiltersWithoutUserFilters(userSessionRule)).thenReturn(newArrayList( - new IssueFilterDto() - .setId(2L) - .setName("False Positive and Won't Fix Issues") - .setShared(false) - .setData("resolutions=FALSE-POSITIVE,WONTFIX") - )); - ws.newGetRequest("api/issue_filters", "search").execute() - .assertJson(getClass(), "logged_in_page_with_favorites.json"); + public void fail_if_anonymous() throws Exception { + userSession.anonymous(); + expectedException.expect(UnauthorizedException.class); + + newRequest(); + } + + private TestResponse newRequest() { + return ws.newRequest().execute(); + } + + private void linkFilterToUser(long filterId, String userLogin) { + dbClient.issueFilterFavouriteDao().insert(dbSession, new IssueFilterFavouriteDto() + .setIssueFilterId(filterId) + .setUserLogin(userLogin)); + } + + private IssueFilterDto insertIssueFilter(IssueFilterDto issueFilter) { + return dbClient.issueFilterDao().insert(dbSession, issueFilter); + } + + private void commit() { + dbSession.commit(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/ShowActionTest.java index 48a21771108..353309874e4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/filter/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/filter/ShowActionTest.java @@ -44,15 +44,13 @@ public class ShowActionTest { @Mock IssueFilterService service; - IssueFilterJsonWriter writer = new IssueFilterJsonWriter(); - ShowAction action; WsTester tester; @Before public void setUp() { - action = new ShowAction(service, writer, userSessionRule); + action = new ShowAction(service, userSessionRule); tester = new WsTester(new IssueFilterWs(mock(AppAction.class), action, mock(SearchAction.class), mock(FavoritesAction.class))); } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/logged_in_page_with_selected_filter.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/logged_in_page_with_selected_filter.json index e56c2b5c754..0497cbd9eaa 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/logged_in_page_with_selected_filter.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/logged_in_page_with_selected_filter.json @@ -2,7 +2,7 @@ "canManageFilters": true, "canBulkChange": true, "filter": { - "id": 13, + "id": "13", "name": "Blocker issues", "shared": false, "query": "severity=BLOCKER", diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/selected_filter_can_not_be_modified.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/selected_filter_can_not_be_modified.json index 8b995de4aa9..ce741bedc35 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/selected_filter_can_not_be_modified.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/AppActionTest/selected_filter_can_not_be_modified.json @@ -2,7 +2,7 @@ "canManageFilters": true, "canBulkChange": true, "filter": { - "id": 13, + "id": "13", "name": "Blocker issues", "shared": true, "query": "severity=BLOCKER", diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/logged_in_page_with_favorites.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/logged_in_page_with_favorites.json deleted file mode 100644 index d8d65271361..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/logged_in_page_with_favorites.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "issueFilters": [ - { - "id": 3, - "name": "My Unresolved Issues", - "shared": true, - "query": "resolved=false|assignees=__me__", - "canModify": false - }, - { - "id": 2, - "name": "False Positive and Won't Fix Issues", - "shared": false, - "query": "resolutions=FALSE-POSITIVE,WONTFIX", - "canModify": false - } - ] -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/search.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/search.json new file mode 100644 index 00000000000..a9bb2c4c541 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/SearchActionTest/search.json @@ -0,0 +1,36 @@ +{ + "issueFilters": [ + { + "name": "My Unresolved Issues", + "shared": true, + "query": "resolved=false|assignees=__me__", + "user": "[SonarQube]", + "canModify": false, + "favourite": true + }, + { + "name": "False Positive and Won't Fix Issues", + "shared": true, + "query": "resolutions=FALSE-POSITIVE,WONTFIX", + "user": "[SonarQube]", + "canModify": false, + "favourite": false + }, + { + "name": "Unresolved Issues", + "shared": true, + "query": "resolved=false", + "user": "grace.hopper", + "canModify": true, + "favourite": false + }, + { + "name": "My Custom Filter", + "shared": false, + "query": "resolved=false|statuses=OPEN,REOPENED|assignees=__me__", + "user": "grace.hopper", + "canModify": true, + "favourite": true + } + ] +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/ShowActionTest/show_filter.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/ShowActionTest/show_filter.json index 447e43632f4..f0428f8d494 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/ShowActionTest/show_filter.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/filter/ShowActionTest/show_filter.json @@ -1,6 +1,6 @@ { "filter": { - "id": 13, + "id": "13", "name": "Blocker issues", "description": "All Blocker Issues", "shared": true, diff --git a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterDao.java b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterDao.java index bdb26dfa746..6a6b6fb86bf 100644 --- a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterDao.java +++ b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterDao.java @@ -24,6 +24,7 @@ import java.util.List; import javax.annotation.CheckForNull; import org.apache.ibatis.session.SqlSession; import org.sonar.db.Dao; +import org.sonar.db.DbSession; import org.sonar.db.MyBatis; public class IssueFilterDao implements Dao { @@ -45,15 +46,23 @@ public class IssueFilterDao implements Dao { } } + /** + * @deprecated since 5.2 use {@link #selectByUser(DbSession, String)} + */ + @Deprecated public List<IssueFilterDto> selectByUser(String user) { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { - return mapper(session).selectByUser(user); + return selectByUser(session, user); } finally { MyBatis.closeQuietly(session); } } + public List<IssueFilterDto> selectByUser(DbSession session, String user) { + return mapper(session).selectByUser(user); + } + public List<IssueFilterDto> selectFavoriteFiltersByUser(String user) { SqlSession session = mybatis.openSession(false); try { @@ -72,27 +81,45 @@ public class IssueFilterDao implements Dao { } } + /** + * @deprecated since 5.2 use {@link #selectSharedFilters(DbSession)} + */ + @Deprecated public List<IssueFilterDto> selectSharedFilters() { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { - return mapper(session).selectSharedFilters(); + return selectSharedFilters(session); } finally { MyBatis.closeQuietly(session); } } + public List<IssueFilterDto> selectSharedFilters(DbSession session) { + return mapper(session).selectSharedFilters(); + } + + /** + * @deprecated since 5.2 use {@link #insert(DbSession, IssueFilterDto)} + */ + @Deprecated public void insert(IssueFilterDto filter) { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { - mapper(session).insert(filter); - session.commit(); + insert(session, filter); } finally { MyBatis.closeQuietly(session); } } + public IssueFilterDto insert(DbSession session, IssueFilterDto filter) { + mapper(session).insert(filter); + session.commit(); + + return filter; + } + public void update(IssueFilterDto filter) { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { mapper(session).update(filter); session.commit(); @@ -102,7 +129,7 @@ public class IssueFilterDao implements Dao { } public void delete(long id) { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { mapper(session).delete(id); session.commit(); diff --git a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteDao.java b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteDao.java index 7e7e20b634b..4253844e253 100644 --- a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteDao.java +++ b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteDao.java @@ -23,6 +23,7 @@ package org.sonar.db.issue; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.sonar.db.Dao; +import org.sonar.db.DbSession; import org.sonar.db.MyBatis; public class IssueFilterFavouriteDao implements Dao { @@ -51,16 +52,24 @@ public class IssueFilterFavouriteDao implements Dao { } } + /** + * @deprecated since 5.2 use {@link #insert(DbSession, IssueFilterFavouriteDto)} + */ + @Deprecated public void insert(IssueFilterFavouriteDto filter) { - SqlSession session = mybatis.openSession(false); + DbSession session = mybatis.openSession(false); try { - mapper(session).insert(filter); - session.commit(); + insert(session, filter); } finally { MyBatis.closeQuietly(session); } } + public void insert(DbSession session, IssueFilterFavouriteDto filter) { + mapper(session).insert(filter); + session.commit(); + } + public void delete(long id) { SqlSession session = mybatis.openSession(false); try { @@ -84,4 +93,8 @@ public class IssueFilterFavouriteDao implements Dao { private IssueFilterFavouriteMapper mapper(SqlSession session) { return session.getMapper(IssueFilterFavouriteMapper.class); } + + public List<IssueFilterFavouriteDto> selectByUser(DbSession dbSession, String login) { + return mapper(dbSession).selectByUser(login); + } } diff --git a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteMapper.java b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteMapper.java index 62bd124174b..947bd799e34 100644 --- a/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/issue/IssueFilterFavouriteMapper.java @@ -33,6 +33,8 @@ public interface IssueFilterFavouriteMapper { List<IssueFilterFavouriteDto> selectByFilterId(@Param("filterId") long filterId); + List<IssueFilterFavouriteDto> selectByUser(String login); + void insert(IssueFilterFavouriteDto filterFavourite); void delete(long id); diff --git a/sonar-db/src/main/resources/org/sonar/db/issue/IssueFilterFavouriteMapper.xml b/sonar-db/src/main/resources/org/sonar/db/issue/IssueFilterFavouriteMapper.xml index 77db11f635c..cdcf51ee499 100644 --- a/sonar-db/src/main/resources/org/sonar/db/issue/IssueFilterFavouriteMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/issue/IssueFilterFavouriteMapper.xml @@ -25,6 +25,13 @@ where filter_favourites.issue_filter_id=#{filterId} </select> + <select id="selectByUser" parameterType="string" resultType="issueFilterFavourite"> + select + <include refid="issueFilterFavouriteColumns"/> + from issue_filter_favourites filter_favourites + where filter_favourites.user_login=#{login} + </select> + <insert id="insert" parameterType="issueFilterFavourite" keyColumn="id" useGeneratedKeys="true" keyProperty="id"> INSERT INTO issue_filter_favourites (user_login, issue_filter_id, created_at) VALUES (#{userLogin}, #{issueFilterId}, current_timestamp) |