From 423c7f37687f59c5aa7416be5f202372c0d1268a Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lievremont Date: Tue, 10 Mar 2015 11:55:08 +0100 Subject: [PATCH] SONAR-6244 assigned_to_me facet must be sticky with respect to assignees --- .../sonar/server/issue/index/IssueIndex.java | 36 +++++++++----- .../server/issue/index/IssueIndexTest.java | 20 +++++++- .../issue/ws/SearchActionMediumTest.java | 47 +++++++++++++++++-- .../assigned_to_me_facet_sticky.json | 42 +++++++++++++++++ 4 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/assigned_to_me_facet_sticky.json diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java index 41fc3d93a6d..abe6c83a571 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java @@ -21,10 +21,7 @@ package org.sonar.server.issue.index; import com.google.common.base.Function; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; +import com.google.common.collect.*; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.elasticsearch.action.search.SearchRequestBuilder; @@ -66,6 +63,7 @@ import javax.annotation.Nullable; import java.text.SimpleDateFormat; import java.util.*; +import java.util.regex.Pattern; import static com.google.common.collect.Lists.newArrayList; @@ -478,8 +476,10 @@ public class IssueIndex extends BaseIndex { StickyFacetBuilder assigneeFacetBuilder = new StickyFacetBuilder(queryBuilder, assigneeFilters); BoolFilterBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName); FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE); - if (!query.assignees().isEmpty()) { - facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, query.assignees()); + + Collection assigneesEscaped = escapeValuesForFacetInclusion(query.assignees()); + if (!assigneesEscaped.isEmpty()) { + facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, assigneesEscaped); } // Add missing facet for unassigned issues @@ -494,6 +494,15 @@ public class IssueIndex extends BaseIndex { .subAggregation(facetTopAggregation); } + private Collection escapeValuesForFacetInclusion(@Nullable Collection values) { + return values == null ? Arrays.asList() : Collections2.transform(values, new Function() { + @Override + public String apply(String input) { + return Pattern.quote(input); + } + }); + } + private void addAssignedToMeFacetIfNeeded(SearchRequestBuilder builder, SearchOptions options, IssueQuery query, Map filters, QueryBuilder queryBuilder) { String login = UserSession.get().login(); @@ -505,14 +514,17 @@ public class IssueIndex extends BaseIndex { String facetName = IssueFilterParameters.FACET_ASSIGNED_TO_ME; // Same as in super.stickyFacetBuilder - Map assigneeFilters = Maps.newHashMap(filters); - StickyFacetBuilder assignedToMeFacetBuilder = new StickyFacetBuilder(queryBuilder, assigneeFilters); - BoolFilterBuilder facetFilter = assignedToMeFacetBuilder.getStickyFacetFilter("__assigned_to_me"); + StickyFacetBuilder assignedToMeFacetBuilder = new StickyFacetBuilder(queryBuilder, filters); + BoolFilterBuilder facetFilter = assignedToMeFacetBuilder.getStickyFacetFilter("__isAssigned", fieldName); - builder.addAggregation(AggregationBuilders - .filter(facetName) + FilterAggregationBuilder facetTopAggregation = AggregationBuilders + .filter(facetName + "__filter") .filter(facetFilter) - .subAggregation(AggregationBuilders.terms(facetName + "__terms").field(fieldName).include(login))); + .subAggregation(AggregationBuilders.terms(facetName + "__terms").field(fieldName).include(login)); + + builder.addAggregation( + AggregationBuilders.global(facetName) + .subAggregation(facetTopAggregation)); } private AggregationBuilder createResolutionFacet(Map filters, QueryBuilder esQuery) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java index 6fa5133dfbc..a833498bdef 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java @@ -56,7 +56,9 @@ import java.util.List; import java.util.Map; import static com.google.common.collect.Lists.newArrayList; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; public class IssueIndexTest { @@ -552,6 +554,22 @@ public class IssueIndexTest { assertThat(result.getFacets().get("assignees")).containsOnly(entry("steph", 1L), entry("simon", 2L), entry("", 1L)); } + @Test + public void facets_on_assignees_supports_dashes() throws Exception { + ComponentDto project = ComponentTesting.newProjectDto(); + ComponentDto file = ComponentTesting.newFileDto(project); + + indexIssues( + IssueTesting.newDoc("ISSUE1", file).setAssignee("j-b"), + IssueTesting.newDoc("ISSUE2", file).setAssignee("simon"), + IssueTesting.newDoc("ISSUE3", file).setAssignee("simon"), + IssueTesting.newDoc("ISSUE4", file).setAssignee(null)); + + SearchResult result = index.search(IssueQuery.builder().assignees(Arrays.asList("j-b")).build(), new SearchOptions().addFacets(newArrayList("assignees"))); + assertThat(result.getFacets().getNames()).containsOnly("assignees"); + assertThat(result.getFacets().get("assignees")).containsOnly(entry("j-b", 1L), entry("simon", 2L), entry("", 1L)); + } + @Test public void filter_by_assigned() throws Exception { ComponentDto project = ComponentTesting.newProjectDto(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java index 2595a65d48e..1132c428782 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java @@ -473,8 +473,31 @@ public class SearchActionMediumTest { .setParam(WebService.Param.FACETS, "assignees,assigned_to_me") .execute() .assertJson(this.getClass(), "filter_by_assigned_to_me.json", false); + } + @Test + public void filter_by_assigned_to_me_unauthenticated() throws Exception { MockUserSession.set(); + + ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); + setDefaultProjectPermission(project); + ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); + RuleDto rule = newRule(); + IssueDto issue1 = IssueTesting.newDto(rule, file, project) + .setStatus("OPEN") + .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") + .setAssignee("john"); + IssueDto issue2 = IssueTesting.newDto(rule, file, project) + .setStatus("OPEN") + .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2") + .setAssignee("alice"); + IssueDto issue3 = IssueTesting.newDto(rule, file, project) + .setStatus("OPEN") + .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2"); + db.issueDao().insert(session, issue1, issue2, issue3); + session.commit(); + tester.get(IssueIndexer.class).indexAll(); + wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) .setParam("resolved", "false") .setParam("assignees", "__me__") @@ -483,31 +506,45 @@ public class SearchActionMediumTest { } @Test - public void filter_by_assigned_to_me_unauthenticated() throws Exception { + public void assigned_to_me_facet_is_sticky_relative_to_assignees() throws Exception { ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject")); setDefaultProjectPermission(project); ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent")); RuleDto rule = newRule(); IssueDto issue1 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) .setStatus("OPEN") .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2") - .setAssignee("john"); + .setSeverity("MAJOR") + .setAssignee("john-bob.polop"); IssueDto issue2 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) .setStatus("OPEN") .setKee("7b112bd4-b650-4037-80bc-82fd47d4eac2") + .setSeverity("MAJOR") .setAssignee("alice"); IssueDto issue3 = IssueTesting.newDto(rule, file, project) + .setIssueCreationDate(DateUtils.parseDate("2014-09-04")) + .setIssueUpdateDate(DateUtils.parseDate("2017-12-04")) + .setDebt(10L) .setStatus("OPEN") - .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2"); + .setKee("82fd47d4-4037-b650-80bc-7b112bd4eac2") + .setSeverity("MAJOR"); db.issueDao().insert(session, issue1, issue2, issue3); session.commit(); tester.get(IssueIndexer.class).indexAll(); + MockUserSession.set().setLogin("john-bob.polop"); wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION) .setParam("resolved", "false") - .setParam("assignees", "__me__") + .setParam("assignees", "alice") + .setParam(WebService.Param.FACETS, "assignees,assigned_to_me") .execute() - .assertJson(this.getClass(), "empty_result.json", false); + .assertJson(this.getClass(), "assigned_to_me_facet_sticky.json", false); } @Test diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/assigned_to_me_facet_sticky.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/assigned_to_me_facet_sticky.json new file mode 100644 index 00000000000..4db42bbaa41 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/assigned_to_me_facet_sticky.json @@ -0,0 +1,42 @@ +{ + "issues": [ + { + "key": "7b112bd4-b650-4037-80bc-82fd47d4eac2", + "component": "MyComponent", + "project": "MyProject", + "rule": "xoo:x1", + "status": "OPEN", + "severity": "MAJOR", + "debt": "10min", + "fUpdateAge": "less than a minute", + "assignee": "alice" + } + ], + "facets": [ + { + "property": "assignees", + "values": [ + { + "val": "john-bob.polop", + "count": 1 + }, + { + "val": "alice", + "count": 1 + }, + { + "val": "", + "count": 1 + } + ] + }, + { + "property": "assigned_to_me", + "values": [ + { + "val": "john-bob.polop", + "count": 1 + } + ] + } + ]} -- 2.39.5