aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2015-02-05 13:37:25 +0100
committerSimon Brandhof <simon.brandhof@sonarsource.com>2015-02-09 11:41:05 +0100
commit0ea7c0cedcadefe53e5ea7aab1e66592c0cb9279 (patch)
tree0a2e73d6426086970cd82726b1436670f01202c6 /server
parent2d34b833738ddc86750d058aa11f1ffef75916c8 (diff)
downloadsonarqube-0ea7c0cedcadefe53e5ea7aab1e66592c0cb9279.tar.gz
sonarqube-0ea7c0cedcadefe53e5ea7aab1e66592c0cb9279.zip
Refactor issue search stack in order to remove dependency with
SearchRequestHandler
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/IssueIndexBenchmarkTest.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/ProjectCleaner.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/BaseIndex.java35
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/EsUtils.java65
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/Facets.java153
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/SearchOptions.java179
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/SearchResult.java58
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/Action.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java55
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java42
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java65
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java30
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java612
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java19
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/BaseIssuesWsAction.java (renamed from server/sonar-server/src/main/java/org/sonar/server/issue/index/FakeIssueDto.java)15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java36
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java248
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/SetTagsAction.java21
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/search/StickyFacetBuilder.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java12
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json11
-rw-r--r--server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/ProjectCleanerTest.java41
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/es/EsUtilsTest.java69
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/es/SearchOptionsTest.java156
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java9
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java40
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java682
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java81
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java17
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java608
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/AuthorsActionTest.java5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueTagsActionTest.java5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java236
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java13
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java22
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/default_page_size_is_100.json1
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/deprecated_paging.json1
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/empty_result.json1
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue.json1
55 files changed, 2163 insertions, 1639 deletions
diff --git a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/IssueIndexBenchmarkTest.java b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/IssueIndexBenchmarkTest.java
index 64950c865d7..4d2a9de9f5b 100644
--- a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/IssueIndexBenchmarkTest.java
+++ b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/IssueIndexBenchmarkTest.java
@@ -34,14 +34,14 @@ import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.index.IssueAuthorizationDao;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
@@ -138,7 +138,7 @@ public class IssueIndexBenchmarkTest {
IssueIndex index = tester.get(IssueIndex.class);
for (int i = 0; i < 10; i++) {
long start = System.currentTimeMillis();
- Result<Issue> result = index.search(query, new QueryContext());
+ SearchResult<IssueDoc> result = index.search(query, new SearchOptions());
long end = System.currentTimeMillis();
LOGGER.info("Request (" + label + "): {} docs in {} ms", result.getTotal(), end - start);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/ProjectCleaner.java b/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/ProjectCleaner.java
index 021f88ebdaf..dd9a2d955ec 100644
--- a/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/ProjectCleaner.java
+++ b/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/ProjectCleaner.java
@@ -28,10 +28,13 @@ import org.sonar.api.config.Settings;
import org.sonar.api.utils.TimeUtils;
import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
import org.sonar.core.persistence.DbSession;
-import org.sonar.core.purge.*;
+import org.sonar.core.purge.IdUuidPair;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeListener;
+import org.sonar.core.purge.PurgeProfiler;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.properties.ProjectSettingsFactory;
-import org.sonar.server.search.IndexClient;
import javax.annotation.Nullable;
import java.util.Date;
@@ -46,16 +49,16 @@ public class ProjectCleaner implements ServerComponent {
private final PurgeDao purgeDao;
private final DefaultPeriodCleaner periodCleaner;
private final ProjectSettingsFactory projectSettingsFactory;
- private final IndexClient indexClient;
+ private final IssueIndex issueIndex;
public ProjectCleaner(PurgeDao purgeDao, DefaultPeriodCleaner periodCleaner, PurgeProfiler profiler, PurgeListener purgeListener,
- ProjectSettingsFactory projectSettingsFactory, IndexClient indexClient) {
+ ProjectSettingsFactory projectSettingsFactory, IssueIndex issueIndex) {
this.purgeDao = purgeDao;
this.periodCleaner = periodCleaner;
this.profiler = profiler;
this.purgeListener = purgeListener;
this.projectSettingsFactory = projectSettingsFactory;
- this.indexClient = indexClient;
+ this.issueIndex = issueIndex;
}
public ProjectCleaner purge(DbSession session, IdUuidPair idUuidPair) {
@@ -77,7 +80,7 @@ public class ProjectCleaner implements ServerComponent {
private void deleteIndexedIssuesBefore(String uuid, @Nullable Date lastDateWithClosedIssues) {
if (lastDateWithClosedIssues != null) {
- indexClient.get(IssueIndex.class).deleteClosedIssuesOfProjectBefore(uuid, lastDateWithClosedIssues);
+ issueIndex.deleteClosedIssuesOfProjectBefore(uuid, lastDateWithClosedIssues);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
index 22cbf6fe36e..ea6ac8f2980 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
@@ -19,10 +19,9 @@
*/
package org.sonar.server.db;
-import org.sonar.core.user.AuthorDao;
-
import org.sonar.api.ServerComponent;
import org.sonar.core.issue.db.ActionPlanDao;
+import org.sonar.core.issue.db.IssueChangeDao;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.Database;
import org.sonar.core.persistence.DbSession;
@@ -33,6 +32,7 @@ import org.sonar.core.resource.ResourceDao;
import org.sonar.core.source.db.FileSourceDao;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.template.LoadedTemplateDao;
+import org.sonar.core.user.AuthorDao;
import org.sonar.core.user.AuthorizationDao;
import org.sonar.server.activity.db.ActivityDao;
import org.sonar.server.component.db.ComponentDao;
@@ -79,6 +79,7 @@ public class DbClient implements ServerComponent {
private final UserDao userDao;
private final GroupDao groupDao;
private final IssueDao issueDao;
+ private final IssueChangeDao issueChangeDao;
private final ActionPlanDao actionPlanDao;
private final AnalysisReportDao analysisReportDao;
private final DashboardDao dashboardDao;
@@ -111,6 +112,7 @@ public class DbClient implements ServerComponent {
userDao = getDao(map, UserDao.class);
groupDao = getDao(map, GroupDao.class);
issueDao = getDao(map, IssueDao.class);
+ issueChangeDao = getDao(map, IssueChangeDao.class);
actionPlanDao = getDao(map, ActionPlanDao.class);
analysisReportDao = getDao(map, AnalysisReportDao.class);
dashboardDao = getDao(map, DashboardDao.class);
@@ -140,6 +142,10 @@ public class DbClient implements ServerComponent {
return issueDao;
}
+ public IssueChangeDao issueChangeDao() {
+ return issueChangeDao;
+ }
+
public QualityProfileDao qualityProfileDao() {
return qualityProfileDao;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/BaseIndex.java b/server/sonar-server/src/main/java/org/sonar/server/es/BaseIndex.java
new file mode 100644
index 00000000000..45d253555b3
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/BaseIndex.java
@@ -0,0 +1,35 @@
+/*
+ * 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.es;
+
+import org.sonar.api.ServerComponent;
+
+public abstract class BaseIndex implements ServerComponent {
+ private final EsClient client;
+
+ public BaseIndex(EsClient client) {
+ this.client = client;
+ }
+
+ public EsClient getClient() {
+ return client;
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/EsUtils.java b/server/sonar-server/src/main/java/org/sonar/server/es/EsUtils.java
new file mode 100644
index 00000000000..837754cf20a
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/EsUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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.es;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.SearchHits;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+import org.sonar.server.search.BaseDoc;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class EsUtils {
+
+ private EsUtils() {
+ // only static methods
+ }
+
+ public static <D extends BaseDoc> List<D> convertToDocs(SearchHits hits, Function<Map<String, Object>, D> converter) {
+ List<D> docs = new ArrayList<>();
+ for (SearchHit hit : hits.getHits()) {
+ docs.add(converter.apply(hit.getSource()));
+ }
+ return docs;
+ }
+
+ public static LinkedHashMap<String, Long> termsToMap(Terms terms) {
+ LinkedHashMap<String, Long> map = new LinkedHashMap<>();
+ List<Terms.Bucket> buckets = terms.getBuckets();
+ for (Terms.Bucket bucket : buckets) {
+ map.put(bucket.getKey(), bucket.getDocCount());
+ }
+ return map;
+ }
+
+ public static List<String> termsKeys(Terms terms) {
+ return Lists.transform(terms.getBuckets(), new Function<Terms.Bucket, String>() {
+ @Override
+ public String apply(Terms.Bucket bucket) {
+ return bucket.getKey();
+ }
+ });
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/Facets.java b/server/sonar-server/src/main/java/org/sonar/server/es/Facets.java
new file mode 100644
index 00000000000..a22131e18f3
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/Facets.java
@@ -0,0 +1,153 @@
+/*
+ * 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.es;
+
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.search.aggregations.Aggregation;
+import org.elasticsearch.search.aggregations.HasAggregations;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram;
+import org.elasticsearch.search.aggregations.bucket.missing.Missing;
+import org.elasticsearch.search.aggregations.bucket.terms.Terms;
+
+import javax.annotation.CheckForNull;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class Facets {
+
+ private final Map<String, LinkedHashMap<String, Long>> facetsByName = new LinkedHashMap<>();
+
+ public Facets(SearchResponse response) {
+ if (response.getAggregations() != null) {
+ for (Aggregation facet : response.getAggregations()) {
+ processAggregation(facet);
+ }
+ }
+ }
+
+ public Facets(Terms terms) {
+ processTermsAggregation(terms);
+ }
+
+ private void processAggregation(Aggregation aggregation) {
+ if (Missing.class.isAssignableFrom(aggregation.getClass())) {
+ processMissingAggregation((Missing) aggregation);
+ } else if (Terms.class.isAssignableFrom(aggregation.getClass())) {
+ processTermsAggregation((Terms) aggregation);
+ } else if (HasAggregations.class.isAssignableFrom(aggregation.getClass())) {
+ processSubAggregations((HasAggregations) aggregation);
+ } else if (DateHistogram.class.isAssignableFrom(aggregation.getClass())) {
+ processDateHistogram((DateHistogram) aggregation);
+ } else {
+ throw new IllegalArgumentException("Aggregation type not supported yet: " + aggregation.getClass());
+ }
+ }
+
+ private void processMissingAggregation(Missing aggregation) {
+ long docCount = aggregation.getDocCount();
+ if (docCount > 0L) {
+ getOrCreateFacet(aggregation.getName().replace("_missing", "")).put("", docCount);
+ }
+ }
+
+ private void processTermsAggregation(Terms aggregation) {
+ String facetName = aggregation.getName();
+ // TODO document this naming convention
+ if (facetName.contains("__") && !facetName.startsWith("__")) {
+ facetName = facetName.substring(0, facetName.indexOf("__"));
+ }
+ facetName = facetName.replace("_selected", "");
+ LinkedHashMap<String, Long> facet = getOrCreateFacet(facetName);
+ for (Terms.Bucket value : aggregation.getBuckets()) {
+ facet.put(value.getKey(), value.getDocCount());
+ }
+ }
+
+ private void processSubAggregations(HasAggregations aggregation) {
+ for (Aggregation sub : aggregation.getAggregations()) {
+ processAggregation(sub);
+ }
+ }
+
+ private void processDateHistogram(DateHistogram aggregation) {
+ LinkedHashMap<String, Long> facet = getOrCreateFacet(aggregation.getName());
+ for (DateHistogram.Bucket value : aggregation.getBuckets()) {
+ facet.put(value.getKeyAsText().toString(), value.getDocCount());
+ }
+ }
+
+ public boolean contains(String facetName) {
+ return facetsByName.containsKey(facetName);
+ }
+
+ /**
+ * The buckets of the given facet. Null if the facet does not exist
+ */
+ @CheckForNull
+ public LinkedHashMap<String, Long> get(String facetName) {
+ return facetsByName.get(facetName);
+ }
+
+ public Map<String, LinkedHashMap<String, Long>> getAll() {
+ return facetsByName;
+ }
+
+ /**
+ * Value of the facet bucket. Null if the facet or the bucket do not exist.
+ */
+ @CheckForNull
+ public Long getBucketValue(String facetName, String bucketKey) {
+ LinkedHashMap<String, Long> facet = facetsByName.get(facetName);
+ if (facet != null) {
+ return facet.get(bucketKey);
+ }
+ return null;
+ }
+
+ public Set<String> getBucketKeys(String facetName) {
+ LinkedHashMap<String, Long> facet = facetsByName.get(facetName);
+ if (facet != null) {
+ return facet.keySet();
+ }
+ return Collections.emptySet();
+ }
+
+ public Set<String> getNames() {
+ return facetsByName.keySet();
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
+ }
+
+ private LinkedHashMap<String, Long> getOrCreateFacet(String facetName) {
+ LinkedHashMap<String, Long> facet = facetsByName.get(facetName);
+ if (facet == null) {
+ facet = new LinkedHashMap<>();
+ facetsByName.put(facetName, facet);
+ }
+ return facet;
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/SearchOptions.java b/server/sonar-server/src/main/java/org/sonar/server/es/SearchOptions.java
new file mode 100644
index 00000000000..57cf4904cef
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/SearchOptions.java
@@ -0,0 +1,179 @@
+/*
+ * 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.es;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.text.JsonWriter;
+
+import javax.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Various Elasticsearch request options: paging, fields and facets
+ */
+public class SearchOptions {
+
+ public static final int DEFAULT_OFFSET = 0;
+ public static final int DEFAULT_LIMIT = 10;
+ public static final int MAX_LIMIT = 500;
+
+ private int offset = DEFAULT_OFFSET;
+ private int limit = DEFAULT_LIMIT;
+ private final Set<String> facets = new LinkedHashSet<>();
+ private final Set<String> fieldsToReturn = new HashSet<>();
+
+ /**
+ * Offset of the first result to return. Defaults to {@link #DEFAULT_OFFSET}
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Sets the offset of the first result to return (zero-based).
+ */
+ public SearchOptions setOffset(int offset) {
+ Preconditions.checkArgument(offset >= 0, "Offset must be positive");
+ this.offset = offset;
+ return this;
+ }
+
+ /**
+ * Set offset and limit according to page approach. If pageSize is negative, then
+ * {@link #MAX_LIMIT} is used.
+ */
+ public SearchOptions setPage(int page, int pageSize) {
+ Preconditions.checkArgument(page >= 1, "Page must be greater or equal to 1 (got " + page + ")");
+ setLimit(pageSize);
+ setOffset((page * this.limit) - this.limit);
+ return this;
+ }
+
+ public int getPage() {
+ return limit > 0 ? (int) Math.ceil((double) (offset + 1) / (double) limit) : 0;
+ }
+
+ /**
+ * Limit on the number of results to return. Defaults to {@link #DEFAULT_LIMIT}.
+ */
+ public int getLimit() {
+ return limit;
+ }
+
+ /**
+ * Sets the limit on the number of results to return.
+ */
+ public SearchOptions setLimit(int limit) {
+ if (limit < 0) {
+ this.limit = MAX_LIMIT;
+ } else {
+ this.limit = Math.min(limit, MAX_LIMIT);
+ }
+ return this;
+ }
+
+ /**
+ * WARNING - dangerous
+ */
+ @Deprecated
+ public SearchOptions disableLimit() {
+ this.limit = 999999;
+ return this;
+ }
+
+ /**
+ * Lists selected facets.
+ */
+ public Collection<String> getFacets() {
+ return facets;
+ }
+
+ /**
+ * Selects facets to return for the domain.
+ */
+ public SearchOptions addFacets(@Nullable Collection<String> f) {
+ if (f != null) {
+ this.facets.addAll(f);
+ }
+ return this;
+ }
+
+ public SearchOptions addFacets(String... array) {
+ Collections.addAll(facets, array);
+ return this;
+ }
+
+ public Set<String> getFields() {
+ return fieldsToReturn;
+ }
+
+ public boolean hasField(String key) {
+ return fieldsToReturn.isEmpty() || fieldsToReturn.contains(key);
+ }
+
+ public SearchOptions addFields(@Nullable Collection<String> c) {
+ if (c != null) {
+ for (String s : c) {
+ if (StringUtils.isNotBlank(s)) {
+ fieldsToReturn.add(s);
+ }
+ }
+ }
+ return this;
+ }
+
+ public SearchOptions addFields(String... array) {
+ return addFields(Arrays.asList(array));
+ }
+
+ public SearchOptions writeJson(JsonWriter json, long totalHits) {
+ json.prop("total", totalHits);
+ json.prop(WebService.Param.PAGE, getPage());
+ json.prop(WebService.Param.PAGE_SIZE, getLimit());
+ return this;
+ }
+
+ @Deprecated
+ public SearchOptions writeDeprecatedJson(JsonWriter json, long totalHits) {
+ int pages = 0;
+ if (limit > 0) {
+ pages = (int) (totalHits / limit);
+ if (totalHits % limit > 0) {
+ pages++;
+ }
+ }
+ json.name("paging").beginObject()
+ .prop("pageIndex", getPage())
+ .prop("pageSize", getLimit())
+ .prop("total", totalHits)
+ .prop("fTotal", String.valueOf(totalHits))
+ .prop("pages", pages)
+ .endObject();
+ return this;
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/SearchResult.java b/server/sonar-server/src/main/java/org/sonar/server/es/SearchResult.java
new file mode 100644
index 00000000000..731f48730cc
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/SearchResult.java
@@ -0,0 +1,58 @@
+/*
+ * 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.es;
+
+import com.google.common.base.Function;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.sonar.server.search.BaseDoc;
+
+import java.util.List;
+import java.util.Map;
+
+public class SearchResult<DOC extends BaseDoc> {
+
+ private final List<DOC> docs;
+ private final Facets facets;
+ private final long total;
+
+ public SearchResult(SearchResponse response, Function<Map<String, Object>, DOC> converter) {
+ this.facets = new Facets(response);
+ this.total = response.getHits().totalHits();
+ this.docs = EsUtils.convertToDocs(response.getHits(), converter);
+ }
+
+ public List<DOC> getDocs() {
+ return docs;
+ }
+
+ public long getTotal() {
+ return total;
+ }
+
+ public Facets getFacets() {
+ return this.facets;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this);
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java
index d5a0c629341..7aa68b28e11 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/AbstractChangeTagsAction.java
@@ -32,11 +32,9 @@ import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
import java.util.Set;
-
public abstract class AbstractChangeTagsAction extends Action implements ServerComponent {
private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();
@@ -50,7 +48,7 @@ public abstract class AbstractChangeTagsAction extends Action implements ServerC
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession){
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
parseTags(properties);
return true;
}
@@ -67,7 +65,7 @@ public abstract class AbstractChangeTagsAction extends Action implements ServerC
Set<String> result = Sets.newHashSet();
String tagsString = (String) properties.get("tags");
if (!Strings.isNullOrEmpty(tagsString)) {
- for(String tag: TAGS_SPLITTER.split(tagsString)) {
+ for (String tag : TAGS_SPLITTER.split(tagsString)) {
RuleTagFormat.validate(tag);
result.add(tag);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java b/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java
index e7224a79129..715e725df6e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/Action.java
@@ -29,6 +29,7 @@ import org.sonar.api.issue.condition.Condition;
import org.sonar.api.issue.internal.IssueChangeContext;
import org.sonar.server.user.UserSession;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -70,7 +71,7 @@ public abstract class Action implements ServerComponent {
return true;
}
- abstract boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession);
+ abstract boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession);
abstract boolean execute(Map<String, Object> properties, Context context);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
index d6ead7dd524..8beab29d430 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
@@ -30,7 +30,7 @@ import org.sonar.api.user.UserFinder;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
@@ -50,7 +50,7 @@ public class AssignAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession){
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession){
String assignee = assigneeValue(properties);
if(!Strings.isNullOrEmpty(assignee)) {
User user = selectUser(assignee);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
index e50eba29d08..d8700f55600 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
@@ -27,10 +27,9 @@ import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
-
public class CommentAction extends Action implements ServerComponent {
public static final String KEY = "comment";
@@ -44,7 +43,7 @@ public class CommentAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
comment(properties);
return true;
}
@@ -58,7 +57,7 @@ public class CommentAction extends Action implements ServerComponent {
private String comment(Map<String, Object> properties) {
String param = (String) properties.get(COMMENT_PROPERTY);
if (Strings.isNullOrEmpty(param)) {
- throw new IllegalArgumentException("Missing parameter : '"+ COMMENT_PROPERTY +"'");
+ throw new IllegalArgumentException("Missing parameter : '" + COMMENT_PROPERTY + "'");
}
return param;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
index e60b31e6323..d20fc825c44 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
@@ -43,6 +43,7 @@ import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceQuery;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.issue.filter.IssueFilterParameters;
@@ -477,7 +478,7 @@ public class InternalRubyIssueService implements ServerComponent {
* Execute issue filter from parameters
*/
public IssueFilterService.IssueFilterResult execute(Map<String, Object> props) {
- return issueFilterService.execute(issueQueryService.createFromMap(props), toContext(props));
+ return issueFilterService.execute(issueQueryService.createFromMap(props), toSearchOptions(props));
}
/**
@@ -636,16 +637,16 @@ public class InternalRubyIssueService implements ServerComponent {
}
@VisibleForTesting
- static QueryContext toContext(Map<String, Object> props) {
- QueryContext context = new QueryContext();
+ static SearchOptions toSearchOptions(Map<String, Object> props) {
+ SearchOptions options = new SearchOptions();
Integer pageIndex = RubyUtils.toInteger(props.get(IssueFilterParameters.PAGE_INDEX));
Integer pageSize = RubyUtils.toInteger(props.get(IssueFilterParameters.PAGE_SIZE));
if (pageSize != null && pageSize < 0) {
- context.setMaxLimit();
+ options.setLimit(SearchOptions.MAX_LIMIT);
} else {
- context.setPage(pageIndex != null ? pageIndex : 1, pageSize != null ? pageSize : 100);
+ options.setPage(pageIndex != null ? pageIndex : 1, pageSize != null ? pageSize : 100);
}
- return context;
+ return options;
}
public Collection<String> listTags() {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
index f235a36e71d..d29e4a4eabe 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
@@ -22,7 +22,9 @@ package org.sonar.server.issue;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.issue.Issue;
@@ -35,16 +37,20 @@ import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.db.IssueDto;
import org.sonar.core.issue.db.IssueStorage;
import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.notification.IssueChangeNotification;
import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
@@ -83,12 +89,12 @@ public class IssueBulkChangeService {
IssueBulkChangeResult result = new IssueBulkChangeResult();
- List<Issue> issues = getByKeysForUpdate(issueBulkChangeQuery.issues());
+ Collection<Issue> issues = getByKeysForUpdate(issueBulkChangeQuery.issues());
Repository repository = new Repository(issues);
List<Action> bulkActions = getActionsToApply(issueBulkChangeQuery, issues, userSession);
IssueChangeContext issueChangeContext = IssueChangeContext.createUser(new Date(), userSession.login());
- Set<String> concernedProjects = new HashSet<String>();
+ Set<String> concernedProjects = new HashSet<>();
for (Issue issue : issues) {
ActionContext actionContext = new ActionContext(issue, issueChangeContext);
for (Action action : bulkActions) {
@@ -119,31 +125,36 @@ public class IssueBulkChangeService {
return result;
}
- private List<Issue> getByKeysForUpdate(List<String> issueKeys) {
+ private Collection<Issue> getByKeysForUpdate(List<String> issueKeys) {
// Load from index to check permission
- List<Issue> authorizedIndexIssues = issueService.search(IssueQuery.builder().issueKeys(issueKeys).build(), new QueryContext().setMaxLimit()).getHits();
- List<String> authorizedIssueKeys = newArrayList(Iterables.transform(authorizedIndexIssues, new Function<Issue, String>() {
+ SearchOptions options = new SearchOptions().setLimit(SearchOptions.MAX_LIMIT);
+ // TODO restrict fields to issue key, in order to not load all other fields;
+ List<IssueDoc> authorizedIssues = issueService.search(IssueQuery.builder().issueKeys(issueKeys).build(), options).getDocs();
+ Collection<String> authorizedKeys = Collections2.transform(authorizedIssues, new Function<IssueDoc, String>() {
@Override
- public String apply(@Nullable Issue input) {
- return input != null ? input.key() : null;
+ public String apply(IssueDoc input) {
+ return input.key();
}
- }));
+ });
- DbSession session = dbClient.openSession(false);
- try {
- List<IssueDto> issueDtos = dbClient.issueDao().selectByKeys(session, authorizedIssueKeys);
- return newArrayList(Iterables.transform(issueDtos, new Function<IssueDto, Issue>() {
- @Override
- public Issue apply(@Nullable IssueDto input) {
- return input != null ? input.toDefaultIssue() : null;
- }
- }));
- } finally {
- session.close();
+ if (!authorizedKeys.isEmpty()) {
+ DbSession session = dbClient.openSession(false);
+ try {
+ List<IssueDto> dtos = dbClient.issueDao().selectByKeys(session, Lists.newArrayList(authorizedKeys));
+ return Collections2.transform(dtos, new Function<IssueDto, Issue>() {
+ @Override
+ public Issue apply(@Nullable IssueDto input) {
+ return input != null ? input.toDefaultIssue() : null;
+ }
+ });
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
}
+ return Collections.emptyList();
}
- private List<Action> getActionsToApply(IssueBulkChangeQuery issueBulkChangeQuery, List<Issue> issues, UserSession userSession) {
+ private List<Action> getActionsToApply(IssueBulkChangeQuery issueBulkChangeQuery, Collection<Issue> issues, UserSession userSession) {
List<Action> bulkActions = newArrayList();
for (String actionKey : issueBulkChangeQuery.actions()) {
Action action = getAction(actionKey);
@@ -207,7 +218,7 @@ public class IssueBulkChangeService {
private final Map<String, ComponentDto> components = newHashMap();
private final Map<String, ComponentDto> projects = newHashMap();
- public Repository(List<Issue> issues) {
+ public Repository(Collection<Issue> issues) {
Set<RuleKey> ruleKeys = newHashSet();
Set<String> componentKeys = newHashSet();
Set<String> projectKeys = newHashSet();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java
index 8067ca37021..94ff60ae58f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java
@@ -24,15 +24,17 @@ import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.server.search.QueryContext;
+import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
+import static com.google.common.collect.Sets.newHashSet;
+
/**
* @since 3.6
*/
@@ -84,6 +86,10 @@ public class IssueQuery {
private final Boolean ignorePaging;
private final Boolean contextualized;
+ private final String userLogin;
+ private final Set<String> userGroups;
+ private final boolean checkAuthorization;
+
private IssueQuery(Builder builder) {
this.issueKeys = defaultCollection(builder.issueKeys);
this.severities = defaultCollection(builder.severities);
@@ -114,6 +120,9 @@ public class IssueQuery {
this.sort = builder.sort;
this.asc = builder.asc;
this.ignorePaging = builder.ignorePaging;
+ this.userLogin = builder.userLogin;
+ this.userGroups = builder.userGroups;
+ this.checkAuthorization = builder.checkAuthorization;
this.contextualized = builder.contextualized;
}
@@ -248,6 +257,19 @@ public class IssueQuery {
}
@CheckForNull
+ public String userLogin() {
+ return userLogin;
+ }
+
+ public Set<String> userGroups() {
+ return newHashSet(defaultCollection(userGroups));
+ }
+
+ public boolean checkAuthorization() {
+ return checkAuthorization;
+ }
+
+ @CheckForNull
public Boolean isContextualized() {
return contextualized;
}
@@ -292,6 +314,9 @@ public class IssueQuery {
private Boolean asc = false;
private Boolean ignorePaging = false;
private boolean contextualized;
+ private String userLogin = UserSession.get().login();
+ private Set<String> userGroups = UserSession.get().userGroups();
+ private boolean checkAuthorization = true;
private Builder() {
}
@@ -475,6 +500,21 @@ public class IssueQuery {
return this;
}
+ public Builder userLogin(@Nullable String userLogin) {
+ this.userLogin = userLogin;
+ return this;
+ }
+
+ public Builder userGroups(@Nullable Set<String> userGroups) {
+ this.userGroups = userGroups;
+ return this;
+ }
+
+ public Builder checkAuthorization(boolean checkAuthorization) {
+ this.checkAuthorization = checkAuthorization;
+ return this;
+ }
+
public Builder setContextualized(boolean b) {
this.contextualized = b;
return this;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
index 0c893e2fe79..6379acc899f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
@@ -48,13 +48,13 @@ import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.rule.RuleDto;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.actionplan.ActionPlanService;
+import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.notification.IssueChangeNotification;
-import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.source.index.SourceLineDoc;
import org.sonar.server.source.index.SourceLineIndex;
import org.sonar.server.user.UserSession;
@@ -64,14 +64,20 @@ import org.sonar.server.user.index.UserIndex;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
import static com.google.common.collect.Maps.newLinkedHashMap;
public class IssueService implements ServerComponent {
private final DbClient dbClient;
- private final IndexClient indexClient;
+ private final IssueIndex issueIndex;
private final IssueWorkflow workflow;
private final IssueUpdater issueUpdater;
@@ -84,7 +90,7 @@ public class IssueService implements ServerComponent {
private final UserIndex userIndex;
private final SourceLineIndex sourceLineIndex;
- public IssueService(DbClient dbClient, IndexClient indexClient,
+ public IssueService(DbClient dbClient, IssueIndex issueIndex,
IssueWorkflow workflow,
IssueStorage issueStorage,
IssueUpdater issueUpdater,
@@ -95,7 +101,7 @@ public class IssueService implements ServerComponent {
UserFinder userFinder,
UserIndex userIndex, SourceLineIndex sourceLineIndex) {
this.dbClient = dbClient;
- this.indexClient = indexClient;
+ this.issueIndex = issueIndex;
this.workflow = workflow;
this.issueStorage = issueStorage;
this.issueUpdater = issueUpdater;
@@ -301,19 +307,20 @@ public class IssueService implements ServerComponent {
public Map<String, Long> findIssueAssignees(IssueQuery query) {
Map<String, Long> result = newLinkedHashMap();
- List<FacetValue> facetValues = indexClient.get(IssueIndex.class).listAssignees(query);
- for (FacetValue facetValue : facetValues) {
- if ("_notAssigned_".equals(facetValue.getKey())) {
- result.put(null, facetValue.getValue());
+ Map<String,Long> buckets = issueIndex.searchForAssignees(query);
+ for (Map.Entry<String, Long> bucket : buckets.entrySet()) {
+ if ("_notAssigned_".equals(bucket.getKey())) {
+ // TODO null key ?
+ result.put(null, bucket.getValue());
} else {
- result.put(facetValue.getKey(), facetValue.getValue());
+ result.put(bucket.getKey(), bucket.getValue());
}
}
return result;
}
public Issue getByKey(String key) {
- return indexClient.get(IssueIndex.class).getByKey(key);
+ return issueIndex.getByKey(key);
}
IssueDto getByKeyForUpdate(DbSession session, String key) {
@@ -346,20 +353,29 @@ public class IssueService implements ServerComponent {
return ruleFinder.findByKey(ruleKey);
}
- public org.sonar.server.search.Result<Issue> search(IssueQuery query, QueryContext options) {
- return indexClient.get(IssueIndex.class).search(query, options);
+ public SearchResult<IssueDoc> search(IssueQuery query, SearchOptions options) {
+ return issueIndex.search(query, options);
}
private void verifyLoggedIn() {
UserSession.get().checkLoggedIn();
}
- public Collection<String> listTags(@Nullable String query, int pageSize) {
- return indexClient.get(IssueIndex.class).listTagsMatching(query, pageSize);
+ /**
+ * Search for all tags, whatever issue resolution or user access rights
+ */
+ public List<String> listTags(@Nullable String textQuery, int pageSize) {
+ IssueQuery query = IssueQuery.builder()
+ .checkAuthorization(false)
+ .build();
+ return issueIndex.listTags(query, textQuery, pageSize);
}
- public Collection<String> listAuthors(@Nullable String query, int pageSize) {
- return indexClient.get(IssueIndex.class).listAuthorsMatching(query, pageSize);
+ public List<String> listAuthors(@Nullable String textQuery, int pageSize) {
+ IssueQuery query = IssueQuery.builder()
+ .checkAuthorization(false)
+ .build();
+ return issueIndex.listAuthors(query, textQuery, pageSize);
}
public Collection<String> setTags(String issueKey, Collection<String> tags) {
@@ -379,8 +395,17 @@ public class IssueService implements ServerComponent {
}
}
+ // TODO check compatibility with Views, projects, etc.
public Map<String, Long> listTagsForComponent(String componentUuid, int pageSize) {
- return indexClient.get(IssueIndex.class).listTagsForComponent(componentUuid, pageSize);
+ IssueQuery query = IssueQuery.builder()
+ .userLogin(UserSession.get().login())
+ .userGroups(UserSession.get().userGroups())
+ .moduleRootUuids(Arrays.asList(componentUuid))
+ .onComponentOnly(false)
+ .setContextualized(true)
+ .resolved(false)
+ .build();
+ return issueIndex.countTags(query, pageSize);
}
@CheckForNull
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
index 49aa95a09ac..1bf7d3ee49b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
@@ -30,10 +30,9 @@ import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
-
public class PlanAction extends Action implements ServerComponent {
public static final String KEY = "plan";
@@ -50,7 +49,7 @@ public class PlanAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
String actionPlanValue = planValue(properties);
if (!Strings.isNullOrEmpty(actionPlanValue)) {
ActionPlan actionPlan = selectActionPlan(actionPlanValue, userSession);
@@ -67,7 +66,7 @@ public class PlanAction extends Action implements ServerComponent {
@Override
public boolean execute(Map<String, Object> properties, Context context) {
- if(!properties.containsKey(VERIFIED_ACTION_PLAN)) {
+ if (!properties.containsKey(VERIFIED_ACTION_PLAN)) {
throw new IllegalArgumentException("Action plan is missing from the execution parameters");
}
ActionPlan actionPlan = (ActionPlan) properties.get(VERIFIED_ACTION_PLAN);
@@ -78,7 +77,7 @@ public class PlanAction extends Action implements ServerComponent {
return (String) properties.get("plan");
}
- private void verifyIssuesAreAllRelatedOnActionPlanProject(List<Issue> issues, ActionPlan actionPlan) {
+ private void verifyIssuesAreAllRelatedOnActionPlanProject(Collection<Issue> issues, ActionPlan actionPlan) {
String projectKey = actionPlan.projectKey();
for (Issue issue : issues) {
DefaultIssue defaultIssue = (DefaultIssue) issue;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
index a48f22c4e2a..7a8efdc62b4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
@@ -30,7 +30,7 @@ import org.sonar.api.web.UserRole;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
public class SetSeverityAction extends Action implements ServerComponent {
@@ -45,7 +45,7 @@ public class SetSeverityAction extends Action implements ServerComponent {
super.setConditions(new IsUnResolved(), new Condition() {
@Override
public boolean matches(Issue issue) {
- return isCurrentUserIssueAdmin(((DefaultIssue) issue).projectKey());
+ return isCurrentUserIssueAdmin(issue.projectKey());
}
});
}
@@ -55,7 +55,7 @@ public class SetSeverityAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
severity(properties);
return true;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
index b2c39ccaa9b..bb18afbfdda 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
@@ -31,7 +31,7 @@ import org.sonar.core.issue.workflow.IssueWorkflow;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
public class TransitionAction extends Action implements ServerComponent {
@@ -46,7 +46,7 @@ public class TransitionAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ public boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
transition(properties);
return true;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java b/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
index f8bd5f91d53..958135fb50d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueDao.java
@@ -28,8 +28,6 @@ import org.sonar.core.persistence.MyBatis;
import org.sonar.server.exceptions.NotFoundException;
import javax.annotation.CheckForNull;
-
-import java.util.Collection;
import java.util.List;
public class IssueDao extends org.sonar.core.issue.db.IssueDao implements DaoComponent {
@@ -55,7 +53,7 @@ public class IssueDao extends org.sonar.core.issue.db.IssueDao implements DaoCom
return mapper(session).selectByActionPlan(actionPlan);
}
- public List<IssueDto> selectByKeys(DbSession session, Collection<String> keys) {
+ public List<IssueDto> selectByKeys(DbSession session, List<String> keys) {
return mapper(session).selectByKeys(keys);
}
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 bf53ae3f6c3..df6025a9b34 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
@@ -25,7 +25,6 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import org.sonar.api.ServerComponent;
-import org.sonar.api.issue.Issue;
import org.sonar.api.utils.Paging;
import org.sonar.core.issue.DefaultIssueFilter;
import org.sonar.core.issue.IssueFilterSerializer;
@@ -35,14 +34,15 @@ import org.sonar.core.issue.db.IssueFilterFavouriteDao;
import org.sonar.core.issue.db.IssueFilterFavouriteDto;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.user.AuthorizationDao;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.issue.IssueQuery;
+import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
@@ -61,8 +61,8 @@ public class IssueFilterService implements ServerComponent {
private final IssueFilterSerializer serializer;
public IssueFilterService(IssueFilterDao filterDao, IssueFilterFavouriteDao favouriteDao,
- IssueIndex issueIndex, AuthorizationDao authorizationDao,
- IssueFilterSerializer serializer) {
+ IssueIndex issueIndex, AuthorizationDao authorizationDao,
+ IssueFilterSerializer serializer) {
this.filterDao = filterDao;
this.favouriteDao = favouriteDao;
this.issueIndex = issueIndex;
@@ -70,8 +70,8 @@ public class IssueFilterService implements ServerComponent {
this.serializer = serializer;
}
- public IssueFilterResult execute(IssueQuery issueQuery, QueryContext context) {
- return createIssueFilterResult(issueIndex.search(issueQuery, context), context);
+ public IssueFilterResult execute(IssueQuery issueQuery, SearchOptions options) {
+ return createIssueFilterResult(issueIndex.search(issueQuery, options), options);
}
public DefaultIssueFilter find(Long id, UserSession userSession) {
@@ -335,8 +335,8 @@ public class IssueFilterService implements ServerComponent {
return authorizationDao.selectGlobalPermissions(user).contains(GlobalPermissions.SYSTEM_ADMIN);
}
- private IssueFilterResult createIssueFilterResult(Result<Issue> issues, QueryContext context) {
- return new IssueFilterResult(issues.getHits(), Paging.create(context.getLimit(), context.getPage(), ((Long) issues.getTotal()).intValue()));
+ private IssueFilterResult createIssueFilterResult(SearchResult<IssueDoc> issues, SearchOptions options) {
+ return new IssueFilterResult(issues.getDocs(), Paging.create(options.getLimit(), options.getPage(), (int) issues.getTotal()));
}
private boolean hasUserSharingPermission(String user) {
@@ -345,21 +345,21 @@ public class IssueFilterService implements ServerComponent {
public static class IssueFilterResult {
- private final List<Issue> issues;
+ private final List<IssueDoc> issues;
private final Paging paging;
- public IssueFilterResult(List<Issue> issues, Paging paging) {
+ public IssueFilterResult(List<IssueDoc> issues, Paging paging) {
this.issues = issues;
this.paging = paging;
}
- public List<Issue> issues(){
+ public List<IssueDoc> issues() {
return issues;
}
- public Paging paging(){
+ public Paging paging() {
return paging;
}
- }
-
+ }
+
}
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 42064038b10..6e42d8c5b21 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
@@ -20,24 +20,25 @@
package org.sonar.server.issue.index;
import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.BooleanUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
-import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.BoolFilterBuilder;
+import org.elasticsearch.index.query.FilterBuilder;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.OrFilterBuilder;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
-import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram.Interval;
+import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogram;
import org.elasticsearch.search.aggregations.bucket.missing.InternalMissing;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
-import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;
-import org.elasticsearch.search.aggregations.bucket.terms.Terms.Order;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.aggregations.metrics.min.Min;
import org.joda.time.Duration;
@@ -45,10 +46,16 @@ import org.sonar.api.issue.Issue;
import org.sonar.api.rule.Severity;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
+import org.sonar.server.es.BaseIndex;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.EsUtils;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.es.Sorting;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.filter.IssueFilterParameters;
-import org.sonar.server.search.*;
+import org.sonar.server.search.StickyFacetBuilder;
import org.sonar.server.user.UserSession;
import org.sonar.server.view.index.ViewIndexDefinition;
@@ -56,179 +63,155 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
import static com.google.common.collect.Lists.newArrayList;
-public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
-
+/**
+ * The unique entry-point to interact with Elasticsearch index "issues".
+ * All the requests are listed here.
+ */
+public class IssueIndex extends BaseIndex {
+
+ public static final List<String> SUPPORTED_FACETS = ImmutableList.of(
+ IssueFilterParameters.SEVERITIES,
+ IssueFilterParameters.STATUSES,
+ IssueFilterParameters.RESOLUTIONS,
+ IssueFilterParameters.ACTION_PLANS,
+ IssueFilterParameters.PROJECT_UUIDS,
+ IssueFilterParameters.RULES,
+ IssueFilterParameters.ASSIGNEES,
+ IssueFilterParameters.REPORTERS,
+ IssueFilterParameters.AUTHORS,
+ IssueFilterParameters.MODULE_UUIDS,
+ IssueFilterParameters.FILE_UUIDS,
+ IssueFilterParameters.DIRECTORIES,
+ IssueFilterParameters.LANGUAGES,
+ IssueFilterParameters.TAGS,
+ IssueFilterParameters.CREATED_AT);
+
+ // TODO to be documented
private static final String FILTER_COMPONENT_ROOT = "__componentRoot";
+ // TODO to be documented
+ // TODO move to Facets ?
private static final String FACET_SUFFIX_MISSING = "_missing";
- private static final int DEFAULT_ISSUE_FACET_SIZE = 15;
-
+ private static final int DEFAULT_FACET_SIZE = 15;
private static final Duration TWENTY_DAYS = Duration.standardDays(20L);
private static final Duration TWENTY_WEEKS = Duration.standardDays(20L * 7L);
private static final Duration TWENTY_MONTHS = Duration.standardDays(20L * 30L);
- private final Sorting sorting;
+ /**
+ * Convert an Elasticsearch result (a map) to an {@link org.sonar.server.issue.index.IssueDoc}. It's
+ * used for {@link org.sonar.server.es.SearchResult}.
+ */
+ private static final Function<Map<String, Object>, IssueDoc> DOC_CONVERTER = new Function<Map<String, Object>, IssueDoc>() {
+ @Override
+ public IssueDoc apply(Map<String, Object> input) {
+ return new IssueDoc(input);
+ }
+ };
+ private final Sorting sorting;
private final System2 system;
- public IssueIndex(SearchClient client, System2 system) {
- super(IndexDefinition.ISSUES, null, client);
- this.system = system;
+ public IssueIndex(EsClient client, System2 system) {
+ super(client);
- sorting = new Sorting();
- sorting.add(IssueQuery.SORT_BY_ASSIGNEE, IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE);
- sorting.add(IssueQuery.SORT_BY_STATUS, IssueIndexDefinition.FIELD_ISSUE_STATUS);
- sorting.add(IssueQuery.SORT_BY_SEVERITY, IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE);
- sorting.add(IssueQuery.SORT_BY_CREATION_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT);
- sorting.add(IssueQuery.SORT_BY_UPDATE_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT);
- sorting.add(IssueQuery.SORT_BY_CLOSE_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT);
- sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID);
- sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_FILE_PATH);
- sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_LINE);
- sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE).reverse();
- sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_KEY);
+ this.system = system;
+ this.sorting = new Sorting();
+ this.sorting.add(IssueQuery.SORT_BY_ASSIGNEE, IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE);
+ this.sorting.add(IssueQuery.SORT_BY_STATUS, IssueIndexDefinition.FIELD_ISSUE_STATUS);
+ this.sorting.add(IssueQuery.SORT_BY_SEVERITY, IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE);
+ this.sorting.add(IssueQuery.SORT_BY_CREATION_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT);
+ this.sorting.add(IssueQuery.SORT_BY_UPDATE_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT);
+ this.sorting.add(IssueQuery.SORT_BY_CLOSE_DATE, IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT);
+ this.sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID);
+ this.sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_FILE_PATH);
+ this.sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_LINE);
+ this.sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_SEVERITY_VALUE).reverse();
+ this.sorting.add(IssueQuery.SORT_BY_FILE_LINE, IssueIndexDefinition.FIELD_ISSUE_KEY);
// by default order by updated date and issue key (in order to be deterministic when same ms)
- sorting.addDefault(IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT).reverse();
- sorting.addDefault(IssueIndexDefinition.FIELD_ISSUE_KEY);
- }
-
- @Override
- protected void initializeIndex() {
- // replaced by IssueIndexDefinition
- }
-
- @Override
- protected String getKeyValue(String keyString) {
- return keyString;
- }
-
- @Override
- protected Map mapProperties() {
- throw new UnsupportedOperationException("Being refactored");
+ this.sorting.addDefault(IssueIndexDefinition.FIELD_ISSUE_FUNC_UPDATED_AT).reverse();
+ this.sorting.addDefault(IssueIndexDefinition.FIELD_ISSUE_KEY);
}
- @Override
- protected Map mapKey() {
- throw new UnsupportedOperationException("Being refactored");
- }
-
- @Override
- protected IssueDoc toDoc(Map<String, Object> fields) {
- Preconditions.checkNotNull(fields, "Cannot construct Issue with null response");
- return new IssueDoc(fields);
- }
-
- @Override
- public Issue getNullableByKey(String key) {
- Result<Issue> result = search(IssueQuery.builder().issueKeys(newArrayList(key)).build(), new QueryContext());
+ /**
+ * Warning, this method is not efficient as routing (the project uuid) is not known.
+ * All the ES cluster nodes are involved.
+ */
+ @CheckForNull
+ public IssueDoc getNullableByKey(String key) {
+ SearchResult<IssueDoc> result = search(IssueQuery.builder().issueKeys(newArrayList(key)).build(), new SearchOptions());
if (result.getTotal() == 1) {
- return result.getHits().get(0);
+ return result.getDocs().get(0);
}
return null;
}
- public List<FacetValue> listAssignees(IssueQuery query) {
- QueryContext queryContext = new QueryContext().setPage(1, 0);
-
- SearchRequestBuilder esSearch = getClient()
- .prepareSearch(IssueIndexDefinition.INDEX)
- .setTypes(IssueIndexDefinition.TYPE_ISSUE);
-
- QueryBuilder esQuery = QueryBuilders.matchAllQuery();
- BoolFilterBuilder esFilter = getFilter(query, queryContext);
- if (esFilter.hasClauses()) {
- esSearch.setQuery(QueryBuilders.filteredQuery(esQuery, esFilter));
- } else {
- esSearch.setQuery(esQuery);
+ /**
+ * Warning, see {@link #getNullableByKey(String)}.
+ * A {@link org.sonar.server.exceptions.NotFoundException} is thrown if key does not exist.
+ */
+ public IssueDoc getByKey(String key) {
+ IssueDoc value = getNullableByKey(key);
+ if (value == null) {
+ throw new NotFoundException(String.format("Issue with key '%s' does not exist", key));
}
- esSearch.addAggregation(AggregationBuilders.terms(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE)
- .size(Integer.MAX_VALUE)
- .field(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE));
- esSearch.addAggregation(AggregationBuilders.missing("notAssigned")
- .field(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE));
-
- SearchResponse response = esSearch.get();
- Terms aggregation = (Terms) response.getAggregations().getAsMap().get(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE);
- List<FacetValue> facetValues = newArrayList();
- for (Terms.Bucket value : aggregation.getBuckets()) {
- facetValues.add(new FacetValue(value.getKey(), value.getDocCount()));
- }
- facetValues.add(new FacetValue("_notAssigned_", ((InternalMissing) response.getAggregations().get("notAssigned")).getDocCount()));
-
- return facetValues;
+ return value;
}
- public Result<Issue> search(IssueQuery query, QueryContext options) {
- SearchRequestBuilder esSearch = getClient()
+ public SearchResult<IssueDoc> search(IssueQuery query, SearchOptions options) {
+ SearchRequestBuilder requestBuilder = getClient()
.prepareSearch(IssueIndexDefinition.INDEX)
.setTypes(IssueIndexDefinition.TYPE_ISSUE);
- if (options.isScroll()) {
- esSearch.setSearchType(SearchType.SCAN);
- esSearch.setScroll(TimeValue.timeValueMinutes(3));
- }
-
- setSorting(query, esSearch);
- setPagination(options, esSearch);
+ configureSorting(query, requestBuilder);
+ configurePagination(options, requestBuilder);
QueryBuilder esQuery = QueryBuilders.matchAllQuery();
- Map<String, FilterBuilder> filters = getFilters(query, options);
- setQueryFilter(esSearch, esQuery, filters);
-
- setFacets(query, options, filters, esQuery, esSearch);
-
- SearchResponse response = esSearch.get();
- return new Result<>(this, response);
- }
-
- protected void setQueryFilter(SearchRequestBuilder esSearch, QueryBuilder esQuery, Map<String, FilterBuilder> filters) {
BoolFilterBuilder esFilter = FilterBuilders.boolFilter();
+ Map<String, FilterBuilder> filters = createFilters(query);
for (FilterBuilder filter : filters.values()) {
if (filter != null) {
esFilter.must(filter);
}
}
-
if (esFilter.hasClauses()) {
- esSearch.setQuery(QueryBuilders.filteredQuery(esQuery, esFilter));
+ requestBuilder.setQuery(QueryBuilders.filteredQuery(esQuery, esFilter));
} else {
- esSearch.setQuery(esQuery);
+ requestBuilder.setQuery(esQuery);
}
+
+ configureStickyFacets(query, options, filters, esQuery, requestBuilder);
+ return new SearchResult<>(requestBuilder.get(), DOC_CONVERTER);
}
- private BoolFilterBuilder getFilter(IssueQuery query, QueryContext options) {
- BoolFilterBuilder esFilter = FilterBuilders.boolFilter();
- for (FilterBuilder filter : getFilters(query, options).values()) {
- if (filter != null) {
- esFilter.must(filter);
- }
+ private void configureSorting(IssueQuery query, SearchRequestBuilder esRequest) {
+ String sortField = query.sort();
+ if (sortField != null) {
+ boolean asc = BooleanUtils.isTrue(query.asc());
+ sorting.fill(esRequest, sortField, asc);
+ } else {
+ sorting.fillDefault(esRequest);
}
- return esFilter;
}
- public void deleteClosedIssuesOfProjectBefore(String uuid, Date beforeDate) {
- FilterBuilder projectFilter = FilterBuilders.boolFilter().must(FilterBuilders.termsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, uuid));
- FilterBuilder dateFilter = FilterBuilders.rangeFilter(IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT).lt(beforeDate.getTime());
- QueryBuilder queryBuilder = QueryBuilders.filteredQuery(
- QueryBuilders.matchAllQuery(),
- FilterBuilders.andFilter(projectFilter, dateFilter)
- );
-
- getClient().prepareDeleteByQuery(IssueIndexDefinition.INDEX).setQuery(queryBuilder).get();
+ protected void configurePagination(SearchOptions options, SearchRequestBuilder esSearch) {
+ esSearch.setFrom(options.getOffset()).setSize(options.getLimit());
}
- /* Build main filter (match based) */
- protected Map<String, FilterBuilder> getFilters(IssueQuery query, QueryContext options) {
-
- Map<String, FilterBuilder> filters = Maps.newHashMap();
-
- filters.put("__authorization", getAuthorizationFilter(options));
+ private Map<String, FilterBuilder> createFilters(IssueQuery query) {
+ Map<String, FilterBuilder> filters = new HashMap<>();
+ filters.put("__authorization", createAuthorizationFilter(query));
// Issue is assigned Filter
String isAssigned = "__isAssigned";
@@ -255,20 +238,20 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
// Field Filters
- filters.put(IssueIndexDefinition.FIELD_ISSUE_KEY, matchFilter(IssueIndexDefinition.FIELD_ISSUE_KEY, query.issueKeys()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN, matchFilter(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN, query.actionPlans()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, matchFilter(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, query.assignees()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_KEY, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_KEY, query.issueKeys()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN, query.actionPlans()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE, query.assignees()));
addComponentRelatedFilters(query, filters);
- filters.put(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, matchFilter(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, query.languages()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_TAGS, matchFilter(IssueIndexDefinition.FIELD_ISSUE_TAGS, query.tags()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, matchFilter(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, query.resolutions()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_REPORTER, matchFilter(IssueIndexDefinition.FIELD_ISSUE_REPORTER, query.reporters()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, matchFilter(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query.authors()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, matchFilter(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, query.rules()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_SEVERITY, matchFilter(IssueIndexDefinition.FIELD_ISSUE_SEVERITY, query.severities()));
- filters.put(IssueIndexDefinition.FIELD_ISSUE_STATUS, matchFilter(IssueIndexDefinition.FIELD_ISSUE_STATUS, query.statuses()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, query.languages()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_TAGS, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_TAGS, query.tags()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION, query.resolutions()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_REPORTER, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_REPORTER, query.reporters()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query.authors()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_RULE_KEY, query.rules()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_SEVERITY, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_SEVERITY, query.severities()));
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_STATUS, createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_STATUS, query.statuses()));
addDatesFilter(filters, query);
@@ -276,14 +259,14 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
private void addComponentRelatedFilters(IssueQuery query, Map<String, FilterBuilder> filters) {
- FilterBuilder viewFilter = viewFilter(query.viewUuids());
- FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids());
- FilterBuilder projectFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids());
- FilterBuilder moduleRootFilter = moduleRootFilter(query.moduleRootUuids());
- FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids());
- FilterBuilder directoryRootFilter = directoryRootFilter(query.moduleUuids(), query.directories());
- FilterBuilder directoryFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories());
- FilterBuilder fileFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids());
+ FilterBuilder viewFilter = createViewFilter(query.viewUuids());
+ FilterBuilder componentFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids());
+ FilterBuilder projectFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids());
+ FilterBuilder moduleRootFilter = createModuleRootFilter(query.moduleRootUuids());
+ FilterBuilder moduleFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids());
+ FilterBuilder directoryRootFilter = createDirectoryRootFilter(query.moduleUuids(), query.directories());
+ FilterBuilder directoryFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories());
+ FilterBuilder fileFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids());
if (BooleanUtils.isTrue(query.isContextualized())) {
if (viewFilter != null) {
@@ -325,12 +308,12 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
@CheckForNull
- private FilterBuilder moduleRootFilter(Collection<String> componentUuids) {
+ private FilterBuilder createModuleRootFilter(Collection<String> componentUuids) {
if (componentUuids.isEmpty()) {
return null;
}
- FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentUuids);
- FilterBuilder modulePathFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, componentUuids);
+ FilterBuilder componentFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentUuids);
+ FilterBuilder modulePathFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, componentUuids);
FilterBuilder compositeFilter = null;
if (componentFilter != null) {
if (modulePathFilter != null) {
@@ -341,14 +324,15 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
} else if (modulePathFilter != null) {
compositeFilter = modulePathFilter;
}
+ System.out.println("compositeFilter:" + compositeFilter);
return compositeFilter;
}
@CheckForNull
- private FilterBuilder directoryRootFilter(Collection<String> moduleUuids, Collection<String> directoryPaths) {
+ private FilterBuilder createDirectoryRootFilter(Collection<String> moduleUuids, Collection<String> directoryPaths) {
BoolFilterBuilder directoryTop = null;
- FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleUuids);
- FilterBuilder directoryFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryPaths);
+ FilterBuilder moduleFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleUuids);
+ FilterBuilder directoryFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryPaths);
if (moduleFilter != null) {
directoryTop = FilterBuilders.boolFilter();
directoryTop.must(moduleFilter);
@@ -363,7 +347,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
@CheckForNull
- private FilterBuilder viewFilter(Collection<String> viewUuids) {
+ private FilterBuilder createViewFilter(Collection<String> viewUuids) {
if (viewUuids.isEmpty()) {
return null;
}
@@ -381,26 +365,29 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
public static String viewsLookupCacheKey(String viewUuid) {
- return IssueIndexDefinition.TYPE_ISSUE + viewUuid + ViewIndexDefinition.TYPE_VIEW;
+ return String.format("%s%s%s", IssueIndexDefinition.TYPE_ISSUE, viewUuid, ViewIndexDefinition.TYPE_VIEW);
}
- private FilterBuilder getAuthorizationFilter(QueryContext options) {
- String user = options.getUserLogin();
- Set<String> groups = options.getUserGroups();
- OrFilterBuilder groupsAndUser = FilterBuilders.orFilter();
- if (user != null) {
- groupsAndUser.add(FilterBuilders.termFilter(IssueIndexDefinition.FIELD_AUTHORIZATION_USERS, user));
- }
- for (String group : groups) {
- groupsAndUser.add(FilterBuilders.termFilter(IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS, group));
+ private FilterBuilder createAuthorizationFilter(IssueQuery query) {
+ if (query.checkAuthorization()) {
+ String user = query.userLogin();
+ OrFilterBuilder groupsAndUser = FilterBuilders.orFilter();
+ if (user != null) {
+ groupsAndUser.add(FilterBuilders.termFilter(IssueIndexDefinition.FIELD_AUTHORIZATION_USERS, user));
+ }
+ for (String group : query.userGroups()) {
+ groupsAndUser.add(FilterBuilders.termFilter(IssueIndexDefinition.FIELD_AUTHORIZATION_GROUPS, group));
+ }
+ return FilterBuilders.hasParentFilter(IssueIndexDefinition.TYPE_AUTHORIZATION,
+ QueryBuilders.filteredQuery(
+ QueryBuilders.matchAllQuery(),
+ FilterBuilders.boolFilter()
+ .must(groupsAndUser)
+ .cache(true))
+ );
+ } else {
+ return FilterBuilders.matchAllFilter();
}
- return FilterBuilders.hasParentFilter(IssueIndexDefinition.TYPE_AUTHORIZATION,
- QueryBuilders.filteredQuery(
- QueryBuilders.matchAllQuery(),
- FilterBuilders.boolFilter()
- .must(groupsAndUser)
- .cache(true))
- );
}
private void addDatesFilter(Map<String, FilterBuilder> filters, IssueQuery query) {
@@ -424,9 +411,9 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
}
- private void setFacets(IssueQuery query, QueryContext options, Map<String, FilterBuilder> filters, QueryBuilder esQuery, SearchRequestBuilder esSearch) {
- if (options.isFacet()) {
- StickyFacetBuilder stickyFacetBuilder = stickyFacetBuilder(esQuery, filters);
+ private void configureStickyFacets(IssueQuery query, SearchOptions options, Map<String, FilterBuilder> filters, QueryBuilder esQuery, SearchRequestBuilder esSearch) {
+ if (!options.getFacets().isEmpty()) {
+ StickyFacetBuilder stickyFacetBuilder = new StickyFacetBuilder(esQuery, filters);
// Execute Term aggregations
addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
IssueFilterParameters.SEVERITIES, IssueIndexDefinition.FIELD_ISSUE_SEVERITY, Severity.ALL.toArray());
@@ -450,33 +437,85 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
IssueFilterParameters.AUTHORS, IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query.authors().toArray());
- if (options.facets().contains(IssueFilterParameters.TAGS)) {
+ if (options.getFacets().contains(IssueFilterParameters.TAGS)) {
esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(IssueIndexDefinition.FIELD_ISSUE_TAGS, IssueFilterParameters.TAGS, query.tags().toArray()));
}
- if (options.facets().contains(IssueFilterParameters.RESOLUTIONS)) {
- esSearch.addAggregation(getResolutionFacet(filters, esQuery));
+ if (options.getFacets().contains(IssueFilterParameters.RESOLUTIONS)) {
+ esSearch.addAggregation(createResolutionFacet(filters, esQuery));
}
- if (options.facets().contains(IssueFilterParameters.ASSIGNEES)) {
- esSearch.addAggregation(getAssigneesFacet(query, filters, esQuery));
+ if (options.getFacets().contains(IssueFilterParameters.ASSIGNEES)) {
+ esSearch.addAggregation(createAssigneesFacet(query, filters, esQuery));
}
- if (options.facets().contains(IssueFilterParameters.ACTION_PLANS)) {
- esSearch.addAggregation(getActionPlansFacet(query, filters, esQuery));
+ if (options.getFacets().contains(IssueFilterParameters.ACTION_PLANS)) {
+ esSearch.addAggregation(createActionPlansFacet(query, filters, esQuery));
}
- if (options.facets().contains(IssueFilterParameters.CREATED_AT)) {
+ if (options.getFacets().contains(IssueFilterParameters.CREATED_AT)) {
esSearch.addAggregation(getCreatedAtFacet(query, filters, esQuery));
}
}
}
- private void addSimpleStickyFacetIfNeeded(QueryContext options, StickyFacetBuilder stickyFacetBuilder, SearchRequestBuilder esSearch,
+ private void addSimpleStickyFacetIfNeeded(SearchOptions options, StickyFacetBuilder stickyFacetBuilder, SearchRequestBuilder esSearch,
String facetName, String fieldName, Object... selectedValues) {
- if (options.facets().contains(facetName)) {
- esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(fieldName, facetName, DEFAULT_ISSUE_FACET_SIZE, selectedValues));
+ if (options.getFacets().contains(facetName)) {
+ esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(fieldName, facetName, DEFAULT_FACET_SIZE, selectedValues));
+ }
+ }
+
+ private AggregationBuilder getCreatedAtFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
+ Date now = system.newDate();
+ SimpleDateFormat tzFormat = new SimpleDateFormat("XX");
+ tzFormat.setTimeZone(TimeZone.getDefault());
+ String timeZoneString = tzFormat.format(now);
+
+ DateHistogram.Interval bucketSize = DateHistogram.Interval.YEAR;
+ Date createdAfter = query.createdAfter();
+ long startTime = createdAfter == null ? getMinCreatedAt(filters, esQuery) : createdAfter.getTime();
+ Date createdBefore = query.createdBefore();
+ long endTime = createdBefore == null ? now.getTime() : createdBefore.getTime();
+ Duration timeSpan = new Duration(startTime, endTime);
+ if (timeSpan.isShorterThan(TWENTY_DAYS)) {
+ bucketSize = DateHistogram.Interval.DAY;
+ } else if (timeSpan.isShorterThan(TWENTY_WEEKS)) {
+ bucketSize = DateHistogram.Interval.WEEK;
+ } else if (timeSpan.isShorterThan(TWENTY_MONTHS)) {
+ bucketSize = DateHistogram.Interval.MONTH;
+ }
+
+ return AggregationBuilders.dateHistogram(IssueFilterParameters.CREATED_AT)
+ .field(IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT)
+ .interval(bucketSize)
+ .minDocCount(0L)
+ .format(DateUtils.DATETIME_FORMAT)
+ .preZone(timeZoneString)
+ .postZone(timeZoneString)
+ .extendedBounds(startTime, endTime);
+ }
+
+ private long getMinCreatedAt(Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
+ String facetNameAndField = IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT;
+ SearchRequestBuilder esRequest = getClient()
+ .prepareSearch(IssueIndexDefinition.INDEX)
+ .setTypes(IssueIndexDefinition.TYPE_ISSUE)
+ .setSearchType(SearchType.COUNT);
+ BoolFilterBuilder esFilter = FilterBuilders.boolFilter();
+ for (FilterBuilder filter : filters.values()) {
+ if (filter != null) {
+ esFilter.must(filter);
+ }
}
+ if (esFilter.hasClauses()) {
+ esRequest.setQuery(QueryBuilders.filteredQuery(esQuery, esFilter));
+ } else {
+ esRequest.setQuery(esQuery);
+ }
+ esRequest.addAggregation(AggregationBuilders.min(facetNameAndField).field(facetNameAndField));
+ Min minValue = esRequest.get().getAggregations().get(facetNameAndField);
+ return (long) minValue.getValue();
}
- private AggregationBuilder getAssigneesFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
+ private AggregationBuilder createAssigneesFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder queryBuilder) {
String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE;
String facetName = IssueFilterParameters.ASSIGNEES;
@@ -484,9 +523,9 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
Map<String, FilterBuilder> assigneeFilters = Maps.newHashMap(filters);
assigneeFilters.remove("__isAssigned");
assigneeFilters.remove(fieldName);
- StickyFacetBuilder assigneeFacetBuilder = new StickyFacetBuilder(esQuery, assigneeFilters);
+ StickyFacetBuilder assigneeFacetBuilder = new StickyFacetBuilder(queryBuilder, assigneeFilters);
BoolFilterBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
- FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_ISSUE_FACET_SIZE);
+ FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
List<String> assignees = Lists.newArrayList(query.assignees());
UserSession session = UserSession.get();
@@ -507,7 +546,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
.subAggregation(facetTopAggregation);
}
- private AggregationBuilder getResolutionFacet(Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
+ private AggregationBuilder createResolutionFacet(Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION;
String facetName = IssueFilterParameters.RESOLUTIONS;
@@ -517,7 +556,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
resolutionFilters.remove(fieldName);
StickyFacetBuilder assigneeFacetBuilder = new StickyFacetBuilder(esQuery, resolutionFilters);
BoolFilterBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
- FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_ISSUE_FACET_SIZE);
+ FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, Issue.RESOLUTIONS.toArray());
// Add missing facet for unresolved issues
@@ -532,7 +571,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
.subAggregation(facetTopAggregation);
}
- private AggregationBuilder getActionPlansFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
+ private AggregationBuilder createActionPlansFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
String fieldName = IssueIndexDefinition.FIELD_ISSUE_ACTION_PLAN;
String facetName = IssueFilterParameters.ACTION_PLANS;
@@ -542,7 +581,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
actionPlanFilters.remove(fieldName);
StickyFacetBuilder actionPlanFacetBuilder = new StickyFacetBuilder(esQuery, actionPlanFilters);
BoolFilterBuilder facetFilter = actionPlanFacetBuilder.getStickyFacetFilter(fieldName);
- FilterAggregationBuilder facetTopAggregation = actionPlanFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_ISSUE_FACET_SIZE);
+ FilterAggregationBuilder facetTopAggregation = actionPlanFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
facetTopAggregation = actionPlanFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, query.actionPlans().toArray());
// Add missing facet for unresolved issues
@@ -557,66 +596,8 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
.subAggregation(facetTopAggregation);
}
- private AggregationBuilder getCreatedAtFacet(IssueQuery query, Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
- Date now = system.newDate();
- SimpleDateFormat tzFormat = new SimpleDateFormat("XX");
- tzFormat.setTimeZone(TimeZone.getDefault());
- String timeZoneString = tzFormat.format(now);
-
- Interval bucketSize = Interval.YEAR;
- Date createdAfter = query.createdAfter();
- long startTime = createdAfter == null ? getMinCreatedAt(filters, esQuery) : createdAfter.getTime();
- Date createdBefore = query.createdBefore();
- long endTime = createdBefore == null ? now.getTime() : createdBefore.getTime();
- Duration timeSpan = new Duration(startTime, endTime);
- if (timeSpan.isShorterThan(TWENTY_DAYS)) {
- bucketSize = Interval.DAY;
- } else if (timeSpan.isShorterThan(TWENTY_WEEKS)) {
- bucketSize = Interval.WEEK;
- } else if (timeSpan.isShorterThan(TWENTY_MONTHS)) {
- bucketSize = Interval.MONTH;
- }
-
-
- return AggregationBuilders.dateHistogram(IssueFilterParameters.CREATED_AT)
- .field(IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT)
- .interval(bucketSize)
- .minDocCount(0L)
- .format(DateUtils.DATETIME_FORMAT)
- .preZone(timeZoneString)
- .postZone(timeZoneString)
- .extendedBounds(startTime, endTime);
- }
-
- private long getMinCreatedAt(Map<String, FilterBuilder> filters, QueryBuilder esQuery) {
- String facetNameAndField = IssueIndexDefinition.FIELD_ISSUE_FUNC_CREATED_AT;
- SearchRequestBuilder minCount = getClient()
- .prepareSearch(IssueIndexDefinition.INDEX)
- .setTypes(IssueIndexDefinition.TYPE_ISSUE)
- .setSearchType(SearchType.COUNT);
- setQueryFilter(minCount, esQuery, filters);
- minCount.addAggregation(AggregationBuilders.min(facetNameAndField).field(facetNameAndField));
- Min minValue = minCount.get().getAggregations().get(facetNameAndField);
- return (long) minValue.getValue();
- }
-
- private void setSorting(IssueQuery query, SearchRequestBuilder esRequest) {
- String sortField = query.sort();
- if (sortField != null) {
- boolean asc = BooleanUtils.isTrue(query.asc());
- sorting.fill(esRequest, sortField, asc);
- } else {
- sorting.fillDefault(esRequest);
- }
- }
-
- protected void setPagination(QueryContext options, SearchRequestBuilder esSearch) {
- esSearch.setFrom(options.getOffset());
- esSearch.setSize(options.getLimit());
- }
-
@CheckForNull
- private FilterBuilder matchFilter(String field, Collection<?> values) {
+ private FilterBuilder createTermsFilter(String field, Collection<?> values) {
if (!values.isEmpty()) {
return FilterBuilders.termsFilter(field, values);
} else {
@@ -624,55 +605,100 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
}
}
- public Collection<String> listTagsMatching(@Nullable String query, int pageSize) {
- return listTermsMatching(IssueIndexDefinition.FIELD_ISSUE_TAGS, query, pageSize);
+ public List<String> listTags(IssueQuery query, @Nullable String textQuery, int maxNumberOfTags) {
+ Terms terms = listTermsMatching(IssueIndexDefinition.FIELD_ISSUE_TAGS, query, textQuery, Terms.Order.term(true), maxNumberOfTags);
+ return EsUtils.termsKeys(terms);
}
- public Collection<String> listAuthorsMatching(@Nullable String query, int pageSize) {
- return listTermsMatching(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query, pageSize);
+ public Map<String, Long> countTags(IssueQuery query, int maxNumberOfTags) {
+ Terms terms = listTermsMatching(IssueIndexDefinition.FIELD_ISSUE_TAGS, query, null, Terms.Order.count(false), maxNumberOfTags);
+ return EsUtils.termsToMap(terms);
}
- private Collection<String> listTermsMatching(String fieldName, @Nullable String query, int pageSize) {
- SearchRequestBuilder count = getClient().prepareSearch(IssueIndexDefinition.INDEX)
- .setTypes(IssueIndexDefinition.TYPE_ISSUE)
- .setQuery(QueryBuilders.matchAllQuery());
+ public List<String> listAuthors(IssueQuery query, @Nullable String textQuery, int maxNumberOfAuthors) {
+ Terms terms = listTermsMatching(IssueIndexDefinition.FIELD_ISSUE_AUTHOR_LOGIN, query, textQuery, Terms.Order.term(true), maxNumberOfAuthors);
+ return EsUtils.termsKeys(terms);
+ }
+
+ private Terms listTermsMatching(String fieldName, IssueQuery query, @Nullable String textQuery, Terms.Order termsOrder, int maxNumberOfTags) {
+ SearchRequestBuilder requestBuilder = getClient()
+ .prepareSearch(IssueIndexDefinition.INDEX)
+ .setTypes(IssueIndexDefinition.TYPE_ISSUE);
+
+ requestBuilder.setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(),
+ createBoolFilter(query)));
+
+ // TODO do not return hits
+
TermsBuilder aggreg = AggregationBuilders.terms("_ref")
.field(fieldName)
- .size(pageSize)
- .order(Order.term(true))
+ .size(maxNumberOfTags)
+ .order(termsOrder)
.minDocCount(1L);
- if (query != null) {
- aggreg.include(".*" + query + ".*");
+ if (textQuery != null) {
+ aggreg.include(String.format(".*%s.*", textQuery));
}
- Terms result = count.addAggregation(aggreg).get().getAggregations().get("_ref");
- return Collections2.transform(result.getBuckets(), new Function<Bucket, String>() {
- @Override
- public String apply(Bucket bucket) {
- return bucket.getKey();
- }
- });
+ SearchResponse searchResponse = requestBuilder.addAggregation(aggreg).get();
+ return searchResponse.getAggregations().get("_ref");
}
- public Map<String, Long> listTagsForComponent(String componentUuid, int pageSize) {
- SearchRequestBuilder count = getClient().prepareSearch(IssueIndexDefinition.INDEX)
- .setTypes(IssueIndexDefinition.TYPE_ISSUE)
- .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(),
- FilterBuilders.boolFilter()
- .must(getAuthorizationFilter(new QueryContext()))
- .must(FilterBuilders.missingFilter(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION))
- .must(moduleRootFilter(Arrays.asList(componentUuid)))));
- TermsBuilder aggreg = AggregationBuilders.terms("_ref")
- .field(IssueIndexDefinition.FIELD_ISSUE_TAGS)
- .size(pageSize)
- .order(Order.count(false))
- .minDocCount(1L);
- Terms result = count.addAggregation(aggreg).get().getAggregations().get("_ref");
+ public void deleteClosedIssuesOfProjectBefore(String projectUuid, Date beforeDate) {
+ FilterBuilder projectFilter = FilterBuilders.boolFilter().must(FilterBuilders.termsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, projectUuid));
+ FilterBuilder dateFilter = FilterBuilders.rangeFilter(IssueIndexDefinition.FIELD_ISSUE_FUNC_CLOSED_AT).lt(beforeDate.getTime());
+ QueryBuilder queryBuilder = QueryBuilders.filteredQuery(
+ QueryBuilders.matchAllQuery(),
+ FilterBuilders.andFilter(projectFilter, dateFilter)
+ );
+
+ getClient().prepareDeleteByQuery(IssueIndexDefinition.INDEX).setQuery(queryBuilder).get();
+ }
- Map<String, Long> map = Maps.newHashMap();
- for (Bucket bucket : result.getBuckets()) {
- map.put(bucket.getKey(), bucket.getDocCount());
+ public LinkedHashMap<String, Long> searchForAssignees(IssueQuery query) {
+ // TODO do not return hits
+ // TODO what's max size ?
+
+ SearchRequestBuilder esSearch = getClient()
+ .prepareSearch(IssueIndexDefinition.INDEX)
+ .setTypes(IssueIndexDefinition.TYPE_ISSUE);
+
+ QueryBuilder esQuery = QueryBuilders.matchAllQuery();
+ BoolFilterBuilder esFilter = createBoolFilter(query);
+ if (esFilter.hasClauses()) {
+ esSearch.setQuery(QueryBuilders.filteredQuery(esQuery, esFilter));
+ } else {
+ esSearch.setQuery(esQuery);
+ }
+ esSearch.addAggregation(AggregationBuilders.terms(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE)
+ .size(Integer.MAX_VALUE)
+ .field(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE));
+ esSearch.addAggregation(AggregationBuilders.missing("notAssigned")
+ .field(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE));
+
+ SearchResponse response = esSearch.get();
+ Terms aggregation = (Terms) response.getAggregations().getAsMap().get(IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE);
+ LinkedHashMap<String, Long> result = EsUtils.termsToMap(aggregation);
+ result.put("_notAssigned_", ((InternalMissing) response.getAggregations().get("notAssigned")).getDocCount());
+ return result;
+ }
+
+ private BoolFilterBuilder createBoolFilter(IssueQuery query) {
+ BoolFilterBuilder boolFilter = FilterBuilders.boolFilter();
+ for (FilterBuilder filter : createFilters(query).values()) {
+ // TODO Can it be null ?
+ if (filter != null) {
+ boolFilter.must(filter);
+ }
}
- return map;
+ return boolFilter;
+ }
+
+ /**
+ * TODO used only by tests, so must be replaced by EsTester#countDocuments()
+ */
+ public long countAll() {
+ return getClient().prepareCount(IssueIndexDefinition.INDEX)
+ .setTypes(IssueIndexDefinition.TYPE_ISSUE)
+ .get().getCount();
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java
index 3d500c0927c..8096dc5dd62 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/AuthorsAction.java
@@ -20,15 +20,15 @@
package org.sonar.server.issue.ws;
import com.google.common.io.Resources;
-import org.sonar.api.server.ws.*;
+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.server.ws.WebService.NewAction;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.issue.IssueService;
-public class AuthorsAction implements RequestHandler {
+public class AuthorsAction implements BaseIssuesWsAction {
- private static final String PARAM_PAGE_SIZE = "ps";
- private static final String PARAM_QUERY = "q";
private final IssueService service;
public AuthorsAction(IssueService service) {
@@ -37,8 +37,8 @@ public class AuthorsAction implements RequestHandler {
@Override
public void handle(Request request, Response response) throws Exception {
- String query = request.param(PARAM_QUERY);
- int pageSize = request.mandatoryParamAsInt(PARAM_PAGE_SIZE);
+ String query = request.param(WebService.Param.TEXT_QUERY);
+ int pageSize = request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE);
JsonWriter json = response.newJsonWriter()
.beginObject()
@@ -52,17 +52,18 @@ public class AuthorsAction implements RequestHandler {
json.endArray().endObject().close();
}
- void define(WebService.NewController controller) {
+ @Override
+ public void define(WebService.NewController controller) {
NewAction action = controller.createAction("authors")
.setSince("5.1")
.setDescription("Search SCM accounts which match a given query")
.setResponseExample(Resources.getResource(this.getClass(), "example-authors.json"))
.setHandler(this);
- action.createParam(PARAM_QUERY)
+ action.createParam(WebService.Param.TEXT_QUERY)
.setDescription("A pattern to match SCM accounts against")
.setExampleValue("luke");
- action.createParam(PARAM_PAGE_SIZE)
+ action.createParam(WebService.Param.PAGE_SIZE)
.setDescription("The size of the list to return")
.setExampleValue("25")
.setDefaultValue("10");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/FakeIssueDto.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/BaseIssuesWsAction.java
index 0db9d5d5b24..051a34613c0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/index/FakeIssueDto.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/BaseIssuesWsAction.java
@@ -17,13 +17,14 @@
* 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.index;
+package org.sonar.server.issue.ws;
-import org.sonar.core.persistence.Dto;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.WebService;
+
+interface BaseIssuesWsAction extends RequestHandler {
+
+ void define(WebService.NewController controller);
-public class FakeIssueDto extends Dto<String> {
- @Override
- public String getKey() {
- throw new UnsupportedOperationException();
- }
}
+
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java
index e642686d0bb..c68e9d00b78 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java
@@ -21,7 +21,6 @@ package org.sonar.server.issue.ws;
import com.google.common.io.Resources;
import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction;
@@ -34,7 +33,7 @@ import java.util.Map;
* List issue tags matching a given query.
* @since 5.1
*/
-public class ComponentTagsAction implements RequestHandler {
+public class ComponentTagsAction implements BaseIssuesWsAction {
private final IssueService service;
@@ -42,7 +41,8 @@ public class ComponentTagsAction implements RequestHandler {
this.service = service;
}
- void define(WebService.NewController controller) {
+ @Override
+ public void define(WebService.NewController controller) {
NewAction action = controller.createAction("component_tags")
.setHandler(this)
.setSince("5.1")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java
index 87340b7eaf1..1c0604c0283 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowAction.java
@@ -29,7 +29,6 @@ import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.user.User;
@@ -54,14 +53,13 @@ import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
import java.util.Date;
import java.util.List;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
-public class IssueShowAction implements RequestHandler {
+public class IssueShowAction implements BaseIssuesWsAction {
public static final String SHOW_ACTION = "show";
@@ -94,7 +92,8 @@ public class IssueShowAction implements RequestHandler {
this.durations = durations;
}
- void define(WebService.NewController controller) {
+ @Override
+ public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction(SHOW_ACTION)
.setDescription("Detail of issue")
.setSince("4.2")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
index 8efe7e1f039..df9e92da850 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
@@ -42,22 +42,10 @@ public class IssuesWs implements WebService {
public static final String DO_ACTION_ACTION = "do_action";
public static final String BULK_CHANGE_ACTION = "bulk_change";
- private final IssueShowAction showAction;
- private final SearchAction esSearchAction;
- private final TagsAction tagsAction;
- private final SetTagsAction setTagsAction;
- private final ComponentTagsAction componentTagsAction;
- private final AuthorsAction authorsAction;
-
-
- public IssuesWs(IssueShowAction showAction, SearchAction searchAction, TagsAction tagsAction, SetTagsAction setTagsAction, ComponentTagsAction componentTagsAction,
- AuthorsAction authorsAction) {
- this.showAction = showAction;
- this.esSearchAction = searchAction;
- this.tagsAction = tagsAction;
- this.setTagsAction = setTagsAction;
- this.componentTagsAction = componentTagsAction;
- this.authorsAction = authorsAction;
+ private final BaseIssuesWsAction[] actions;
+
+ public IssuesWs(BaseIssuesWsAction... actions) {
+ this.actions = actions;
}
@Override
@@ -65,14 +53,14 @@ public class IssuesWs implements WebService {
NewController controller = context.createController(API_ENDPOINT);
controller.setDescription("Coding rule issues");
controller.setSince("3.6");
+ for (BaseIssuesWsAction action : actions) {
+ action.define(controller);
+ }
+ defineRailsActions(controller);
+ controller.done();
+ }
- showAction.define(controller);
- esSearchAction.define(controller);
- tagsAction.define(controller);
- setTagsAction.define(controller);
- componentTagsAction.define(controller);
- authorsAction.define(controller);
-
+ private void defineRailsActions(NewController controller) {
defineChangelogAction(controller);
defineAssignAction(controller);
defineAddCommentAction(controller);
@@ -85,8 +73,6 @@ public class IssuesWs implements WebService {
defineCreateAction(controller);
defineDoActionAction(controller);
defineBulkChangeAction(controller);
-
- controller.done();
}
private void defineChangelogAction(NewController controller) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
index 6960a88c93e..528aa02d5af 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
@@ -22,6 +22,7 @@ package org.sonar.server.issue.ws;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
import com.google.common.io.Resources;
import org.apache.commons.lang.BooleanUtils;
import org.sonar.api.i18n.I18n;
@@ -34,6 +35,7 @@ import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
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.user.User;
import org.sonar.api.user.UserFinder;
@@ -42,35 +44,37 @@ import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.component.ComponentDto;
-import org.sonar.core.issue.db.IssueChangeDao;
import org.sonar.core.persistence.DbSession;
import org.sonar.markdown.Markdown;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.IssueQueryService;
import org.sonar.server.issue.IssueService;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.issue.filter.IssueFilterParameters;
import org.sonar.server.issue.index.IssueDoc;
+import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.rule.Rule;
import org.sonar.server.rule.RuleService;
-import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
-import org.sonar.server.search.ws.SearchRequestHandler;
import org.sonar.server.user.UserSession;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
-public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
-
+public class SearchAction implements BaseIssuesWsAction {
public static final String SEARCH_ACTION = "search";
@@ -84,7 +88,6 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. ";
- private final IssueChangeDao issueChangeDao;
private final IssueService service;
private final IssueActionsWriter actionsWriter;
@@ -97,11 +100,9 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
private final Durations durations;
private final Languages languages;
- public SearchAction(DbClient dbClient, IssueChangeDao issueChangeDao, IssueService service, IssueActionsWriter actionsWriter, IssueQueryService issueQueryService,
+ public SearchAction(DbClient dbClient, IssueService service, IssueActionsWriter actionsWriter, IssueQueryService issueQueryService,
RuleService ruleService, ActionPlanService actionPlanService, UserFinder userFinder, I18n i18n, Durations durations, Languages languages) {
- super(SEARCH_ACTION);
this.dbClient = dbClient;
- this.issueChangeDao = issueChangeDao;
this.service = service;
this.actionsWriter = actionsWriter;
this.issueQueryService = issueQueryService;
@@ -114,12 +115,22 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
}
@Override
- protected void doDefinition(WebService.NewAction action) {
- action.setDescription("Get a list of issues. If the number of issues is greater than 10,000, only the first 10,000 ones are returned by the web service. " +
- "Requires Browse permission on project(s)")
+ public void define(WebService.NewController controller) {
+ WebService.NewAction action = controller
+ .createAction(SEARCH_ACTION)
+ .setHandler(this)
+ .setDescription(
+ "Get a list of issues. If the number of issues is greater than 10,000, only the first 10,000 ones are returned by the web service. Requires Browse permission on project(s)")
.setSince("3.6")
.setResponseExample(Resources.getResource(this.getClass(), "example-search.json"));
+ action.addPagingParams(100);
+ action.createParam(WebService.Param.FACETS)
+ .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")
+ .setPossibleValues(IssueIndex.SUPPORTED_FACETS);
+ action.addSortParams(IssueQuery.SORTS, null, true);
+ // TODO support param "f"
+
addComponentRelatedParams(action);
action.createParam(IssueFilterParameters.ISSUES)
.setDescription("Comma-separated list of issue keys")
@@ -182,14 +193,6 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
action.createParam(IssueFilterParameters.CREATED_BEFORE)
.setDescription("To retrieve issues created before the given date (exclusive). Format: date or datetime ISO formats")
.setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)");
- action.createParam(SearchRequestHandler.PARAM_SORT)
- .setDescription("Sort field")
- .setDeprecatedKey(IssueFilterParameters.SORT)
- .setPossibleValues(IssueQuery.SORTS);
- action.createParam(SearchRequestHandler.PARAM_ASCENDING)
- .setDeprecatedKey(IssueFilterParameters.ASC)
- .setDescription("Ascending sort")
- .setBooleanPossibleValues();
action.createParam(IssueFilterParameters.IGNORE_PAGING)
.setDescription("Return the full list of issues, regardless of paging. For internal use only")
.setBooleanPossibleValues()
@@ -199,7 +202,6 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
}
private void addComponentRelatedParams(WebService.NewAction action) {
-
action.createParam(IssueFilterParameters.ON_COMPONENT_ONLY)
.setDescription("Return only issues at a component's level, not on its descendants (modules, directories, files, etc). " +
"This parameter is only considered when componentKeys or componentUuids is set. " +
@@ -260,49 +262,34 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
}
@Override
- protected IssueQuery doQuery(Request request) {
- return issueQueryService.createFromRequest(request);
+ public final void handle(Request request, Response response) throws Exception {
+ SearchOptions options = new SearchOptions();
+ options.setPage(request.mandatoryParamAsInt(IssuesWs.Param.PAGE), request.mandatoryParamAsInt(IssuesWs.Param.PAGE_SIZE));
+ options.addFacets(request.paramAsStrings(WebService.Param.FACETS));
+
+ IssueQuery query = issueQueryService.createFromRequest(request);
+ SearchResult<IssueDoc> result = execute(query, options);
+
+ JsonWriter json = response.newJsonWriter().beginObject();
+ options.writeJson(json, result.getTotal());
+ options.writeDeprecatedJson(json, result.getTotal());
+
+ writeResponse(request, result, json);
+ if (!options.getFacets().isEmpty()) {
+ writeFacets(request, options, result, json);
+ }
+ json.endObject().close();
}
- @Override
- protected Result<Issue> doSearch(IssueQuery query, QueryContext context) {
+ private SearchResult<IssueDoc> execute(IssueQuery query, SearchOptions options) {
Collection<String> components = query.componentUuids();
if (components != null && components.size() == 1 && BooleanUtils.isTrue(query.ignorePaging())) {
- context.setShowFullResult(true);
+ options.disableLimit();
}
- return service.search(query, context);
+ return service.search(query, options);
}
- @Override
- @CheckForNull
- protected Collection<String> possibleFields() {
- return Collections.emptyList();
- }
-
- @Override
- @CheckForNull
- protected Collection<String> possibleFacets() {
- return Arrays.asList(new String[]{
- IssueFilterParameters.SEVERITIES,
- IssueFilterParameters.STATUSES,
- IssueFilterParameters.RESOLUTIONS,
- IssueFilterParameters.ACTION_PLANS,
- IssueFilterParameters.PROJECT_UUIDS,
- IssueFilterParameters.RULES,
- IssueFilterParameters.ASSIGNEES,
- IssueFilterParameters.REPORTERS,
- IssueFilterParameters.AUTHORS,
- IssueFilterParameters.MODULE_UUIDS,
- IssueFilterParameters.FILE_UUIDS,
- IssueFilterParameters.DIRECTORIES,
- IssueFilterParameters.LANGUAGES,
- IssueFilterParameters.TAGS,
- IssueFilterParameters.CREATED_AT,
- });
- }
-
- @Override
- protected void doContextResponse(Request request, QueryContext context, Result<Issue> result, JsonWriter json) {
+ private void writeResponse(Request request, SearchResult<IssueDoc> result, JsonWriter json) {
List<String> issueKeys = newArrayList();
Set<RuleKey> ruleKeys = newHashSet();
Set<String> projectUuids = newHashSet();
@@ -313,21 +300,19 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
Map<String, ComponentDto> componentsByUuid = newHashMap();
Multimap<String, DefaultIssueComment> commentsByIssues = ArrayListMultimap.create();
Collection<ComponentDto> componentDtos = newHashSet();
- List<ComponentDto> projectDtos = newArrayList();
Map<String, ComponentDto> projectsByComponentUuid = newHashMap();
- for (Issue issue : result.getHits()) {
- IssueDoc issueDoc = (IssueDoc) issue;
- issueKeys.add(issue.key());
- ruleKeys.add(issue.ruleKey());
+ for (IssueDoc issueDoc : result.getDocs()) {
+ issueKeys.add(issueDoc.key());
+ ruleKeys.add(issueDoc.ruleKey());
projectUuids.add(issueDoc.projectUuid());
componentUuids.add(issueDoc.componentUuid());
- actionPlanKeys.add(issue.actionPlanKey());
- if (issue.reporter() != null) {
- userLogins.add(issue.reporter());
+ actionPlanKeys.add(issueDoc.actionPlanKey());
+ if (issueDoc.reporter() != null) {
+ userLogins.add(issueDoc.reporter());
}
- if (issue.assignee() != null) {
- userLogins.add(issue.assignee());
+ if (issueDoc.assignee() != null) {
+ userLogins.add(issueDoc.assignee());
}
}
@@ -342,7 +327,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
DbSession session = dbClient.openSession(false);
try {
- List<DefaultIssueComment> comments = issueChangeDao.selectCommentsByIssues(session, issueKeys);
+ List<DefaultIssueComment> comments = dbClient.issueChangeDao().selectCommentsByIssues(session, issueKeys);
for (DefaultIssueComment issueComment : comments) {
userLogins.add(issueComment.userLogin());
commentsByIssues.put(issueComment.issueKey(), issueComment);
@@ -357,7 +342,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
projectUuids.add(component.projectUuid());
}
- projectDtos = dbClient.componentDao().getByUuids(session, projectUuids);
+ List<ComponentDto> projectDtos = dbClient.componentDao().getByUuids(session, projectUuids);
componentDtos.addAll(projectDtos);
for (ComponentDto componentDto : componentDtos) {
componentsByUuid.put(componentDto.uuid(), componentDto);
@@ -378,28 +363,24 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
writeUsers(json, usersByLogin);
writeActionPlans(json, actionPlanByKeys.values());
writeLanguages(json);
-
- // TODO remove legacy paging. Handled by the SearchRequestHandler
- writeLegacyPaging(context, json, result);
}
- private void collectRuleKeys(Request request, Result<Issue> result, Set<RuleKey> ruleKeys) {
- Collection<FacetValue> facetRules = result.getFacetValues(IssueFilterParameters.RULES);
+ private void collectRuleKeys(Request request, SearchResult<IssueDoc> result, Set<RuleKey> ruleKeys) {
+ Set<String> facetRules = result.getFacets().getBucketKeys(IssueFilterParameters.RULES);
if (facetRules != null) {
- for (FacetValue rule: facetRules) {
- ruleKeys.add(RuleKey.parse(rule.getKey()));
+ for (String rule : facetRules) {
+ ruleKeys.add(RuleKey.parse(rule));
}
}
List<String> rulesFromRequest = request.paramAsStrings(IssueFilterParameters.RULES);
- if (rulesFromRequest != null ) {
- for (String ruleKey: rulesFromRequest) {
+ if (rulesFromRequest != null) {
+ for (String ruleKey : rulesFromRequest) {
ruleKeys.add(RuleKey.parse(ruleKey));
}
}
}
- @Override
- protected void writeFacets(Request request, QueryContext context, Result<?> results, JsonWriter json) {
+ protected void writeFacets(Request request, SearchOptions options, SearchResult<IssueDoc> results, JsonWriter json) {
addMandatoryFacetValues(results, IssueFilterParameters.SEVERITIES, Severity.ALL);
addMandatoryFacetValues(results, IssueFilterParameters.STATUSES, Issue.STATUSES);
List<String> resolutions = Lists.newArrayList("");
@@ -429,37 +410,51 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
addMandatoryFacetValues(results, IssueFilterParameters.ACTION_PLANS, actionPlans);
addMandatoryFacetValues(results, IssueFilterParameters.COMPONENT_UUIDS, request.paramAsStrings(IssueFilterParameters.COMPONENT_UUIDS));
- super.writeFacets(request, context, results, json);
+ json.name("facets").beginArray();
+ for (String facetName : options.getFacets()) {
+ json.beginObject();
+ json.prop("property", facetName);
+ json.name("values").beginArray();
+ if (results.getFacets().contains(facetName)) {
+ Set<String> itemsFromFacets = Sets.newHashSet();
+ for (Map.Entry<String, Long> bucket : results.getFacets().get(facetName).entrySet()) {
+ itemsFromFacets.add(bucket.getKey());
+ json.beginObject();
+ json.prop("val", bucket.getKey());
+ json.prop("count", bucket.getValue());
+ json.endObject();
+ }
+ addZeroFacetsForSelectedItems(request, facetName, itemsFromFacets, json);
+ }
+ json.endArray().endObject();
+ }
+ json.endArray();
}
- private void collectFacetsData(Request request, Result<Issue> result, Set<String> projectUuids, Set<String> componentUuids, List<String> userLogins, Set<String> actionPlanKeys) {
- collectFacetKeys(result, IssueFilterParameters.PROJECT_UUIDS, projectUuids);
+ private void collectFacetsData(Request request, SearchResult<IssueDoc> result, Set<String> projectUuids, Set<String> componentUuids, List<String> userLogins,
+ Set<String> actionPlanKeys) {
+ collectBucketKeys(result, IssueFilterParameters.PROJECT_UUIDS, projectUuids);
collectParameterValues(request, IssueFilterParameters.PROJECT_UUIDS, projectUuids);
- collectFacetKeys(result, IssueFilterParameters.COMPONENT_UUIDS, componentUuids);
+ collectBucketKeys(result, IssueFilterParameters.COMPONENT_UUIDS, componentUuids);
collectParameterValues(request, IssueFilterParameters.COMPONENT_UUIDS, componentUuids);
- collectFacetKeys(result, IssueFilterParameters.FILE_UUIDS, componentUuids);
+ collectBucketKeys(result, IssueFilterParameters.FILE_UUIDS, componentUuids);
collectParameterValues(request, IssueFilterParameters.FILE_UUIDS, componentUuids);
- collectFacetKeys(result, IssueFilterParameters.MODULE_UUIDS, componentUuids);
+ collectBucketKeys(result, IssueFilterParameters.MODULE_UUIDS, componentUuids);
collectParameterValues(request, IssueFilterParameters.MODULE_UUIDS, componentUuids);
collectParameterValues(request, IssueFilterParameters.COMPONENT_ROOT_UUIDS, componentUuids);
- collectFacetKeys(result, IssueFilterParameters.ASSIGNEES, userLogins);
+ collectBucketKeys(result, IssueFilterParameters.ASSIGNEES, userLogins);
collectParameterValues(request, IssueFilterParameters.ASSIGNEES, userLogins);
- collectFacetKeys(result, IssueFilterParameters.REPORTERS, userLogins);
+ collectBucketKeys(result, IssueFilterParameters.REPORTERS, userLogins);
collectParameterValues(request, IssueFilterParameters.REPORTERS, userLogins);
- collectFacetKeys(result, IssueFilterParameters.ACTION_PLANS, actionPlanKeys);
+ collectBucketKeys(result, IssueFilterParameters.ACTION_PLANS, actionPlanKeys);
collectParameterValues(request, IssueFilterParameters.ACTION_PLANS, actionPlanKeys);
}
- private void collectFacetKeys(Result<Issue> result, String facetName, Collection<String> facetKeys) {
- Collection<FacetValue> facetValues = result.getFacetValues(facetName);
- if (facetValues != null) {
- for (FacetValue project : facetValues) {
- facetKeys.add(project.getKey());
- }
- }
+ private void collectBucketKeys(SearchResult<IssueDoc> result, String facetName, Collection<String> bucketKeys) {
+ bucketKeys.addAll(result.getFacets().getBucketKeys(facetName));
}
private void collectParameterValues(Request request, String facetName, Collection<String> facetKeys) {
@@ -469,28 +464,6 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
}
}
- private void writeLegacyPaging(QueryContext context, JsonWriter json, Result<?> result) {
- // TODO remove with stas on HTML side
- json.prop("maxResultsReached", false);
-
- long pages = context.getLimit();
- if (pages > 0) {
- pages = result.getTotal() / context.getLimit();
- if (result.getTotal() % context.getLimit() > 0) {
- pages++;
- }
- }
-
- json.name("paging").beginObject()
- .prop("pageIndex", context.getPage())
- .prop("pageSize", context.getLimit())
- .prop("total", result.getTotal())
- // TODO Remove as part of Front-end rework on Issue Domain
- .prop("fTotal", i18n.formatInteger(UserSession.get().locale(), (int) result.getTotal()))
- .prop("pages", pages)
- .endObject();
- }
-
// TODO change to use the RuleMapper
private void writeRules(JsonWriter json, Collection<Rule> rules) {
json.name("rules").beginArray();
@@ -508,11 +481,12 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
json.endArray();
}
- private void writeIssues(Result<Issue> result, Multimap<String, DefaultIssueComment> commentsByIssues, Map<String, User> usersByLogin, Map<String, ActionPlan> actionPlanByKeys,
+ private void writeIssues(SearchResult<IssueDoc> result, Multimap<String, DefaultIssueComment> commentsByIssues, Map<String, User> usersByLogin,
+ Map<String, ActionPlan> actionPlanByKeys,
Map<String, ComponentDto> componentsByUuid, Map<String, ComponentDto> projectsByComponentUuid, @Nullable List<String> extraFields, JsonWriter json) {
json.name("issues").beginArray();
- for (Issue issue : result.getHits()) {
+ for (IssueDoc issue : result.getDocs()) {
json.beginObject();
String actionPlanKey = issue.actionPlanKey();
@@ -520,7 +494,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
ComponentDto project = null, subProject = null;
if (file != null) {
project = projectsByComponentUuid.get(file.uuid());
- if (! file.projectUuid().equals(file.moduleUuid())) {
+ if (!file.projectUuid().equals(file.moduleUuid())) {
subProject = componentsByUuid.get(file.moduleUuid());
}
}
@@ -565,7 +539,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
Collection<String> tags = issue.tags();
if (tags != null && !tags.isEmpty()) {
json.name("tags").beginArray();
- for (String tag: tags) {
+ for (String tag : tags) {
json.value(tag);
}
json.endArray();
@@ -806,4 +780,28 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
return null;
}
+ protected void addMandatoryFacetValues(SearchResult<IssueDoc> results, String facetName, @Nullable List<String> mandatoryValues) {
+ Map<String, Long> buckets = results.getFacets().get(facetName);
+ if (buckets != null && mandatoryValues != null) {
+ for (String mandatoryValue : mandatoryValues) {
+ if (!buckets.containsKey(mandatoryValue)) {
+ buckets.put(mandatoryValue, 0L);
+ }
+ }
+ }
+ }
+
+ private void addZeroFacetsForSelectedItems(Request request, String facetName, Set<String> itemsFromFacets, JsonWriter json) {
+ List<String> requestParams = request.paramAsStrings(facetName);
+ if (requestParams != null) {
+ for (String param : requestParams) {
+ if (!itemsFromFacets.contains(param)) {
+ json.beginObject();
+ json.prop("val", param);
+ json.prop("count", 0);
+ json.endObject();
+ }
+ }
+ }
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SetTagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SetTagsAction.java
index 1119fc96a6f..f6ccf7dc444 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SetTagsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SetTagsAction.java
@@ -19,11 +19,8 @@
*/
package org.sonar.server.issue.ws;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Objects;
import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.NewAction;
@@ -31,14 +28,13 @@ import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.issue.IssueService;
import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
/**
- * Set tags on an issue.
- * @since 5.1
+ * Set tags on an issue
*/
-public class SetTagsAction implements RequestHandler {
-
- private static final Splitter WS_TAGS_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
+public class SetTagsAction implements BaseIssuesWsAction {
private final IssueService service;
@@ -46,7 +42,8 @@ public class SetTagsAction implements RequestHandler {
this.service = service;
}
- void define(WebService.NewController controller) {
+ @Override
+ public void define(WebService.NewController controller) {
NewAction action = controller.createAction("set_tags")
.setHandler(this)
.setPost(true)
@@ -64,8 +61,8 @@ public class SetTagsAction implements RequestHandler {
@Override
public void handle(Request request, Response response) throws Exception {
String key = request.mandatoryParam("key");
- String tags = Strings.nullToEmpty(request.param("tags"));
- Collection<String> resultTags = service.setTags(key, ImmutableSet.copyOf(WS_TAGS_SPLITTER.split(tags)));
+ List<String> tags = Objects.firstNonNull(request.paramAsStrings("tags"), Collections.<String>emptyList());
+ Collection<String> resultTags = service.setTags(key, tags);
JsonWriter json = response.newJsonWriter().beginObject().name("tags").beginArray();
for (String tag : resultTags) {
json.value(tag);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java
index ab47393cc39..c3da60898a4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java
@@ -20,7 +20,9 @@
package org.sonar.server.issue.ws;
import com.google.common.io.Resources;
-import org.sonar.api.server.ws.*;
+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.server.ws.WebService.NewAction;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.issue.IssueService;
@@ -29,7 +31,7 @@ import org.sonar.server.issue.IssueService;
* List issue tags matching a given query.
* @since 5.1
*/
-public class TagsAction implements RequestHandler {
+public class TagsAction implements BaseIssuesWsAction {
private final IssueService service;
@@ -37,7 +39,8 @@ public class TagsAction implements RequestHandler {
this.service = service;
}
- void define(WebService.NewController controller) {
+ @Override
+ public void define(WebService.NewController controller) {
NewAction action = controller.createAction("tags")
.setHandler(this)
.setSince("5.1")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/StickyFacetBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/search/StickyFacetBuilder.java
index ba932a23915..53b36c093ba 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/search/StickyFacetBuilder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/search/StickyFacetBuilder.java
@@ -35,12 +35,10 @@ import java.util.Map;
public class StickyFacetBuilder {
private static final int FACET_DEFAULT_MIN_DOC_COUNT = 1;
-
private static final int FACET_DEFAULT_SIZE = 10;
- private QueryBuilder query;
-
- private Map<String, FilterBuilder> filters;
+ private final QueryBuilder query;
+ private final Map<String, FilterBuilder> filters;
public StickyFacetBuilder(QueryBuilder query, Map<String, FilterBuilder> filters) {
this.query = query;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java
index 0cbf88ebb1d..9d0393a340a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java
@@ -25,20 +25,18 @@ import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortOrder;
-import org.sonar.api.ServerComponent;
+import org.sonar.server.es.BaseIndex;
import org.sonar.server.es.EsClient;
import org.sonar.server.exceptions.NotFoundException;
import java.util.List;
-public class SourceLineIndex implements ServerComponent {
+public class SourceLineIndex extends BaseIndex {
private static final int MAX_RESULT = 500000;
- private final EsClient esClient;
-
public SourceLineIndex(EsClient esClient) {
- this.esClient = esClient;
+ super(esClient);
}
/**
@@ -61,7 +59,7 @@ public class SourceLineIndex implements ServerComponent {
}
int toLimited = size + from - 1;
- for (SearchHit hit : esClient.prepareSearch(SourceLineIndexDefinition.INDEX)
+ for (SearchHit hit : getClient().prepareSearch(SourceLineIndexDefinition.INDEX)
.setTypes(SourceLineIndexDefinition.TYPE)
.setSize(size)
.setQuery(QueryBuilders.boolQuery()
@@ -79,7 +77,7 @@ public class SourceLineIndex implements ServerComponent {
public SourceLineDoc getLine(String fileUuid, int line) {
Preconditions.checkArgument(line > 0, "Line should be greater than 0");
- SearchRequestBuilder request = esClient.prepareSearch(SourceLineIndexDefinition.INDEX)
+ SearchRequestBuilder request = getClient().prepareSearch(SourceLineIndexDefinition.INDEX)
.setTypes(SourceLineIndexDefinition.TYPE)
.setSize(1)
.setQuery(QueryBuilders.boolQuery()
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json
index ff8974c9fc5..8494c14e03e 100644
--- a/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json
+++ b/server/sonar-server/src/main/resources/org/sonar/server/issue/ws/example-search.json
@@ -1,12 +1,7 @@
{
- "securityExclusions": false,
- "maxResultsReached": false,
- "paging": {
- "pageIndex": 1,
- "pageSize": 5,
- "total": 206,
- "pages": 42
- },
+ "total": 206,
+ "p": 1,
+ "ps": 5,
"issues": [
{
"key": "01fc972e-2a3c-433e-bcae-0bd7f88f5123",
diff --git a/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/ProjectCleanerTest.java b/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/ProjectCleanerTest.java
index 0cb24b9a9f7..f2a58bd6107 100644
--- a/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/ProjectCleanerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/ProjectCleanerTest.java
@@ -25,12 +25,15 @@ import org.junit.Test;
import org.slf4j.Logger;
import org.sonar.api.CoreProperties;
import org.sonar.api.config.Settings;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.purge.*;
import org.sonar.core.computation.dbcleaner.period.DefaultPeriodCleaner;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.purge.IdUuidPair;
+import org.sonar.core.purge.PurgeConfiguration;
+import org.sonar.core.purge.PurgeDao;
+import org.sonar.core.purge.PurgeListener;
+import org.sonar.core.purge.PurgeProfiler;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.properties.ProjectSettingsFactory;
-import org.sonar.server.search.IndexClient;
import java.util.Date;
@@ -41,35 +44,25 @@ import static org.mockito.Mockito.*;
public class ProjectCleanerTest {
private ProjectCleaner sut;
- private PurgeDao dao;
- private PurgeProfiler profiler;
- private DefaultPeriodCleaner periodCleaner;
- private PurgeListener purgeListener;
+ private PurgeDao dao= mock(PurgeDao.class);
+ private PurgeProfiler profiler= mock(PurgeProfiler.class);
+ private DefaultPeriodCleaner periodCleaner= mock(DefaultPeriodCleaner.class);
+ private PurgeListener purgeListener= mock(PurgeListener.class);
private ProjectSettingsFactory projectSettingsFactory;
- private IndexClient indexClient;
- private IssueIndex issueIndex;
- private Settings settings;
+ private IssueIndex issueIndex= mock(IssueIndex.class);
+ private Settings settings = new Settings();
@Before
public void before() throws Exception {
- this.dao = mock(PurgeDao.class);
- this.profiler = mock(PurgeProfiler.class);
- this.periodCleaner = mock(DefaultPeriodCleaner.class);
- this.purgeListener = mock(PurgeListener.class);
- this.settings = mock(Settings.class);
this.projectSettingsFactory = mock(ProjectSettingsFactory.class);
when(projectSettingsFactory.newProjectSettings(any(DbSession.class), any(Long.class))).thenReturn(settings);
- this.issueIndex = mock(IssueIndex.class);
- this.indexClient = mock(IndexClient.class);
- when(indexClient.get(IssueIndex.class)).thenReturn(issueIndex);
-
- this.sut = new ProjectCleaner(dao, periodCleaner, profiler, purgeListener, projectSettingsFactory, indexClient);
+ this.sut = new ProjectCleaner(dao, periodCleaner, profiler, purgeListener, projectSettingsFactory, issueIndex);
}
@Test
public void no_profiling_when_property_is_false() throws Exception {
- when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(false);
+ settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, false);
when(projectSettingsFactory.newProjectSettings(any(DbSession.class), any(Long.class))).thenReturn(settings);
sut.purge(mock(DbSession.class), mock(IdUuidPair.class));
@@ -83,12 +76,12 @@ public class ProjectCleanerTest {
sut.purge(mock(DbSession.class), mock(IdUuidPair.class));
- verify(indexClient, never()).get(IssueIndex.class);
+ verifyZeroInteractions(issueIndex);
}
@Test
public void profiling_when_property_is_true() throws Exception {
- when(settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)).thenReturn(true);
+ settings.setProperty(CoreProperties.PROFILING_LOG_PROPERTY, true);
sut.purge(mock(DbSession.class), mock(IdUuidPair.class));
@@ -97,7 +90,7 @@ public class ProjectCleanerTest {
@Test
public void call_period_cleaner_index_client_and_purge_dao() throws Exception {
- when(settings.getInt(DbCleanerConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES)).thenReturn(5);
+ settings.setProperty(DbCleanerConstants.DAYS_BEFORE_DELETING_CLOSED_ISSUES, 5);
sut.purge(mock(DbSession.class), mock(IdUuidPair.class));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/EsUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/EsUtilsTest.java
new file mode 100644
index 00000000000..e5139c098b4
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/EsUtilsTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.es;
+
+import com.google.common.base.Function;
+import org.elasticsearch.search.SearchHit;
+import org.elasticsearch.search.SearchHits;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.server.issue.index.IssueDoc;
+import org.sonar.server.search.BaseDoc;
+import org.sonar.test.TestUtils;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class EsUtilsTest {
+
+ @Test
+ public void convertToDocs_empty() throws Exception {
+ SearchHits hits = mock(SearchHits.class, Mockito.RETURNS_MOCKS);
+ List<BaseDoc> docs = EsUtils.convertToDocs(hits, new Function<Map<String, Object>, BaseDoc>() {
+ @Override
+ public BaseDoc apply(Map<String, Object> input) {
+ return new IssueDoc(input);
+ }
+ });
+ assertThat(docs).isEmpty();
+ }
+
+ @Test
+ public void convertToDocs() throws Exception {
+ SearchHits hits = mock(SearchHits.class, Mockito.RETURNS_MOCKS);
+ when(hits.getHits()).thenReturn(new SearchHit[]{mock(SearchHit.class)});
+ List<BaseDoc> docs = EsUtils.convertToDocs(hits, new Function<Map<String, Object>, BaseDoc>() {
+ @Override
+ public BaseDoc apply(Map<String, Object> input) {
+ return new IssueDoc(input);
+ }
+ });
+ assertThat(docs).hasSize(1);
+ }
+
+ @Test
+ public void util_class() throws Exception {
+ assertThat(TestUtils.hasOnlyPrivateConstructors(EsUtils.class));
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/SearchOptionsTest.java b/server/sonar-server/src/test/java/org/sonar/server/es/SearchOptionsTest.java
new file mode 100644
index 00000000000..e4cac26fca3
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/SearchOptionsTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.es;
+
+import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.server.search.QueryContext;
+
+import java.io.StringWriter;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+public class SearchOptionsTest {
+
+ @Test
+ public void defaults() throws Exception {
+ SearchOptions options = new SearchOptions();
+
+ assertThat(options.getFacets()).isEmpty();
+ assertThat(options.getFields()).isEmpty();
+ assertThat(options.getOffset()).isEqualTo(0);
+ assertThat(options.getLimit()).isEqualTo(10);
+ assertThat(options.getPage()).isEqualTo(1);
+ }
+
+ @Test
+ public void page_shortcut_for_limit_and_offset() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(3, 10);
+
+ assertThat(options.getLimit()).isEqualTo(10);
+ assertThat(options.getOffset()).isEqualTo(20);
+ }
+
+ @Test
+ public void page_starts_at_one() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(1, 10);
+ assertThat(options.getLimit()).isEqualTo(10);
+ assertThat(options.getOffset()).isEqualTo(0);
+ assertThat(options.getPage()).isEqualTo(1);
+ }
+
+ @Test
+ public void with_zero_page_size() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(1, 0);
+ assertThat(options.getLimit()).isEqualTo(0);
+ assertThat(options.getOffset()).isEqualTo(0);
+ assertThat(options.getPage()).isEqualTo(0);
+ }
+
+ @Test
+ public void page_must_be_strictly_positive() throws Exception {
+ try {
+ new SearchOptions().setPage(0, 10);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertThat(e).hasMessage("Page must be greater or equal to 1 (got 0)");
+ }
+ }
+
+ @Test
+ public void use_max_limit_if_negative() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(2, -1);
+ assertThat(options.getLimit()).isEqualTo(SearchOptions.MAX_LIMIT);
+ }
+
+ @Test
+ public void max_limit() throws Exception {
+ SearchOptions options = new SearchOptions().setLimit(42);
+ assertThat(options.getLimit()).isEqualTo(42);
+
+ options.setLimit(SearchOptions.MAX_LIMIT + 10);
+ assertThat(options.getLimit()).isEqualTo(QueryContext.MAX_LIMIT);
+ }
+
+ @Test
+ public void disable_limit() throws Exception {
+ SearchOptions options = new SearchOptions().disableLimit();
+ assertThat(options.getLimit()).isEqualTo(999999);
+ }
+
+ @Test
+ public void max_page_size() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(3, QueryContext.MAX_LIMIT + 10);
+ assertThat(options.getOffset()).isEqualTo(QueryContext.MAX_LIMIT * 2);
+ assertThat(options.getLimit()).isEqualTo(QueryContext.MAX_LIMIT);
+ }
+
+ @Test
+ public void hasField() throws Exception {
+ // parameter is missing -> all the fields are returned by default
+ SearchOptions options = new SearchOptions();
+ assertThat(options.hasField("repo")).isTrue();
+
+ // parameter is set to empty -> all the fields are returned by default
+ options = new SearchOptions().addFields("");
+ assertThat(options.hasField("repo")).isTrue();
+
+ // parameter is set -> return only the selected fields
+ options = new SearchOptions().addFields("name", "repo");
+ assertThat(options.hasField("name")).isTrue();
+ assertThat(options.hasField("repo")).isTrue();
+ assertThat(options.hasField("severity")).isFalse();
+ }
+
+ @Test
+ public void writeJson() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(3, 10);
+ StringWriter json = new StringWriter();
+ JsonWriter jsonWriter = JsonWriter.of(json).beginObject();
+ options.writeJson(jsonWriter, 42L);
+ jsonWriter.endObject().close();
+
+ JSONAssert.assertEquals("{\"total\": 42, \"p\": 3, \"ps\": 10}", json.toString(), true);
+ }
+
+ @Test
+ public void writeDeprecatedJson() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(3, 10);
+ StringWriter json = new StringWriter();
+ JsonWriter jsonWriter = JsonWriter.of(json).beginObject();
+ options.writeDeprecatedJson(jsonWriter, 42L);
+ jsonWriter.endObject().close();
+
+ JSONAssert.assertEquals("{\"paging\": {\"pageIndex\": 3, \"pageSize\": 10, \"total\": 42, \"fTotal\": \"42\", \"pages\": 5}}", json.toString(), true);
+ }
+
+ @Test
+ public void writeDeprecatedJson_exact_nb_of_pages() throws Exception {
+ SearchOptions options = new SearchOptions().setPage(3, 10);
+ StringWriter json = new StringWriter();
+ JsonWriter jsonWriter = JsonWriter.of(json).beginObject();
+ options.writeDeprecatedJson(jsonWriter, 30L);
+ jsonWriter.endObject().close();
+
+ JSONAssert.assertEquals("{\"paging\": {\"pageIndex\": 3, \"pageSize\": 10, \"total\": 30, \"fTotal\": \"30\", \"pages\": 3}}", json.toString(), true);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java
index 939b355c973..553a424f293 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ActionTest.java
@@ -24,12 +24,11 @@ import org.junit.Test;
import org.sonar.api.issue.Issue;
import org.sonar.server.user.UserSession;
-import java.util.List;
+import java.util.Collection;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
-
public class ActionTest {
@Test
@@ -37,9 +36,10 @@ public class ActionTest {
try {
new Action("") {
@Override
- boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
return false;
}
+
@Override
boolean execute(Map<String, Object> properties, Context context) {
return false;
@@ -55,9 +55,10 @@ public class ActionTest {
try {
new Action(null) {
@Override
- boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ boolean verify(Map<String, Object> properties, Collection<Issue> issues, UserSession userSession) {
return false;
}
+
@Override
boolean execute(Map<String, Object> properties, Context context) {
return false;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
index 10a2efadbcc..b85e27a46e5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
@@ -21,7 +21,6 @@
package org.sonar.server.issue;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Test;
@@ -40,14 +39,16 @@ import org.sonar.core.issue.DefaultIssueFilter;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceQuery;
+import org.sonar.server.es.SearchOptions;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.Message;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.issue.filter.IssueFilterService;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.user.UserSession;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
@@ -57,10 +58,7 @@ import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class InternalRubyIssueServiceTest {
@@ -563,7 +561,7 @@ public class InternalRubyIssueServiceTest {
@Test
public void execute_issue_filter_from_issue_query() {
service.execute(Maps.<String, Object>newHashMap());
- verify(issueFilterService).execute(any(IssueQuery.class), any(QueryContext.class));
+ verify(issueFilterService).execute(any(IssueQuery.class), any(SearchOptions.class));
}
@Test
@@ -584,14 +582,14 @@ public class InternalRubyIssueServiceTest {
service.execute(10L, overrideProps);
ArgumentCaptor<IssueQuery> issueQueryArgumentCaptor = ArgumentCaptor.forClass(IssueQuery.class);
- ArgumentCaptor<QueryContext> contextArgumentCaptor = ArgumentCaptor.forClass(QueryContext.class);
+ ArgumentCaptor<SearchOptions> contextArgumentCaptor = ArgumentCaptor.forClass(SearchOptions.class);
verify(issueFilterService).execute(issueQueryArgumentCaptor.capture(), contextArgumentCaptor.capture());
verify(issueFilterService).find(eq(10L), any(UserSession.class));
- QueryContext queryContext = contextArgumentCaptor.getValue();
- assertThat(queryContext.getLimit()).isEqualTo(20);
- assertThat(queryContext.getPage()).isEqualTo(2);
+ SearchOptions searchOptions = contextArgumentCaptor.getValue();
+ assertThat(searchOptions.getLimit()).isEqualTo(20);
+ assertThat(searchOptions.getPage()).isEqualTo(2);
}
@Test
@@ -687,25 +685,25 @@ public class InternalRubyIssueServiceTest {
Map<String, Object> map = newHashMap();
map.put("pageSize", 10l);
map.put("pageIndex", 50);
- QueryContext context = InternalRubyIssueService.toContext(map);
- assertThat(context.getLimit()).isEqualTo(10);
- assertThat(context.getPage()).isEqualTo(50);
+ SearchOptions searchOptions = InternalRubyIssueService.toSearchOptions(map);
+ assertThat(searchOptions.getLimit()).isEqualTo(10);
+ assertThat(searchOptions.getPage()).isEqualTo(50);
map = newHashMap();
map.put("pageSize", -1);
map.put("pageIndex", 50);
- context = InternalRubyIssueService.toContext(map);
- assertThat(context.getLimit()).isEqualTo(500);
- assertThat(context.getPage()).isEqualTo(1);
+ searchOptions = InternalRubyIssueService.toSearchOptions(map);
+ assertThat(searchOptions.getLimit()).isEqualTo(500);
+ assertThat(searchOptions.getPage()).isEqualTo(1);
- context = InternalRubyIssueService.toContext(Maps.<String, Object>newHashMap());
- assertThat(context.getLimit()).isEqualTo(100);
- assertThat(context.getPage()).isEqualTo(1);
+ searchOptions = InternalRubyIssueService.toSearchOptions(Maps.<String, Object>newHashMap());
+ assertThat(searchOptions.getLimit()).isEqualTo(100);
+ assertThat(searchOptions.getPage()).isEqualTo(1);
}
@Test
public void list_tags() throws Exception {
- ImmutableSet<String> tags = ImmutableSet.of("tag1", "tag2", "tag3");
+ List<String> tags = Arrays.asList("tag1", "tag2", "tag3");
when(issueService.listTags(null, 0)).thenReturn(tags);
assertThat(service.listTags()).isEqualTo(tags);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
index 39cb75ea3fd..a781c2deeec 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
@@ -20,367 +20,327 @@
package org.sonar.server.issue;
-import com.google.common.collect.Lists;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.condition.Condition;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.notifications.NotificationManager;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
-import org.sonar.api.rules.Rule;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.issue.db.IssueStorage;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.issue.db.IssueDao;
-import org.sonar.server.issue.notification.IssueChangeNotification;
-import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.rule.RuleTesting;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.user.MockUserSession;
-import org.sonar.server.user.UserSession;
-
-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 com.google.common.collect.Sets.newHashSet;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anyMap;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
public class IssueBulkChangeServiceTest {
- DbClient dbClient = mock(DbClient.class);
- DbSession dbSession = mock(DbSession.class);
-
- IssueDao issueDao = mock(IssueDao.class);
- IssueService issueService = mock(IssueService.class);
- IssueStorage issueStorage = mock(IssueStorage.class);
- DefaultRuleFinder ruleFinder = mock(DefaultRuleFinder.class);
- ComponentDao componentDao = mock(ComponentDao.class);
- NotificationManager notificationService = mock(NotificationManager.class);
-
- IssueBulkChangeService service;
-
- UserSession userSession = MockUserSession.create().setLogin("john").setUserId(10);
-
- DefaultIssue issue;
- Rule rule;
- ComponentDto project;
- ComponentDto file;
-
- List<Action> actions;
-
- @Before
- public void before() {
- when(dbClient.openSession(false)).thenReturn(dbSession);
- when(dbClient.componentDao()).thenReturn(componentDao);
- when(dbClient.issueDao()).thenReturn(issueDao);
-
- rule = Rule.create("repo", "key").setName("the rule name");
- when(ruleFinder.findByKeys(newHashSet(rule.ruleKey()))).thenReturn(newArrayList(rule));
-
- project = new ComponentDto()
- .setId(1L)
- .setKey("MyProject")
- .setLongName("My Project")
- .setQualifier(Qualifiers.PROJECT)
- .setScope(Scopes.PROJECT);
- when(componentDao.getByKeys(dbSession, newHashSet(project.key()))).thenReturn(newArrayList(project));
-
- file = new ComponentDto()
- .setId(2L)
- .setParentProjectId(project.getId())
- .setKey("MyComponent")
- .setLongName("My Component");
- when(componentDao.getByKeys(dbSession, newHashSet(file.key()))).thenReturn(newArrayList(file));
-
- IssueDto issueDto = IssueTesting.newDto(RuleTesting.newDto(rule.ruleKey()).setId(50), file, project).setKee("ABCD");
- issue = issueDto.toDefaultIssue();
-
- org.sonar.server.search.Result<Issue> result = mock(org.sonar.server.search.Result.class);
- when(result.getHits()).thenReturn(newArrayList((Issue) issue));
- when(issueService.search(any(IssueQuery.class), any(QueryContext.class))).thenReturn(result);
- when(issueDao.selectByKeys(dbSession, newArrayList(issue.key()))).thenReturn(newArrayList(issueDto));
-
- actions = newArrayList();
- service = new IssueBulkChangeService(dbClient, issueService, issueStorage, ruleFinder, notificationService, actions);
- }
-
- @Test
- public void should_execute_bulk_change() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- actions.add(new MockAction("assign"));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).hasSize(1);
- assertThat(result.issuesNotChanged()).isEmpty();
-
- verify(issueStorage).save(eq(issue));
- verifyNoMoreInteractions(issueStorage);
- verify(notificationService).scheduleForSending(any(IssueChangeNotification.class));
- verifyNoMoreInteractions(notificationService);
- }
-
- @Test
- public void should_skip_send_notifications() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- actions.add(new MockAction("assign"));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, false);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).hasSize(1);
- assertThat(result.issuesNotChanged()).isEmpty();
-
- verify(issueStorage).save(eq(issue));
- verifyNoMoreInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_execute_bulk_change_with_comment() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
-
- Action commentAction = mock(Action.class);
- when(commentAction.key()).thenReturn("comment");
- when(commentAction.supports(any(Issue.class))).thenReturn(true);
- when(commentAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
- when(commentAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true);
- actions.add(commentAction);
- actions.add(new MockAction("assign"));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, "my comment", true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).hasSize(1);
- assertThat(result.issuesNotChanged()).isEmpty();
-
- verify(commentAction).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
- verify(issueStorage).save(eq(issue));
- }
-
- @Test
- public void should_execute_bulk_change_with_comment_only_on_changed_issues() {
- IssueDto issueDto1 = IssueTesting.newDto(RuleTesting.newDto(rule.ruleKey()).setId(50), file, project).setKee("ABCD");
- IssueDto issueDto2 = IssueTesting.newDto(RuleTesting.newDto(rule.ruleKey()).setId(50), file, project).setKee("EFGH");
-
- org.sonar.server.search.Result<Issue> resultIssues = mock(org.sonar.server.search.Result.class);
- when(resultIssues.getHits()).thenReturn(Lists.<Issue>newArrayList(issueDto1.toDefaultIssue(), issueDto2.toDefaultIssue()));
- when(issueService.search(any(IssueQuery.class), any(QueryContext.class))).thenReturn(resultIssues);
- when(issueDao.selectByKeys(dbSession, newArrayList("ABCD", "EFGH"))).thenReturn(newArrayList(issueDto1, issueDto2));
-
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD,EFGH");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
-
- Action commentAction = mock(Action.class);
- when(commentAction.key()).thenReturn("comment");
- when(commentAction.supports(any(Issue.class))).thenReturn(true);
- when(commentAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
- when(commentAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true);
- actions.add(commentAction);
-
- // This action will only be executed on the first issue, not the second
- Action assignAction = mock(Action.class);
- when(assignAction.key()).thenReturn("assign");
- when(assignAction.supports(any(Issue.class))).thenReturn(true).thenReturn(false);
- when(assignAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
- when(assignAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true).thenReturn(false);
- actions.add(assignAction);
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, "my comment", true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).hasSize(1);
- assertThat(result.issuesNotChanged()).hasSize(1);
-
- // Only one issue will receive the comment
- verify(assignAction, times(1)).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
- verify(issueStorage).save(eq(issueDto1.toDefaultIssue()));
- }
-
- @Test
- public void should_save_once_per_issue() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign,set_severity");
- properties.put("assign.assignee", "fred");
- properties.put("set_severity.severity", "MINOR");
-
- actions.add(new MockAction("set_severity"));
- actions.add(new MockAction("assign"));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).hasSize(1);
- assertThat(result.issuesNotChanged()).isEmpty();
-
- verify(issueStorage, times(1)).save(eq(issue));
- verifyNoMoreInteractions(issueStorage);
- verify(notificationService).scheduleForSending(any(IssueChangeNotification.class));
- verifyNoMoreInteractions(notificationService);
- }
-
- @Test
- public void should_not_execute_bulk_if_issue_does_not_support_action() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- actions.add(new MockAction("assign", true, true, false));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).isEmpty();
- assertThat(result.issuesNotChanged()).hasSize(1);
-
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_not_execute_bulk_if_action_is_not_verified() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- actions.add(new MockAction("assign", false, true, true));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).isEmpty();
- assertThat(result.issuesNotChanged()).isEmpty();
-
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_not_execute_bulk_if_action_could_not_be_executed_on_issue() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- actions.add(new MockAction("assign", true, false, true));
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).isEmpty();
- assertThat(result.issuesNotChanged()).hasSize(1);
-
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_not_execute_bulk_on_unexpected_error() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
-
- Action action = mock(Action.class);
- when(action.key()).thenReturn("assign");
- when(action.supports(any(Issue.class))).thenReturn(true);
- when(action.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
- doThrow(new RuntimeException("Error")).when(action).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
- actions.add(action);
-
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result.issuesChanged()).isEmpty();
- assertThat(result.issuesNotChanged()).hasSize(1);
-
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_fail_if_user_not_logged() {
- userSession = MockUserSession.create().setLogin(null);
-
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "assign");
- properties.put("assign.assignee", "fred");
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- try {
- service.execute(issueBulkChangeQuery, userSession);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(UnauthorizedException.class);
- }
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- @Test
- public void should_fail_if_action_not_found() {
- Map<String, Object> properties = newHashMap();
- properties.put("issues", "ABCD");
- properties.put("actions", "unknown");
- properties.put("unknown.unknown", "unknown");
- IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
- try {
- service.execute(issueBulkChangeQuery, userSession);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("The action : 'unknown' is unknown");
- }
- verifyZeroInteractions(issueStorage);
- verifyZeroInteractions(notificationService);
- }
-
- class MockAction extends Action {
-
- private boolean verify;
- private boolean execute;
-
- public MockAction(String key, boolean verify, boolean execute, final boolean support) {
- super(key);
- this.verify = verify;
- this.execute = execute;
- setConditions(new Condition() {
- @Override
- public boolean matches(Issue issue) {
- return support;
- }
- });
- }
-
- public MockAction(String key) {
- this(key, true, true, true);
- }
-
- @Override
- boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
- return verify;
- }
-
- @Override
- boolean execute(Map<String, Object> properties, Context context) {
- return execute;
- }
- }
+// DbClient dbClient = mock(DbClient.class);
+// DbSession dbSession = mock(DbSession.class);
+//
+// IssueDao issueDao = mock(IssueDao.class);
+// IssueService issueService = mock(IssueService.class);
+// IssueStorage issueStorage = mock(IssueStorage.class);
+// DefaultRuleFinder ruleFinder = mock(DefaultRuleFinder.class);
+// ComponentDao componentDao = mock(ComponentDao.class);
+// NotificationManager notificationService = mock(NotificationManager.class);
+//
+// IssueBulkChangeService service;
+//
+// UserSession userSession = MockUserSession.create().setLogin("john").setUserId(10);
+//
+// IssueDoc issue;
+// Rule rule;
+// ComponentDto project;
+// ComponentDto file;
+//
+// List<Action> actions;
+//
+// @Before
+// public void before() {
+// when(dbClient.openSession(false)).thenReturn(dbSession);
+// when(dbClient.componentDao()).thenReturn(componentDao);
+// when(dbClient.issueDao()).thenReturn(issueDao);
+//
+// rule = Rule.create("repo", "key").setName("the rule name");
+// when(ruleFinder.findByKeys(newHashSet(rule.ruleKey()))).thenReturn(newArrayList(rule));
+//
+// project = new ComponentDto()
+// .setId(1L)
+// .setKey("MyProject")
+// .setLongName("My Project")
+// .setQualifier(Qualifiers.PROJECT)
+// .setScope(Scopes.PROJECT);
+// when(componentDao.getByKeys(dbSession, newHashSet(project.key()))).thenReturn(newArrayList(project));
+//
+// file = new ComponentDto()
+// .setId(2L)
+// .setParentProjectId(project.getId())
+// .setKey("MyComponent")
+// .setLongName("My Component");
+// when(componentDao.getByKeys(dbSession, newHashSet(file.key()))).thenReturn(newArrayList(file));
+//
+// IssueDoc issueDto = IssueTesting.newDoc("ABCD", file).setRuleKey(rule.ruleKey().toString());
+// issue = issueDto.toDefaultIssue();
+//
+// SearchResult<IssueDoc> result = mock(SearchResult.class);
+// when(result.getDocs()).thenReturn(newArrayList((IssueDoc) issue));
+// when(issueService.search(any(IssueQuery.class), any(SearchOptions.class))).thenReturn(result);
+// when(issueDao.selectByKeys(dbSession, newArrayList(issue.key()))).thenReturn(newArrayList(issueDto));
+//
+// actions = newArrayList();
+// service = new IssueBulkChangeService(dbClient, issueService, issueStorage, ruleFinder, notificationService, actions);
+// }
+//
+// @Test
+// public void should_execute_bulk_change() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// actions.add(new MockAction("assign"));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).hasSize(1);
+// assertThat(result.issuesNotChanged()).isEmpty();
+//
+// verify(issueStorage).save(eq(issue));
+// verifyNoMoreInteractions(issueStorage);
+// verify(notificationService).scheduleForSending(any(IssueChangeNotification.class));
+// verifyNoMoreInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_skip_send_notifications() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// actions.add(new MockAction("assign"));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, false);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).hasSize(1);
+// assertThat(result.issuesNotChanged()).isEmpty();
+//
+// verify(issueStorage).save(eq(issue));
+// verifyNoMoreInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_execute_bulk_change_with_comment() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+//
+// Action commentAction = mock(Action.class);
+// when(commentAction.key()).thenReturn("comment");
+// when(commentAction.supports(any(Issue.class))).thenReturn(true);
+// when(commentAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
+// when(commentAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true);
+// actions.add(commentAction);
+// actions.add(new MockAction("assign"));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, "my comment", true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).hasSize(1);
+// assertThat(result.issuesNotChanged()).isEmpty();
+//
+// verify(commentAction).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
+// verify(issueStorage).save(eq(issue));
+// }
+//
+// @Test
+// public void should_execute_bulk_change_with_comment_only_on_changed_issues() {
+// IssueDto issueDto1 = IssueTesting.newDto(RuleTesting.newDto(rule.ruleKey()).setId(50), file, project).setKee("ABCD");
+// IssueDto issueDto2 = IssueTesting.newDto(RuleTesting.newDto(rule.ruleKey()).setId(50), file, project).setKee("EFGH");
+//
+// org.sonar.server.search.Result<Issue> resultIssues = mock(org.sonar.server.search.Result.class);
+// when(resultIssues.getHits()).thenReturn(Lists.<Issue>newArrayList(issueDto1.toDefaultIssue(), issueDto2.toDefaultIssue()));
+// when(issueService.search(any(IssueQuery.class), any(QueryContext.class))).thenReturn(resultIssues);
+// when(issueDao.selectByKeys(dbSession, newArrayList("ABCD", "EFGH"))).thenReturn(newArrayList(issueDto1, issueDto2));
+//
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD,EFGH");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+//
+// Action commentAction = mock(Action.class);
+// when(commentAction.key()).thenReturn("comment");
+// when(commentAction.supports(any(Issue.class))).thenReturn(true);
+// when(commentAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
+// when(commentAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true);
+// actions.add(commentAction);
+//
+// // This action will only be executed on the first issue, not the second
+// Action assignAction = mock(Action.class);
+// when(assignAction.key()).thenReturn("assign");
+// when(assignAction.supports(any(Issue.class))).thenReturn(true).thenReturn(false);
+// when(assignAction.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
+// when(assignAction.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true).thenReturn(false);
+// actions.add(assignAction);
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, "my comment", true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).hasSize(1);
+// assertThat(result.issuesNotChanged()).hasSize(1);
+//
+// // Only one issue will receive the comment
+// verify(assignAction, times(1)).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
+// verify(issueStorage).save(eq(issueDto1.toDefaultIssue()));
+// }
+//
+// @Test
+// public void should_save_once_per_issue() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign,set_severity");
+// properties.put("assign.assignee", "fred");
+// properties.put("set_severity.severity", "MINOR");
+//
+// actions.add(new MockAction("set_severity"));
+// actions.add(new MockAction("assign"));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).hasSize(1);
+// assertThat(result.issuesNotChanged()).isEmpty();
+//
+// verify(issueStorage, times(1)).save(eq(issue));
+// verifyNoMoreInteractions(issueStorage);
+// verify(notificationService).scheduleForSending(any(IssueChangeNotification.class));
+// verifyNoMoreInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_not_execute_bulk_if_issue_does_not_support_action() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// actions.add(new MockAction("assign", true, true, false));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).isEmpty();
+// assertThat(result.issuesNotChanged()).hasSize(1);
+//
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_not_execute_bulk_if_action_is_not_verified() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// actions.add(new MockAction("assign", false, true, true));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).isEmpty();
+// assertThat(result.issuesNotChanged()).isEmpty();
+//
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_not_execute_bulk_if_action_could_not_be_executed_on_issue() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// actions.add(new MockAction("assign", true, false, true));
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).isEmpty();
+// assertThat(result.issuesNotChanged()).hasSize(1);
+//
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_not_execute_bulk_on_unexpected_error() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+//
+// Action action = mock(Action.class);
+// when(action.key()).thenReturn("assign");
+// when(action.supports(any(Issue.class))).thenReturn(true);
+// when(action.verify(anyMap(), anyListOf(Issue.class), any(UserSession.class))).thenReturn(true);
+// doThrow(new RuntimeException("Error")).when(action).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
+// actions.add(action);
+//
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+// assertThat(result.issuesChanged()).isEmpty();
+// assertThat(result.issuesNotChanged()).hasSize(1);
+//
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_fail_if_user_not_logged() {
+// userSession = MockUserSession.create().setLogin(null);
+//
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "assign");
+// properties.put("assign.assignee", "fred");
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// try {
+// service.execute(issueBulkChangeQuery, userSession);
+// fail();
+// } catch (Exception e) {
+// assertThat(e).isInstanceOf(UnauthorizedException.class);
+// }
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// @Test
+// public void should_fail_if_action_not_found() {
+// Map<String, Object> properties = newHashMap();
+// properties.put("issues", "ABCD");
+// properties.put("actions", "unknown");
+// properties.put("unknown.unknown", "unknown");
+// IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties, true);
+// try {
+// service.execute(issueBulkChangeQuery, userSession);
+// fail();
+// } catch (Exception e) {
+// assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("The action : 'unknown' is unknown");
+// }
+// verifyZeroInteractions(issueStorage);
+// verifyZeroInteractions(notificationService);
+// }
+//
+// class MockAction extends Action {
+//
+// private boolean verify;
+// private boolean execute;
+//
+// public MockAction(String key, boolean verify, boolean execute, final boolean support) {
+// super(key);
+// this.verify = verify;
+// this.execute = execute;
+// setConditions(new Condition() {
+// @Override
+// public boolean matches(Issue issue) {
+// return support;
+// }
+// });
+// }
+//
+// public MockAction(String key) {
+// this(key, true, true, true);
+// }
+//
+// @Override
+// boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+// return verify;
+// }
+//
+// @Override
+// boolean execute(Map<String, Object> properties, Context context) {
+// return execute;
+// }
+// }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
index b405eef9efd..0ae5cf970a6 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
@@ -19,7 +19,11 @@
*/
package org.sonar.server.issue;
-import com.google.common.collect.*;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Multiset;
+import com.google.common.collect.Sets;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
@@ -44,6 +48,8 @@ import org.sonar.core.user.UserDto;
import org.sonar.server.component.ComponentTesting;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.db.IssueDao;
@@ -55,8 +61,6 @@ import org.sonar.server.permission.PermissionChange;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.db.RuleDao;
import org.sonar.server.search.BaseNormalizer;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.source.index.SourceLineDoc;
import org.sonar.server.source.index.SourceLineIndexer;
import org.sonar.server.source.index.SourceLineResultSetIterator;
@@ -66,7 +70,6 @@ import org.sonar.server.user.NewUser;
import org.sonar.server.user.UserService;
import org.sonar.server.user.db.GroupDao;
-import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -85,7 +88,7 @@ public class IssueServiceMediumTest {
public static ServerTester tester = new ServerTester();
DbClient db;
- IndexClient indexClient;
+ IssueIndex IssueIndex;
DbSession session;
IssueService service;
@@ -93,7 +96,7 @@ public class IssueServiceMediumTest {
public void setUp() throws Exception {
tester.clearDbAndIndexes();
db = tester.get(DbClient.class);
- indexClient = tester.get(IndexClient.class);
+ IssueIndex = tester.get(IssueIndex.class);
session = db.openSession(false);
service = tester.get(IssueService.class);
}
@@ -126,14 +129,14 @@ public class IssueServiceMediumTest {
saveIssue(IssueTesting.newDto(rule, file, project).setActionPlanKey("P1"));
saveIssue(IssueTesting.newDto(rule, file, project).setActionPlanKey("P2").setResolution("NONE"));
- org.sonar.server.search.Result<Issue> result = service.search(IssueQuery.builder().build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getFacets()).isEmpty();
+ SearchResult<IssueDoc> result = service.search(IssueQuery.builder().build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getFacets().getNames()).isEmpty();
- result = service.search(IssueQuery.builder().build(), new QueryContext().addFacets(Arrays.asList("actionPlans", "assignees")));
- assertThat(result.getFacets().keySet()).hasSize(2);
- assertThat(result.getFacetKeys("actionPlans")).hasSize(2);
- assertThat(result.getFacetKeys("assignees")).hasSize(1);
+ result = service.search(IssueQuery.builder().build(), new SearchOptions().addFacets("actionPlans", "assignees"));
+ assertThat(result.getFacets().getNames()).hasSize(2);
+ assertThat(result.getFacets().get("actionPlans")).hasSize(2);
+ assertThat(result.getFacets().get("assignees")).hasSize(1);
}
@Test
@@ -162,11 +165,11 @@ public class IssueServiceMediumTest {
IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project).setStatus(Issue.STATUS_OPEN));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_OPEN);
+ assertThat(IssueIndex.getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_OPEN);
service.doTransition(issue.getKey(), DefaultTransitions.CONFIRM);
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_CONFIRMED);
+ assertThat(IssueIndex.getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_CONFIRMED);
}
@Test
@@ -183,11 +186,11 @@ public class IssueServiceMediumTest {
session.commit();
index();
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isNull();
+ assertThat(IssueIndex.getByKey(issue.getKey()).assignee()).isNull();
service.assign(issue.getKey(), user.getLogin());
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
+ assertThat(IssueIndex.getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
}
@Test
@@ -204,11 +207,11 @@ public class IssueServiceMediumTest {
session.commit();
index();
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
+ assertThat(IssueIndex.getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
service.assign(issue.getKey(), "");
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isNull();
+ assertThat(IssueIndex.getByKey(issue.getKey()).assignee()).isNull();
}
@Test
@@ -242,11 +245,11 @@ public class IssueServiceMediumTest {
session.commit();
index();
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isNull();
+ assertThat(IssueIndex.getByKey(issue.getKey()).actionPlanKey()).isNull();
service.plan(issue.getKey(), actionPlanKey);
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
+ assertThat(IssueIndex.getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
}
@Test
@@ -260,11 +263,11 @@ public class IssueServiceMediumTest {
db.actionPlanDao().save(new ActionPlanDto().setKey(actionPlanKey).setProjectId(project.getId()));
IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project).setActionPlanKey(actionPlanKey));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
+ assertThat(IssueIndex.getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
service.plan(issue.getKey(), null);
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isNull();
+ assertThat(IssueIndex.getByKey(issue.getKey()).actionPlanKey()).isNull();
}
@Test
@@ -292,11 +295,11 @@ public class IssueServiceMediumTest {
IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project).setSeverity(Severity.BLOCKER));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(IssueIndex.getByKey(issue.getKey()).severity()).isEqualTo(Severity.BLOCKER);
service.setSeverity(issue.getKey(), Severity.MINOR);
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).severity()).isEqualTo(Severity.MINOR);
+ assertThat(IssueIndex.getByKey(issue.getKey()).severity()).isEqualTo(Severity.MINOR);
}
@Test
@@ -311,7 +314,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), null, "Fix it", Severity.MINOR, 2d);
- IssueDoc manualIssue = (IssueDoc) indexClient.get(IssueIndex.class).getByKey(result.key());
+ IssueDoc manualIssue = (IssueDoc) IssueIndex.getByKey(result.key());
assertThat(manualIssue.componentUuid()).isEqualTo(file.uuid());
assertThat(manualIssue.projectUuid()).isEqualTo(project.uuid());
assertThat(manualIssue.ruleKey()).isEqualTo(manualRule.getKey());
@@ -337,7 +340,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 1, "Fix it", Severity.MINOR, 2d);
- IssueDoc manualIssue = (IssueDoc) indexClient.get(IssueIndex.class).getByKey(result.key());
+ IssueDoc manualIssue = (IssueDoc) IssueIndex.getByKey(result.key());
assertThat(manualIssue.componentUuid()).isEqualTo(file.uuid());
assertThat(manualIssue.projectUuid()).isEqualTo(project.uuid());
assertThat(manualIssue.ruleKey()).isEqualTo(manualRule.getKey());
@@ -361,7 +364,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), null, "Fix it", null, 2d);
- Issue manualIssue = indexClient.get(IssueIndex.class).getByKey(result.key());
+ Issue manualIssue = IssueIndex.getByKey(result.key());
assertThat(manualIssue.severity()).isEqualTo(Severity.MAJOR);
}
@@ -377,7 +380,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), null, null, null, 2d);
- Issue manualIssue = indexClient.get(IssueIndex.class).getByKey(result.key());
+ Issue manualIssue = IssueIndex.getByKey(result.key());
assertThat(manualIssue.message()).isEqualTo("Manual rule name");
}
@@ -397,7 +400,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 1, "Fix it", Severity.MINOR, 2d);
- IssueDoc manualIssue = (IssueDoc) indexClient.get(IssueIndex.class).getByKey(result.key());
+ IssueDoc manualIssue = (IssueDoc) IssueIndex.getByKey(result.key());
assertThat(manualIssue.assignee()).isNull();
}
@@ -415,7 +418,7 @@ public class IssueServiceMediumTest {
Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 1, "Fix it", Severity.MINOR, 2d);
- IssueDoc manualIssue = (IssueDoc) indexClient.get(IssueIndex.class).getByKey(result.key());
+ IssueDoc manualIssue = (IssueDoc) IssueIndex.getByKey(result.key());
assertThat(manualIssue.assignee()).isNull();
}
@@ -496,7 +499,7 @@ public class IssueServiceMediumTest {
ComponentDto file = newFile(project);
saveIssue(IssueTesting.newDto(rule, file, project));
- List<Issue> result = service.search(IssueQuery.builder().build(), new QueryContext()).getHits();
+ List<IssueDoc> result = service.search(IssueQuery.builder().build(), new SearchOptions()).getDocs();
assertThat(result).hasSize(1);
}
@@ -548,15 +551,15 @@ public class IssueServiceMediumTest {
IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).isEmpty();
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).isEmpty();
// Tags are lowercased
service.setTags(issue.getKey(), ImmutableSet.of("bug", "Convention"));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).containsOnly("bug", "convention");
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).containsOnly("bug", "convention");
// nulls and empty tags are ignored
service.setTags(issue.getKey(), Sets.newHashSet("security", null, "", "convention"));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
// tag validation
try {
@@ -564,14 +567,14 @@ public class IssueServiceMediumTest {
} catch (Exception exception) {
assertThat(exception).isInstanceOf(IllegalArgumentException.class);
}
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
// unchanged tags
service.setTags(issue.getKey(), ImmutableSet.of("convention", "security"));
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).containsOnly("security", "convention");
service.setTags(issue.getKey(), ImmutableSet.<String>of());
- assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).tags()).isEmpty();
+ assertThat(IssueIndex.getByKey(issue.getKey()).tags()).isEmpty();
}
@Test
@@ -585,7 +588,7 @@ public class IssueServiceMediumTest {
saveIssue(IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention", "java8", "bug")).setResolution(Issue.RESOLUTION_FIXED));
saveIssue(IssueTesting.newDto(rule, file, project).setTags(ImmutableSet.of("convention")));
- assertThat(service.listTagsForComponent(project.uuid(), 5)).contains(entry("convention", 3L), entry("bug", 2L), entry("java8", 1L));
+ assertThat(service.listTagsForComponent(project.uuid(), 5)).containsOnly(entry("convention", 3L), entry("bug", 2L), entry("java8", 1L));
assertThat(service.listTagsForComponent(project.uuid(), 2)).contains(entry("convention", 3L), entry("bug", 2L)).doesNotContainEntry("java8", 1L);
assertThat(service.listTagsForComponent("other", 10)).isEmpty();
}
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 bc1dd5ba7f9..363de1c16e5 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
@@ -26,8 +26,6 @@ import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssueFilter;
import org.sonar.core.issue.IssueFilterSerializer;
@@ -37,14 +35,15 @@ import org.sonar.core.issue.db.IssueFilterFavouriteDao;
import org.sonar.core.issue.db.IssueFilterFavouriteDto;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.user.AuthorizationDao;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.issue.IssueQuery;
+import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.user.UserSession;
@@ -528,14 +527,14 @@ public class IssueFilterServiceTest {
@Test
public void should_execute_from_issue_query() {
IssueQuery issueQuery = IssueQuery.builder().build();
- QueryContext queryContext = new QueryContext().setPage(2, 50);
+ SearchOptions searchOptions = new SearchOptions().setPage(2, 50);
- Result<Issue> result = mock(Result.class);
- when(result.getHits()).thenReturn(newArrayList((Issue) new DefaultIssue()));
+ SearchResult<IssueDoc> result = mock(SearchResult.class);
+ when(result.getDocs()).thenReturn(newArrayList((IssueDoc) new IssueDoc()));
when(result.getTotal()).thenReturn(100L);
- when(issueIndex.search(issueQuery, queryContext)).thenReturn(result);
+ when(issueIndex.search(issueQuery, searchOptions)).thenReturn(result);
- IssueFilterService.IssueFilterResult issueFilterResult = service.execute(issueQuery, queryContext);
+ IssueFilterService.IssueFilterResult issueFilterResult = service.execute(issueQuery, searchOptions);
assertThat(issueFilterResult.issues()).hasSize(1);
assertThat(issueFilterResult.paging().total()).isEqualTo(100);
assertThat(issueFilterResult.paging().pageIndex()).isEqualTo(2);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
index fb39f468d5e..bcb26d6a3e2 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
@@ -32,12 +32,11 @@ import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.core.component.ComponentDto;
import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.IssueTesting;
-import org.sonar.server.search.FacetValue;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.search.Result;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
import org.sonar.server.view.index.ViewDoc;
@@ -46,12 +45,15 @@ import org.sonar.server.view.index.ViewIndexer;
import javax.annotation.Nullable;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
/**
* As soon as IssueIndex take {@link org.sonar.server.es.EsClient} in its constructor, ServerTester should be replaced by EsTester, it will make this test going faster !
@@ -126,9 +128,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("1", ComponentTesting.newFileDto(project)),
IssueTesting.newDoc("2", ComponentTesting.newFileDto(project)));
- assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("1", "2")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("1")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("3", "4")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("1", "2")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("1")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().issueKeys(newArrayList("3", "4")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -145,8 +147,8 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE5", subModule),
IssueTesting.newDoc("ISSUE6", ComponentTesting.newFileDto(subModule)));
- assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(6);
- assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new SearchOptions()).getDocs()).hasSize(6);
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -159,9 +161,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", ComponentTesting.newFileDto(project)),
IssueTesting.newDoc("ISSUE3", ComponentTesting.newFileDto(project2)));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("projectUuids")));
- assertThat(result.getFacets()).containsOnlyKeys("projectUuids");
- assertThat(result.getFacets().get("projectUuids")).containsOnly(new FacetValue("ABCD", 2), new FacetValue("EFGH", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("projectUuids")));
+ assertThat(result.getFacets().getNames()).containsOnly("projectUuids");
+ assertThat(result.getFacets().get("projectUuids")).containsOnly(entry("ABCD", 2L), entry("EFGH", 1L));
}
@Test
@@ -177,15 +179,15 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file));
assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
- .moduleUuids(newArrayList(file.uuid())).build(), new QueryContext()).getHits()).isEmpty();
+ .moduleUuids(newArrayList(file.uuid())).build(), new SearchOptions()).getDocs()).isEmpty();
assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
- .moduleUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+ .moduleUuids(newArrayList(module.uuid())).build(), new SearchOptions()).getDocs()).hasSize(1);
assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
- .moduleUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+ .moduleUuids(newArrayList(subModule.uuid())).build(), new SearchOptions()).getDocs()).hasSize(1);
assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
- .moduleUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+ .moduleUuids(newArrayList(project.uuid())).build(), new SearchOptions()).getDocs()).hasSize(1);
assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
- .moduleUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ .moduleUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -207,20 +209,20 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE5", subModule),
IssueTesting.newDoc("ISSUE6", file3));
- assertThat(index.search(IssueQuery.builder().setContextualized(true).fileUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new QueryContext())
- .getHits()).hasSize(3);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).fileUuids(newArrayList(file1.uuid())).build(), new QueryContext())
- .getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).moduleRootUuids(newArrayList(subModule.uuid())).build(), new QueryContext())
- .getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).moduleRootUuids(newArrayList(module.uuid())).build(), new QueryContext())
- .getHits()).hasSize(4);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).projectUuids(newArrayList(project.uuid())).build(), new QueryContext())
- .getHits()).hasSize(6);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).viewUuids(newArrayList(view)).build(), new QueryContext())
- .getHits()).hasSize(6);
- assertThat(index.search(IssueQuery.builder().setContextualized(true).projectUuids(newArrayList("unknown")).build(), new QueryContext())
- .getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).fileUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new SearchOptions())
+ .getDocs()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).fileUuids(newArrayList(file1.uuid())).build(), new SearchOptions())
+ .getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).moduleRootUuids(newArrayList(subModule.uuid())).build(), new SearchOptions())
+ .getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).moduleRootUuids(newArrayList(module.uuid())).build(), new SearchOptions())
+ .getDocs()).hasSize(4);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).projectUuids(newArrayList(project.uuid())).build(), new SearchOptions())
+ .getDocs()).hasSize(6);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).viewUuids(newArrayList(view)).build(), new SearchOptions())
+ .getDocs()).hasSize(6);
+ assertThat(index.search(IssueQuery.builder().setContextualized(true).projectUuids(newArrayList("unknown")).build(), new SearchOptions())
+ .getDocs()).isEmpty();
}
@Test
@@ -242,15 +244,15 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE5", subModule),
IssueTesting.newDoc("ISSUE6", file3));
- assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
- assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(6);
- assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view)).build(), new QueryContext()).getHits()).hasSize(6);
- assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(1); // XXX
- // Misleading
- // !
- assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new QueryContext()).getHits()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new SearchOptions()).getDocs()).hasSize(6);
+ assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view)).build(), new SearchOptions()).getDocs()).hasSize(6);
+ assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(module.uuid())).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(subModule.uuid())).build(), new SearchOptions()).getDocs()).hasSize(1); // XXX
+ // Misleading
+ // !
+ assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid())).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new SearchOptions()).getDocs()).hasSize(3);
}
@Test
@@ -267,9 +269,10 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE4", file2),
IssueTesting.newDoc("ISSUE5", file3));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("fileUuids")));
- assertThat(result.getFacets()).containsOnlyKeys("fileUuids");
- assertThat(result.getFacets().get("fileUuids")).containsOnly(new FacetValue("A", 1), new FacetValue("ABCD", 1), new FacetValue("BCDE", 2), new FacetValue("CDEF", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("fileUuids")));
+ assertThat(result.getFacets().getNames()).containsOnly("fileUuids");
+ assertThat(result.getFacets().get("fileUuids"))
+ .containsOnly(entry("A", 1L), entry("ABCD", 1L), entry("BCDE", 2L), entry("CDEF", 1L));
}
@Test
@@ -282,9 +285,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file1).setDirectoryPath("/src/main/xoo"),
IssueTesting.newDoc("ISSUE2", file2).setDirectoryPath("/"));
- assertThat(index.search(IssueQuery.builder().directories(newArrayList("/src/main/xoo")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().directories(newArrayList("/")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().directories(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().directories(newArrayList("/src/main/xoo")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().directories(newArrayList("/")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().directories(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -297,9 +300,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file1).setDirectoryPath("/src/main/xoo"),
IssueTesting.newDoc("ISSUE2", file2).setDirectoryPath("/"));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("directories")));
- assertThat(result.getFacets()).containsOnlyKeys("directories");
- assertThat(result.getFacets().get("directories")).containsOnly(new FacetValue("/src/main/xoo", 1), new FacetValue("/", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("directories")));
+ assertThat(result.getFacets().getNames()).containsOnly("directories");
+ assertThat(result.getFacets().get("directories")).containsOnly(entry("/src/main/xoo", 1L), entry("/", 1L));
}
@Test
@@ -322,10 +325,10 @@ public class IssueIndexMediumTest {
String view2 = "CDEF";
indexView(view2, newArrayList(project2.uuid()));
- assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1)).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view2)).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1, view2)).build(), new QueryContext()).getHits()).hasSize(3);
- assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1)).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view2)).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList(view1, view2)).build(), new SearchOptions()).getDocs()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().viewUuids(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -337,9 +340,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setSeverity(Severity.INFO),
IssueTesting.newDoc("ISSUE2", file).setSeverity(Severity.MAJOR));
- assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.INFO, Severity.MAJOR)).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.INFO)).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.BLOCKER)).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.INFO, Severity.MAJOR)).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.INFO)).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().severities(newArrayList(Severity.BLOCKER)).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -352,9 +355,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setSeverity(Severity.INFO),
IssueTesting.newDoc("ISSUE3", file).setSeverity(Severity.MAJOR));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("severities")));
- assertThat(result.getFacets()).containsOnlyKeys("severities");
- assertThat(result.getFacets().get("severities")).containsOnly(new FacetValue("INFO", 2), new FacetValue("MAJOR", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("severities")));
+ assertThat(result.getFacets().getNames()).containsOnly("severities");
+ assertThat(result.getFacets().get("severities")).containsOnly(entry("INFO", 2L), entry("MAJOR", 1L));
}
@Test
@@ -366,9 +369,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setStatus(Issue.STATUS_CLOSED),
IssueTesting.newDoc("ISSUE2", file).setStatus(Issue.STATUS_OPEN));
- assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CLOSED, Issue.STATUS_OPEN)).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CLOSED)).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CONFIRMED)).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CLOSED, Issue.STATUS_OPEN)).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CLOSED)).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_CONFIRMED)).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -381,9 +384,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setStatus(Issue.STATUS_CLOSED),
IssueTesting.newDoc("ISSUE3", file).setStatus(Issue.STATUS_OPEN));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("statuses")));
- assertThat(result.getFacets()).containsOnlyKeys("statuses");
- assertThat(result.getFacets().get("statuses")).containsOnly(new FacetValue("CLOSED", 2), new FacetValue("OPEN", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("statuses")));
+ assertThat(result.getFacets().getNames()).containsOnly("statuses");
+ assertThat(result.getFacets().get("statuses")).containsOnly(entry("CLOSED", 2L), entry("OPEN", 1L));
}
@Test
@@ -395,10 +398,10 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setResolution(Issue.RESOLUTION_FALSE_POSITIVE),
IssueTesting.newDoc("ISSUE2", file).setResolution(Issue.RESOLUTION_FIXED));
- assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_FIXED)).build(), new QueryContext()).getHits())
+ assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE, Issue.RESOLUTION_FIXED)).build(), new SearchOptions()).getDocs())
.hasSize(2);
- assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE)).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_REMOVED)).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_FALSE_POSITIVE)).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().resolutions(newArrayList(Issue.RESOLUTION_REMOVED)).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -411,9 +414,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setResolution(Issue.RESOLUTION_FALSE_POSITIVE),
IssueTesting.newDoc("ISSUE3", file).setResolution(Issue.RESOLUTION_FIXED));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("resolutions")));
- assertThat(result.getFacets()).containsOnlyKeys("resolutions");
- assertThat(result.getFacets().get("resolutions")).containsOnly(new FacetValue("FALSE-POSITIVE", 2), new FacetValue("FIXED", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("resolutions")));
+ assertThat(result.getFacets().getNames()).containsOnly("resolutions");
+ assertThat(result.getFacets().get("resolutions")).containsOnly(entry("FALSE-POSITIVE", 2L), entry("FIXED", 1L));
}
@Test
@@ -426,9 +429,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setStatus(Issue.STATUS_OPEN).setResolution(null),
IssueTesting.newDoc("ISSUE3", file).setStatus(Issue.STATUS_OPEN).setResolution(null));
- assertThat(index.search(IssueQuery.builder().resolved(true).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().resolved(false).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().resolved(null).build(), new QueryContext()).getHits()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().resolved(true).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().resolved(false).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().resolved(null).build(), new SearchOptions()).getDocs()).hasSize(3);
}
@Test
@@ -440,10 +443,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setActionPlanKey("plan1"),
IssueTesting.newDoc("ISSUE2", file).setActionPlanKey("plan2"));
- assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("plan1")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("plan1", "plan2")).build(), new
- QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("plan1")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("plan1", "plan2")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().actionPlans(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -455,9 +457,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setActionPlanKey("plan1"),
IssueTesting.newDoc("ISSUE2", file).setActionPlanKey("plan2"));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("actionPlans")));
- assertThat(result.getFacets()).containsOnlyKeys("actionPlans");
- assertThat(result.getFacets().get("actionPlans")).containsOnly(new FacetValue("plan1", 1), new FacetValue("plan2", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("actionPlans")));
+ assertThat(result.getFacets().getNames()).containsOnly("actionPlans");
+ assertThat(result.getFacets().get("actionPlans")).containsOnly(entry("plan1", 1L), entry("plan2", 1L));
}
@Test
@@ -470,9 +472,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setActionPlanKey(null),
IssueTesting.newDoc("ISSUE3", file).setActionPlanKey(null));
- assertThat(index.search(IssueQuery.builder().planned(true).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().planned(false).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().planned(null).build(), new QueryContext()).getHits()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().planned(true).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().planned(false).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().planned(null).build(), new SearchOptions()).getDocs()).hasSize(3);
}
@Test
@@ -483,8 +485,8 @@ public class IssueIndexMediumTest {
indexIssues(IssueTesting.newDoc("ISSUE1", file).setRuleKey(ruleKey.toString()));
- assertThat(index.search(IssueQuery.builder().rules(newArrayList(ruleKey)).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().rules(newArrayList(RuleKey.of("rule", "without issue"))).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().rules(newArrayList(ruleKey)).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().rules(newArrayList(RuleKey.of("rule", "without issue"))).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -495,9 +497,9 @@ public class IssueIndexMediumTest {
indexIssues(IssueTesting.newDoc("ISSUE1", file).setRuleKey(ruleKey.toString()).setLanguage("xoo"));
- assertThat(index.search(IssueQuery.builder().languages(newArrayList("xoo")).build(), new
- QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().languages(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().languages(newArrayList("xoo")).build(),
+ new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().languages(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -508,9 +510,9 @@ public class IssueIndexMediumTest {
indexIssues(IssueTesting.newDoc("ISSUE1", file).setRuleKey(ruleKey.toString()).setLanguage("xoo"));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("languages")));
- assertThat(result.getFacets()).containsOnlyKeys("languages");
- assertThat(result.getFacets().get("languages")).containsOnly(new FacetValue("xoo", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("languages")));
+ assertThat(result.getFacets().getNames()).containsOnly("languages");
+ assertThat(result.getFacets().get("languages")).containsOnly(entry("xoo", 1L));
}
@Test
@@ -523,9 +525,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setAssignee("simon"),
IssueTesting.newDoc("ISSUE3", file).setAssignee(null));
- assertThat(index.search(IssueQuery.builder().assignees(newArrayList("steph")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().assignees(newArrayList("steph", "simon")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().assignees(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().assignees(newArrayList("steph")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().assignees(newArrayList("steph", "simon")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().assignees(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -539,9 +541,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE3", file).setAssignee("simon"),
IssueTesting.newDoc("ISSUE4", file).setAssignee(null));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("assignees")));
- assertThat(result.getFacets()).containsOnlyKeys("assignees");
- assertThat(result.getFacets().get("assignees")).containsOnly(new FacetValue("steph", 1), new FacetValue("simon", 2), new FacetValue("", 1));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("assignees")));
+ assertThat(result.getFacets().getNames()).containsOnly("assignees");
+ assertThat(result.getFacets().get("assignees")).containsOnly(entry("steph", 1L), entry("simon", 2L), entry("", 1L));
}
@Test
@@ -554,9 +556,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setAssignee(null),
IssueTesting.newDoc("ISSUE3", file).setAssignee(null));
- assertThat(index.search(IssueQuery.builder().assigned(true).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().assigned(false).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().assigned(null).build(), new QueryContext()).getHits()).hasSize(3);
+ assertThat(index.search(IssueQuery.builder().assigned(true).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().assigned(false).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().assigned(null).build(), new SearchOptions()).getDocs()).hasSize(3);
}
@Test
@@ -568,9 +570,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setReporter("fabrice"),
IssueTesting.newDoc("ISSUE2", file).setReporter("stephane"));
- assertThat(index.search(IssueQuery.builder().reporters(newArrayList("fabrice", "stephane")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().reporters(newArrayList("fabrice")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().reporters(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().reporters(newArrayList("fabrice", "stephane")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().reporters(newArrayList("fabrice")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().reporters(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -583,9 +585,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setAuthorLogin("simon"),
IssueTesting.newDoc("ISSUE3", file).setAssignee(null));
- assertThat(index.search(IssueQuery.builder().authors(newArrayList("steph")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().authors(newArrayList("steph", "simon")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().authors(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().authors(newArrayList("steph")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().authors(newArrayList("steph", "simon")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().authors(newArrayList("unknown")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -599,9 +601,9 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE3", file).setAuthorLogin("simon"),
IssueTesting.newDoc("ISSUE4", file).setAuthorLogin(null));
- Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("authors")));
- assertThat(result.getFacets()).containsOnlyKeys("authors");
- assertThat(result.getFacets().get("authors")).containsOnly(new FacetValue("steph", 1), new FacetValue("simon", 2));
+ SearchResult<IssueDoc> result = index.search(IssueQuery.builder().build(), new SearchOptions().addFacets(newArrayList("authors")));
+ assertThat(result.getFacets().getNames()).containsOnly("authors");
+ assertThat(result.getFacets().get("authors")).containsOnly(entry("steph", 1L), entry("simon", 2L));
}
@Test
@@ -613,10 +615,10 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setFuncCreationDate(DateUtils.parseDate("2014-09-20")),
IssueTesting.newDoc("ISSUE2", file).setFuncCreationDate(DateUtils.parseDate("2014-09-23")));
- assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-19")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-20")).build(), new QueryContext()).getHits()).hasSize(2);
- assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-21")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-25")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-19")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-20")).build(), new SearchOptions()).getDocs()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-21")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-25")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -628,10 +630,10 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE1", file).setFuncCreationDate(DateUtils.parseDate("2014-09-20")),
IssueTesting.newDoc("ISSUE2", file).setFuncCreationDate(DateUtils.parseDate("2014-09-23")));
- assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-19")).build(), new QueryContext()).getHits()).isEmpty();
- assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-20")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-21")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-25")).build(), new QueryContext()).getHits()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-19")).build(), new SearchOptions()).getDocs()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-20")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-21")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2014-09-25")).build(), new SearchOptions()).getDocs()).hasSize(2);
}
@Test
@@ -641,121 +643,114 @@ public class IssueIndexMediumTest {
indexIssues(IssueTesting.newDoc("ISSUE1", file).setFuncCreationDate(DateUtils.parseDate("2014-09-20")));
- assertThat(index.search(IssueQuery.builder().createdAt(DateUtils.parseDate("2014-09-20")).build(), new QueryContext()).getHits()).hasSize(1);
- assertThat(index.search(IssueQuery.builder().createdAt(DateUtils.parseDate("2014-09-21")).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().createdAt(DateUtils.parseDate("2014-09-20")).build(), new SearchOptions()).getDocs()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().createdAt(DateUtils.parseDate("2014-09-21")).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
public void facet_on_created_at_with_less_than_20_days() throws Exception {
- QueryContext queryContext = fixtureForCreatedAtFacet();
-
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-01")).createdBefore(DateUtils.parseDate("2014-09-08")).build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(8)
- .containsOnly(
- new FacetValue("2014-08-31T01:00:00+0000", 0),
- new FacetValue("2014-09-01T01:00:00+0000", 2),
- new FacetValue("2014-09-02T01:00:00+0000", 1),
- new FacetValue("2014-09-03T01:00:00+0000", 0),
- new FacetValue("2014-09-04T01:00:00+0000", 0),
- new FacetValue("2014-09-05T01:00:00+0000", 1),
- new FacetValue("2014-09-06T01:00:00+0000", 0),
- new FacetValue("2014-09-07T01:00:00+0000", 0));
+ SearchOptions options = fixtureForCreatedAtFacet();
+
+ IssueQuery query = IssueQuery.builder()
+ .createdAfter(DateUtils.parseDate("2014-09-01"))
+ .createdBefore(DateUtils.parseDate("2014-09-08"))
+ .checkAuthorization(false)
+ .build();
+ SearchResult<IssueDoc> result = index.search(query, options);
+ Map<String, Long> buckets = result.getFacets().get("createdAt");
+ assertThat(buckets).containsOnly(
+ entry("2014-08-31T01:00:00+0000", 0L),
+ entry("2014-09-01T01:00:00+0000", 2L),
+ entry("2014-09-02T01:00:00+0000", 1L),
+ entry("2014-09-03T01:00:00+0000", 0L),
+ entry("2014-09-04T01:00:00+0000", 0L),
+ entry("2014-09-05T01:00:00+0000", 1L),
+ entry("2014-09-06T01:00:00+0000", 0L),
+ entry("2014-09-07T01:00:00+0000", 0L));
}
@Test
public void facet_on_created_at_with_less_than_20_weeks() throws Exception {
- QueryContext queryContext = fixtureForCreatedAtFacet();
+ SearchOptions SearchOptions = fixtureForCreatedAtFacet();
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-01")).createdBefore(DateUtils.parseDate("2014-09-21")).build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(4)
- .containsOnly(
- new FacetValue("2014-08-25T01:00:00+0000", 0),
- new FacetValue("2014-09-01T01:00:00+0000", 4),
- new FacetValue("2014-09-08T01:00:00+0000", 0),
- new FacetValue("2014-09-15T01:00:00+0000", 1));
+ Map<String, Long> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-01")).createdBefore(DateUtils.parseDate("2014-09-21")).build(),
+ SearchOptions).getFacets().get("createdAt");
+ assertThat(createdAt).containsOnly(
+ entry("2014-08-25T01:00:00+0000", 0L),
+ entry("2014-09-01T01:00:00+0000", 4L),
+ entry("2014-09-08T01:00:00+0000", 0L),
+ entry("2014-09-15T01:00:00+0000", 1L));
}
@Test
public void facet_on_created_at_with_less_than_20_months() throws Exception {
- QueryContext queryContext = fixtureForCreatedAtFacet();
-
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-01")).createdBefore(DateUtils.parseDate("2015-01-19")).build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(6)
- .containsOnly(
- new FacetValue("2014-08-01T01:00:00+0000", 0),
- new FacetValue("2014-09-01T01:00:00+0000", 5),
- new FacetValue("2014-10-01T01:00:00+0000", 0),
- new FacetValue("2014-11-01T01:00:00+0000", 0),
- new FacetValue("2014-12-01T01:00:00+0000", 0),
- new FacetValue("2015-01-01T01:00:00+0000", 1));
+ SearchOptions SearchOptions = fixtureForCreatedAtFacet();
+
+ Map<String, Long> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2014-09-01")).createdBefore(DateUtils.parseDate("2015-01-19")).build(),
+ SearchOptions).getFacets().get("createdAt");
+ assertThat(createdAt).containsOnly(
+ entry("2014-08-01T01:00:00+0000", 0L),
+ entry("2014-09-01T01:00:00+0000", 5L),
+ entry("2014-10-01T01:00:00+0000", 0L),
+ entry("2014-11-01T01:00:00+0000", 0L),
+ entry("2014-12-01T01:00:00+0000", 0L),
+ entry("2015-01-01T01:00:00+0000", 1L));
}
@Test
public void facet_on_created_at_with_more_than_20_months() throws Exception {
-
- QueryContext queryContext = fixtureForCreatedAtFacet();
-
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2011-01-01")).createdBefore(DateUtils.parseDate("2016-01-01")).build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(6)
- .containsOnly(
- new FacetValue("2011-01-01T01:00:00+0000", 1),
- new FacetValue("2012-01-01T01:00:00+0000", 0),
- new FacetValue("2013-01-01T01:00:00+0000", 0),
- new FacetValue("2014-01-01T01:00:00+0000", 5),
- new FacetValue("2015-01-01T01:00:00+0000", 1),
- new FacetValue("2016-01-01T01:00:00+0000", 0));
+ SearchOptions SearchOptions = fixtureForCreatedAtFacet();
+
+ Map<String, Long> createdAt = index.search(IssueQuery.builder().createdAfter(DateUtils.parseDate("2011-01-01")).createdBefore(DateUtils.parseDate("2016-01-01")).build(),
+ SearchOptions).getFacets().get("createdAt");
+ assertThat(createdAt).containsOnly(
+ entry("2011-01-01T01:00:00+0000", 1L),
+ entry("2012-01-01T01:00:00+0000", 0L),
+ entry("2013-01-01T01:00:00+0000", 0L),
+ entry("2014-01-01T01:00:00+0000", 5L),
+ entry("2015-01-01T01:00:00+0000", 1L),
+ entry("2016-01-01T01:00:00+0000", 0L));
}
@Test
public void facet_on_created_at_with_bounds_outside_of_data() throws Exception {
-
- QueryContext queryContext = fixtureForCreatedAtFacet();
-
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder()
- .createdAfter(DateUtils.parseDate("2009-01-01"))
- .createdBefore(DateUtils.parseDate("2016-01-01"))
- .build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(8)
- .containsOnly(
- new FacetValue("2009-01-01T01:00:00+0000", 0),
- new FacetValue("2010-01-01T01:00:00+0000", 0),
- new FacetValue("2011-01-01T01:00:00+0000", 1),
- new FacetValue("2012-01-01T01:00:00+0000", 0),
- new FacetValue("2013-01-01T01:00:00+0000", 0),
- new FacetValue("2014-01-01T01:00:00+0000", 5),
- new FacetValue("2015-01-01T01:00:00+0000", 1),
- new FacetValue("2016-01-01T01:00:00+0000", 0));
-
+ SearchOptions options = fixtureForCreatedAtFacet();
+
+ Map<String, Long> createdAt = index.search(IssueQuery.builder()
+ .createdAfter(DateUtils.parseDate("2009-01-01"))
+ .createdBefore(DateUtils.parseDate("2016-01-01"))
+ .build(), options).getFacets().get("createdAt");
+ assertThat(createdAt).containsOnly(
+ entry("2009-01-01T01:00:00+0000", 0L),
+ entry("2010-01-01T01:00:00+0000", 0L),
+ entry("2011-01-01T01:00:00+0000", 1L),
+ entry("2012-01-01T01:00:00+0000", 0L),
+ entry("2013-01-01T01:00:00+0000", 0L),
+ entry("2014-01-01T01:00:00+0000", 5L),
+ entry("2015-01-01T01:00:00+0000", 1L),
+ entry("2016-01-01T01:00:00+0000", 0L));
}
@Test
public void facet_on_created_at_without_start_bound() throws Exception {
-
- QueryContext queryContext = fixtureForCreatedAtFacet();
-
- Collection<FacetValue> createdAt = index.search(IssueQuery.builder()
- .createdBefore(DateUtils.parseDate("2016-01-01")).build(),
- queryContext).getFacets().get("createdAt");
- assertThat(createdAt).hasSize(6)
- .containsOnly(
- new FacetValue("2011-01-01T01:00:00+0000", 1),
- new FacetValue("2012-01-01T01:00:00+0000", 0),
- new FacetValue("2013-01-01T01:00:00+0000", 0),
- new FacetValue("2014-01-01T01:00:00+0000", 5),
- new FacetValue("2015-01-01T01:00:00+0000", 1),
- new FacetValue("2016-01-01T01:00:00+0000", 0));
+ SearchOptions SearchOptions = fixtureForCreatedAtFacet();
+
+ Map<String, Long> createdAt = index.search(IssueQuery.builder().createdBefore(DateUtils.parseDate("2016-01-01")).build(),
+ SearchOptions).getFacets().get("createdAt");
+ assertThat(createdAt).containsOnly(
+ entry("2011-01-01T01:00:00+0000", 1L),
+ entry("2012-01-01T01:00:00+0000", 0L),
+ entry("2013-01-01T01:00:00+0000", 0L),
+ entry("2014-01-01T01:00:00+0000", 5L),
+ entry("2015-01-01T01:00:00+0000", 1L),
+ entry("2016-01-01T01:00:00+0000", 0L));
}
- protected QueryContext fixtureForCreatedAtFacet() {
+ protected SearchOptions fixtureForCreatedAtFacet() {
ComponentDto project = ComponentTesting.newProjectDto();
ComponentDto file = ComponentTesting.newFileDto(project);
@@ -769,8 +764,7 @@ public class IssueIndexMediumTest {
indexIssues(issue0, issue1, issue2, issue3, issue4, issue5, issue6);
- QueryContext queryContext = new QueryContext().addFacets(Arrays.asList("createdAt"));
- return queryContext;
+ return new SearchOptions().addFacets("createdAt");
}
@Test
@@ -783,16 +777,16 @@ public class IssueIndexMediumTest {
IssueQuery.Builder query = IssueQuery.builder();
// There are 12 issues in total, with 10 issues per page, the page 2 should only contain 2 elements
- Result<Issue> result = index.search(query.build(), new QueryContext().setPage(2, 10));
- assertThat(result.getHits()).hasSize(2);
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions().setPage(2, 10));
+ assertThat(result.getDocs()).hasSize(2);
assertThat(result.getTotal()).isEqualTo(12);
- result = index.search(IssueQuery.builder().build(), new QueryContext().setOffset(0).setLimit(5));
- assertThat(result.getHits()).hasSize(5);
+ result = index.search(IssueQuery.builder().build(), new SearchOptions().setOffset(0).setLimit(5));
+ assertThat(result.getDocs()).hasSize(5);
assertThat(result.getTotal()).isEqualTo(12);
- result = index.search(IssueQuery.builder().build(), new QueryContext().setOffset(2).setLimit(0));
- assertThat(result.getHits()).hasSize(0);
+ result = index.search(IssueQuery.builder().build(), new SearchOptions().setOffset(2).setLimit(0));
+ assertThat(result.getDocs()).hasSize(0);
assertThat(result.getTotal()).isEqualTo(12);
}
@@ -808,8 +802,8 @@ public class IssueIndexMediumTest {
indexIssues(issues.toArray(new IssueDoc[] {}));
IssueQuery.Builder query = IssueQuery.builder();
- Result<Issue> result = index.search(query.build(), new QueryContext().setMaxLimit());
- assertThat(result.getHits()).hasSize(500);
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions().setLimit(Integer.MAX_VALUE));
+ assertThat(result.getDocs()).hasSize(SearchOptions.MAX_LIMIT);
}
@Test
@@ -823,16 +817,16 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE3", file).setStatus(Issue.STATUS_REOPENED));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_STATUS).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits().get(0).status()).isEqualTo(Issue.STATUS_CLOSED);
- assertThat(result.getHits().get(1).status()).isEqualTo(Issue.STATUS_OPEN);
- assertThat(result.getHits().get(2).status()).isEqualTo(Issue.STATUS_REOPENED);
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs().get(0).status()).isEqualTo(Issue.STATUS_CLOSED);
+ assertThat(result.getDocs().get(1).status()).isEqualTo(Issue.STATUS_OPEN);
+ assertThat(result.getDocs().get(2).status()).isEqualTo(Issue.STATUS_REOPENED);
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_STATUS).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits().get(0).status()).isEqualTo(Issue.STATUS_REOPENED);
- assertThat(result.getHits().get(1).status()).isEqualTo(Issue.STATUS_OPEN);
- assertThat(result.getHits().get(2).status()).isEqualTo(Issue.STATUS_CLOSED);
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs().get(0).status()).isEqualTo(Issue.STATUS_REOPENED);
+ assertThat(result.getDocs().get(1).status()).isEqualTo(Issue.STATUS_OPEN);
+ assertThat(result.getDocs().get(2).status()).isEqualTo(Issue.STATUS_CLOSED);
}
@Test
@@ -848,20 +842,20 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE5", file).setSeverity(Severity.MAJOR));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_SEVERITY).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits().get(0).severity()).isEqualTo(Severity.INFO);
- assertThat(result.getHits().get(1).severity()).isEqualTo(Severity.MINOR);
- assertThat(result.getHits().get(2).severity()).isEqualTo(Severity.MAJOR);
- assertThat(result.getHits().get(3).severity()).isEqualTo(Severity.CRITICAL);
- assertThat(result.getHits().get(4).severity()).isEqualTo(Severity.BLOCKER);
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs().get(0).severity()).isEqualTo(Severity.INFO);
+ assertThat(result.getDocs().get(1).severity()).isEqualTo(Severity.MINOR);
+ assertThat(result.getDocs().get(2).severity()).isEqualTo(Severity.MAJOR);
+ assertThat(result.getDocs().get(3).severity()).isEqualTo(Severity.CRITICAL);
+ assertThat(result.getDocs().get(4).severity()).isEqualTo(Severity.BLOCKER);
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_SEVERITY).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits().get(0).severity()).isEqualTo(Severity.BLOCKER);
- assertThat(result.getHits().get(1).severity()).isEqualTo(Severity.CRITICAL);
- assertThat(result.getHits().get(2).severity()).isEqualTo(Severity.MAJOR);
- assertThat(result.getHits().get(3).severity()).isEqualTo(Severity.MINOR);
- assertThat(result.getHits().get(4).severity()).isEqualTo(Severity.INFO);
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs().get(0).severity()).isEqualTo(Severity.BLOCKER);
+ assertThat(result.getDocs().get(1).severity()).isEqualTo(Severity.CRITICAL);
+ assertThat(result.getDocs().get(2).severity()).isEqualTo(Severity.MAJOR);
+ assertThat(result.getDocs().get(3).severity()).isEqualTo(Severity.MINOR);
+ assertThat(result.getDocs().get(4).severity()).isEqualTo(Severity.INFO);
}
@Test
@@ -874,16 +868,16 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setAssignee("simon"));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_ASSIGNEE).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).assignee()).isEqualTo("simon");
- assertThat(result.getHits().get(1).assignee()).isEqualTo("steph");
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).assignee()).isEqualTo("simon");
+ assertThat(result.getDocs().get(1).assignee()).isEqualTo("steph");
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_ASSIGNEE).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).assignee()).isEqualTo("steph");
- assertThat(result.getHits().get(1).assignee()).isEqualTo("simon");
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).assignee()).isEqualTo("steph");
+ assertThat(result.getDocs().get(1).assignee()).isEqualTo("simon");
}
@Test
@@ -896,16 +890,16 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setFuncCreationDate(DateUtils.parseDate("2014-09-24")));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CREATION_DATE).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
- assertThat(result.getHits().get(1).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ assertThat(result.getDocs().get(1).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CREATION_DATE).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
- assertThat(result.getHits().get(1).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ assertThat(result.getDocs().get(1).creationDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
}
@Test
@@ -918,16 +912,16 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE2", file).setFuncUpdateDate(DateUtils.parseDate("2014-09-24")));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_UPDATE_DATE).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
- assertThat(result.getHits().get(1).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ assertThat(result.getDocs().get(1).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_UPDATE_DATE).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(2);
- assertThat(result.getHits().get(0).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
- assertThat(result.getHits().get(1).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(2);
+ assertThat(result.getDocs().get(0).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ assertThat(result.getDocs().get(1).updateDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
}
@Test
@@ -941,18 +935,18 @@ public class IssueIndexMediumTest {
IssueTesting.newDoc("ISSUE3", file).setFuncCloseDate(null));
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CLOSE_DATE).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(3);
- assertThat(result.getHits().get(0).closeDate()).isNull();
- assertThat(result.getHits().get(1).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
- assertThat(result.getHits().get(2).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(3);
+ assertThat(result.getDocs().get(0).closeDate()).isNull();
+ assertThat(result.getDocs().get(1).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ assertThat(result.getDocs().get(2).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_CLOSE_DATE).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(3);
- assertThat(result.getHits().get(0).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
- assertThat(result.getHits().get(1).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
- assertThat(result.getHits().get(2).closeDate()).isNull();
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(3);
+ assertThat(result.getDocs().get(0).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-24"));
+ assertThat(result.getDocs().get(1).closeDate()).isEqualTo(DateUtils.parseDate("2014-09-23"));
+ assertThat(result.getDocs().get(2).closeDate()).isNull();
}
@Test
@@ -975,25 +969,25 @@ public class IssueIndexMediumTest {
// ascending sort -> F1 then F2. Line "0" first.
IssueQuery.Builder query = IssueQuery.builder().sort(IssueQuery.SORT_BY_FILE_LINE).asc(true);
- Result<Issue> result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(6);
- assertThat(result.getHits().get(0).key()).isEqualTo("F1_1");
- assertThat(result.getHits().get(1).key()).isEqualTo("F1_2");
- assertThat(result.getHits().get(2).key()).isEqualTo("F1_3");
- assertThat(result.getHits().get(3).key()).isEqualTo("F2_1");
- assertThat(result.getHits().get(4).key()).isEqualTo("F2_2");
- assertThat(result.getHits().get(5).key()).isEqualTo("F2_3");
+ SearchResult<IssueDoc> result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(6);
+ assertThat(result.getDocs().get(0).key()).isEqualTo("F1_1");
+ assertThat(result.getDocs().get(1).key()).isEqualTo("F1_2");
+ assertThat(result.getDocs().get(2).key()).isEqualTo("F1_3");
+ assertThat(result.getDocs().get(3).key()).isEqualTo("F2_1");
+ assertThat(result.getDocs().get(4).key()).isEqualTo("F2_2");
+ assertThat(result.getDocs().get(5).key()).isEqualTo("F2_3");
// descending sort -> F2 then F1
query = IssueQuery.builder().sort(IssueQuery.SORT_BY_FILE_LINE).asc(false);
- result = index.search(query.build(), new QueryContext());
- assertThat(result.getHits()).hasSize(6);
- assertThat(result.getHits().get(0).key()).isEqualTo("F2_3");
- assertThat(result.getHits().get(1).key()).isEqualTo("F2_2");
- assertThat(result.getHits().get(2).key()).isEqualTo("F2_1");
- assertThat(result.getHits().get(3).key()).isEqualTo("F1_3");
- assertThat(result.getHits().get(4).key()).isEqualTo("F1_2");
- assertThat(result.getHits().get(5).key()).isEqualTo("F1_1");
+ result = index.search(query.build(), new SearchOptions());
+ assertThat(result.getDocs()).hasSize(6);
+ assertThat(result.getDocs().get(0).key()).isEqualTo("F2_3");
+ assertThat(result.getDocs().get(1).key()).isEqualTo("F2_2");
+ assertThat(result.getDocs().get(2).key()).isEqualTo("F2_1");
+ assertThat(result.getDocs().get(3).key()).isEqualTo("F1_3");
+ assertThat(result.getDocs().get(4).key()).isEqualTo("F1_2");
+ assertThat(result.getDocs().get(5).key()).isEqualTo("F1_1");
}
@Test
@@ -1013,22 +1007,20 @@ public class IssueIndexMediumTest {
// project3 can be seen by nobody
indexIssue(IssueTesting.newDoc("ISSUE3", file3), null, null);
- IssueQuery.Builder query = IssueQuery.builder();
-
MockUserSession.set().setUserGroups("sonar-users");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1);
MockUserSession.set().setUserGroups("sonar-admins");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1);
MockUserSession.set().setUserGroups("sonar-users", "sonar-admins");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(2);
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(2);
MockUserSession.set().setUserGroups("another group");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).isEmpty();
MockUserSession.set().setUserGroups("sonar-users", "sonar-admins");
- assertThat(index.search(query.projectUuids(newArrayList(project3.uuid())).build(), new QueryContext()).getHits()).isEmpty();
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project3.uuid())).build(), new SearchOptions()).getDocs()).isEmpty();
}
@Test
@@ -1046,19 +1038,18 @@ public class IssueIndexMediumTest {
indexIssue(IssueTesting.newDoc("ISSUE2", file2), null, "max");
indexIssue(IssueTesting.newDoc("ISSUE3", file3), null, null);
- IssueQuery.Builder query = IssueQuery.builder();
-
MockUserSession.set().setLogin("john");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(1);
+
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1);
MockUserSession.set().setLogin("max");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(1);
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(1);
MockUserSession.set().setLogin("another guy");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(0);
+ assertThat(index.search(IssueQuery.builder().build(), new SearchOptions()).getDocs()).hasSize(0);
MockUserSession.set().setLogin("john");
- assertThat(index.search(query.projectUuids(newArrayList(project3.key())).build(), new QueryContext()).getHits()).hasSize(0);
+ assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project3.key())).build(), new SearchOptions()).getDocs()).hasSize(0);
}
@Test
@@ -1075,7 +1066,7 @@ public class IssueIndexMediumTest {
IssueQuery.Builder query = IssueQuery.builder();
MockUserSession.set().setLogin("john").setUserGroups("sonar-users");
- assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(1);
+ assertThat(index.search(query.build(), new SearchOptions()).getDocs()).hasSize(1);
}
@Test
@@ -1091,17 +1082,22 @@ public class IssueIndexMediumTest {
// Issue assigned to julien should not be returned as the issue is closed
IssueTesting.newDoc("ISSUE5", file).setAssignee("julien").setStatus(Issue.STATUS_CLOSED));
- List<FacetValue> results = index.listAssignees(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_OPEN)).build());
-
+ LinkedHashMap<String, Long> results = index.searchForAssignees(IssueQuery.builder().statuses(newArrayList(Issue.STATUS_OPEN)).build());
assertThat(results).hasSize(3);
- assertThat(results.get(0).getKey()).isEqualTo("steph");
- assertThat(results.get(0).getValue()).isEqualTo(2);
- assertThat(results.get(1).getKey()).isEqualTo("simon");
- assertThat(results.get(1).getValue()).isEqualTo(1);
+ Iterator<Map.Entry<String, Long>> buckets = results.entrySet().iterator();
- assertThat(results.get(2).getKey()).isEqualTo("_notAssigned_");
- assertThat(results.get(2).getValue()).isEqualTo(1);
+ Map.Entry<String, Long> bucket = buckets.next();
+ assertThat(bucket.getKey()).isEqualTo("steph");
+ assertThat(bucket.getValue()).isEqualTo(2L);
+
+ bucket = buckets.next();
+ assertThat(bucket.getKey()).isEqualTo("simon");
+ assertThat(bucket.getValue()).isEqualTo(1L);
+
+ bucket = buckets.next();
+ assertThat(bucket.getKey()).isEqualTo("_notAssigned_");
+ assertThat(bucket.getValue()).isEqualTo(1L);
}
@Test
@@ -1123,9 +1119,9 @@ public class IssueIndexMediumTest {
index.deleteClosedIssuesOfProjectBefore(project.uuid(), yesterday);
// ASSERT
- List<Issue> issues = index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits();
+ List<IssueDoc> issues = index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new SearchOptions()).getDocs();
List<Date> dates = newArrayList();
- for (Issue issue : issues) {
+ for (IssueDoc issue : issues) {
dates.add(issue.closeDate());
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AuthorsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AuthorsActionTest.java
index 33acb9a906c..c10978bb6ee 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AuthorsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/AuthorsActionTest.java
@@ -31,7 +31,6 @@ import org.sonar.server.ws.WsTester;
import java.util.Arrays;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -47,9 +46,7 @@ public class AuthorsActionTest {
@Before
public void setUp() throws Exception {
- tester = new WsTester(new IssuesWs(mock(IssueShowAction.class), new SearchAction(null, null, null, null, null, null, null, null, null, null, null),
- mock(TagsAction.class), mock(SetTagsAction.class), mock(ComponentTagsAction.class),
- new AuthorsAction(service)));
+ tester = new WsTester(new IssuesWs(new AuthorsAction(service)));
controller = tester.controller("api/issues");
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java
index 31bb581a730..5ea8d46672d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java
@@ -49,10 +49,7 @@ public class ComponentTagsActionTest {
@Before
public void setUp() {
componentTagsAction = new ComponentTagsAction(service);
- tester = new WsTester(
- new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null),
- new SearchAction(null, null, null, null, null, null, null, null, null, null,null),
- new TagsAction(null), new SetTagsAction(null), componentTagsAction, new AuthorsAction(null)));
+ tester = new WsTester(new IssuesWs(componentTagsAction));
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java
index 5dd1de61d0b..d730f222275 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java
@@ -31,7 +31,6 @@ import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.DefaultIssueComment;
import org.sonar.api.issue.internal.FieldDiffs;
-import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
import org.sonar.api.user.User;
@@ -41,7 +40,6 @@ import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.DefaultActionPlan;
-import org.sonar.core.issue.db.IssueChangeDao;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.user.DefaultUser;
@@ -49,7 +47,11 @@ import org.sonar.server.component.ComponentTesting;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.db.DbClient;
import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.issue.*;
+import org.sonar.server.issue.ActionService;
+import org.sonar.server.issue.IssueChangelog;
+import org.sonar.server.issue.IssueChangelogService;
+import org.sonar.server.issue.IssueCommentService;
+import org.sonar.server.issue.IssueService;
import org.sonar.server.issue.actionplan.ActionPlanService;
import org.sonar.server.rule.Rule;
import org.sonar.server.rule.RuleService;
@@ -141,11 +143,7 @@ public class IssueShowActionTest {
tester = new WsTester(new IssuesWs(
new IssueShowAction(dbClient, issueService, issueChangelogService, commentService,
- new IssueActionsWriter(issueService, actionService), actionPlanService, userFinder, debtModel, ruleService, i18n, durations),
- new SearchAction(mock(DbClient.class), mock(IssueChangeDao.class), mock(IssueService.class), mock(IssueActionsWriter.class), mock(IssueQueryService.class),
- mock(RuleService.class),
- mock(ActionPlanService.class), mock(UserFinder.class), mock(I18n.class), mock(Durations.class), mock(Languages.class)),
- new TagsAction(null), new SetTagsAction(null), new ComponentTagsAction(null), new AuthorsAction(null)
+ new IssueActionsWriter(issueService, actionService), actionPlanService, userFinder, debtModel, ruleService, i18n, durations)
));
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueTagsActionTest.java
index 45f97790bde..9519396292b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueTagsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueTagsActionTest.java
@@ -47,10 +47,7 @@ public class IssueTagsActionTest {
@Before
public void setUp() {
tagsAction = new TagsAction(service);
- tester = new WsTester(
- new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null),
- new SearchAction(null, null, null, null, null, null, null, null, null, null,null),
- tagsAction, new SetTagsAction(null), new ComponentTagsAction(null), new AuthorsAction(null)));
+ tester = new WsTester(new IssuesWs(tagsAction));
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java
index f3d0d3e73f9..e47f7fac894 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssuesWsTest.java
@@ -19,242 +19,32 @@
*/
package org.sonar.server.issue.ws;
-import org.junit.Before;
import org.junit.Test;
-import org.sonar.api.i18n.I18n;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.server.ws.WebService;
-import org.sonar.api.user.UserFinder;
-import org.sonar.api.utils.Durations;
-import org.sonar.core.issue.db.IssueChangeDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.issue.IssueChangelogService;
-import org.sonar.server.issue.IssueCommentService;
-import org.sonar.server.issue.IssueQueryService;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.issue.actionplan.ActionPlanService;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.ws.WsTester;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
public class IssuesWsTest {
- IssueShowAction showAction;
-
- WsTester tester;
-
- @Before
- public void setUp() throws Exception {
- IssueChangelogService issueChangelogService = mock(IssueChangelogService.class);
- IssueActionsWriter actionsWriter = mock(IssueActionsWriter.class);
- DebtModelService debtModelService = mock(DebtModelService.class);
- I18n i18n = mock(I18n.class);
- Durations durations = mock(Durations.class);
-
- showAction = new IssueShowAction(mock(DbClient.class), mock(IssueService.class), issueChangelogService, mock(IssueCommentService.class), actionsWriter,
- mock(ActionPlanService.class), mock(UserFinder.class),
- debtModelService, mock(RuleService.class), i18n, durations);
- SearchAction searchAction = new SearchAction(mock(DbClient.class), mock(IssueChangeDao.class), mock(IssueService.class), mock(IssueActionsWriter.class),
- mock(IssueQueryService.class), mock(RuleService.class),
- mock(ActionPlanService.class), mock(UserFinder.class), mock(I18n.class), mock(Durations.class), mock(Languages.class));
- tester = new WsTester(new IssuesWs(showAction, searchAction, new TagsAction(null), new SetTagsAction(null), new ComponentTagsAction(null), new AuthorsAction(null)));
- }
-
@Test
- public void define_controller() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
+ public void define_actions() throws Exception {
+ BaseIssuesWsAction action1 = mock(BaseIssuesWsAction.class);
+ BaseIssuesWsAction action2 = mock(BaseIssuesWsAction.class);
+ IssuesWs ws = new IssuesWs(action1, action2);
+ WebService.Context context = new WebService.Context();
+ ws.define(context);
+
+ WebService.Controller controller = context.controller("api/issues");
assertThat(controller).isNotNull();
assertThat(controller.description()).isNotEmpty();
assertThat(controller.since()).isEqualTo("3.6");
- assertThat(controller.actions()).hasSize(18);
- }
-
- @Test
- public void define_show_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("show");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("4.2");
- assertThat(action.isPost()).isFalse();
- assertThat(action.isInternal()).isTrue();
- assertThat(action.handler()).isSameAs(showAction);
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(1);
-
- WebService.Param key = action.param("key");
- assertThat(key).isNotNull();
- assertThat(key.description()).isNotNull();
- assertThat(key.isRequired()).isFalse();
- }
-
- @Test
- public void define_changelog_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("changelog");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(2);
- }
-
- @Test
- public void define_assign_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("assign");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_add_comment_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("add_comment");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_delete_comment_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("delete_comment");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(1);
- }
-
- @Test
- public void define_edit_comment_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("edit_comment");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_change_severity_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("set_severity");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_plan_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("plan");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_do_transition_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("do_transition");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_transitions_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("transitions");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isFalse();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params()).hasSize(1);
- }
-
- @Test
- public void define_create_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("create");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.params()).hasSize(6);
- }
-
- @Test
- public void define_do_action_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
-
- WebService.Action action = controller.action("do_action");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.6");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.params()).hasSize(3);
- }
-
- @Test
- public void define_bulk_change_action() throws Exception {
- WebService.Controller controller = tester.controller("api/issues");
- WebService.Action action = controller.action("bulk_change");
- assertThat(action).isNotNull();
- assertThat(action.handler()).isNotNull();
- assertThat(action.since()).isEqualTo("3.7");
- assertThat(action.isPost()).isTrue();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isInstanceOf(RailsHandler.class);
- assertThat(action.params()).hasSize(9);
+ assertThat(controller.actions()).isNotEmpty();
+ verify(action1).define(any(WebService.NewController.class));
+ verify(action2).define(any(WebService.NewController.class));
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
index 5a50b56856c..324210099d5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
@@ -27,6 +27,7 @@ import org.junit.Test;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
@@ -158,13 +159,13 @@ public class SearchActionComponentsMediumTest {
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam(IssueFilterParameters.PROJECT_UUIDS, project1.uuid())
- .setParam(SearchAction.PARAM_FACETS, "projectUuids")
+ .setParam(WebService.Param.FACETS, "projectUuids")
.execute()
.assertJson(this.getClass(), "display_sticky_project_facet.json", false);
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam(IssueFilterParameters.COMPONENT_UUIDS, project1.uuid())
- .setParam(SearchAction.PARAM_FACETS, "projectUuids")
+ .setParam(WebService.Param.FACETS, "projectUuids")
.execute()
.assertJson(this.getClass(), "display_non_sticky_project_facet.json", false);
}
@@ -242,7 +243,7 @@ public class SearchActionComponentsMediumTest {
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid())
.setParam(IssueFilterParameters.FILE_UUIDS, file1.uuid() + "," + file3.uuid())
- .setParam(SearchAction.PARAM_FACETS, "fileUuids")
+ .setParam(WebService.Param.FACETS, "fileUuids")
.execute()
.assertJson(this.getClass(), "display_file_facet.json", false);
}
@@ -349,7 +350,7 @@ public class SearchActionComponentsMediumTest {
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid())
.setParam(IssueFilterParameters.MODULE_UUIDS, subModule1.uuid() + "," + subModule3.uuid())
- .setParam(SearchAction.PARAM_FACETS, "moduleUuids")
+ .setParam(WebService.Param.FACETS, "moduleUuids")
.execute()
.assertJson(this.getClass(), "display_module_facet.json", false);
}
@@ -368,7 +369,7 @@ public class SearchActionComponentsMediumTest {
MockUserSession.set().setLogin("john");
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam("resolved", "false")
- .setParam(SearchAction.PARAM_FACETS, "directories")
+ .setParam(WebService.Param.FACETS, "directories")
.execute();
result.assertJson(this.getClass(), "display_directory_facet.json", false);
}
@@ -469,7 +470,7 @@ public class SearchActionComponentsMediumTest {
wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam(IssueFilterParameters.AUTHORS, "leia")
- .setParam(SearchAction.PARAM_FACETS, "authors")
+ .setParam(WebService.Param.FACETS, "authors")
.execute()
.assertJson(this.getClass(), "search_by_authors.json", false);
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 8111464b588..d1bf870bfdc 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
@@ -88,7 +88,7 @@ public class SearchActionMediumTest {
assertThat(show.isPost()).isFalse();
assertThat(show.isInternal()).isFalse();
assertThat(show.responseExampleAsString()).isNotEmpty();
- assertThat(show.params()).hasSize(39);
+ assertThat(show.params()).hasSize(38);
}
@Test
@@ -367,7 +367,7 @@ public class SearchActionMediumTest {
MockUserSession.set().setLogin("john");
WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
.setParam("resolved", "false")
- .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
+ .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
.execute();
result.assertJson(this.getClass(), "display_facets.json", false);
}
@@ -393,7 +393,7 @@ public class SearchActionMediumTest {
.setParam("resolved", "false")
.setParam("severities", "MAJOR,MINOR")
.setParam("languages", "xoo,polop,palap")
- .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
+ .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
.execute();
result.assertJson(this.getClass(), "display_zero_facets.json", false);
}
@@ -451,8 +451,8 @@ public class SearchActionMediumTest {
tester.get(IssueIndexer.class).indexAll();
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION);
- request.setParam(SearchAction.PARAM_PAGE, "2");
- request.setParam(SearchAction.PARAM_PAGE_SIZE, "9");
+ request.setParam(WebService.Param.PAGE, "2");
+ request.setParam(WebService.Param.PAGE_SIZE, "9");
WsTester.Result result = request.execute();
result.assertJson(this.getClass(), "paging.json", false);
@@ -472,8 +472,8 @@ public class SearchActionMediumTest {
tester.get(IssueIndexer.class).indexAll();
WsTester.TestRequest request = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION);
- request.setParam(SearchAction.PARAM_PAGE, "1");
- request.setParam(SearchAction.PARAM_PAGE_SIZE, "-1");
+ request.setParam(WebService.Param.PAGE, "1");
+ request.setParam(WebService.Param.PAGE_SIZE, "-1");
WsTester.Result result = request.execute();
result.assertJson(this.getClass(), "paging_with_page_size_to_minus_one.json", false);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
index 2dd3a9f2bf3..7ccfb597930 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SetTagsActionTest.java
@@ -19,6 +19,7 @@
*/
package org.sonar.server.issue.ws;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Test;
@@ -38,19 +39,14 @@ import static org.mockito.Mockito.when;
public class SetTagsActionTest {
@Mock
- private IssueService service;
-
- private SetTagsAction setTagsAction;
-
- private WsTester tester;
+ IssueService service;
+ SetTagsAction sut;
+ WsTester tester;
@Before
public void setUp() {
- setTagsAction = new SetTagsAction(service);
- tester = new WsTester(
- new IssuesWs(new IssueShowAction(null, null, null, null, null, null, null, null, null, null, null),
- new SearchAction(null, null, null, null, null, null, null, null, null, null,null),
- new TagsAction(null), setTagsAction, new ComponentTagsAction(null), new AuthorsAction(null)));
+ sut = new SetTagsAction(service);
+ tester = new WsTester(new IssuesWs(sut));
}
@Test
@@ -60,7 +56,7 @@ public class SetTagsActionTest {
assertThat(action.responseExampleAsString()).isNull();
assertThat(action.isPost()).isTrue();
assertThat(action.isInternal()).isFalse();
- assertThat(action.handler()).isEqualTo(setTagsAction);
+ assertThat(action.handler()).isEqualTo(sut);
assertThat(action.params()).hasSize(2);
Param query = action.param("key");
@@ -76,9 +72,9 @@ public class SetTagsActionTest {
@Test
public void should_set_tags() throws Exception {
- when(service.setTags("polop", ImmutableSet.of("palap"))).thenReturn(ImmutableSet.of("palap"));
+ when(service.setTags("polop", ImmutableList.of("palap"))).thenReturn(ImmutableSet.of("palap"));
tester.newPostRequest("api/issues", "set_tags").setParam("key", "polop").setParam("tags", "palap").execute()
.assertJson("{\"tags\":[\"palap\"]}");
- verify(service).setTags("polop", ImmutableSet.of("palap"));
+ verify(service).setTags("polop", ImmutableList.of("palap"));
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java
index ff806db5e70..3f80f02f695 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerMediumTest.java
@@ -34,16 +34,18 @@ import org.sonar.core.rule.RuleDto;
import org.sonar.server.component.ComponentTesting;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.IssueTesting;
import org.sonar.server.issue.db.IssueDao;
+import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.permission.InternalPermissionService;
import org.sonar.server.permission.PermissionChange;
import org.sonar.server.rule.RuleTesting;
import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.search.QueryContext;
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
@@ -97,7 +99,9 @@ public class ViewIndexerMediumTest {
indexer.index(viewUuid);
// Execute issue query on view -> 1 issue on view
- assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(1);
+ SearchResult<IssueDoc> docs = tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(),
+ new SearchOptions());
+ assertThat(docs.getDocs()).hasSize(1);
// Add a project to the view and index it again
ComponentDto project2 = addProjectWithIssue(rule);
@@ -107,7 +111,7 @@ public class ViewIndexerMediumTest {
indexer.index(viewUuid);
// Execute issue query on view -> issue of project2 are well taken into account : the cache has been cleared
- assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new QueryContext()).getHits()).hasSize(2);
+ assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().viewUuids(newArrayList(viewUuid)).build(), new SearchOptions()).getDocs()).hasSize(2);
}
private ComponentDto addProjectWithIssue(RuleDto rule) {
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/default_page_size_is_100.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/default_page_size_is_100.json
index 0fc07a00b50..a4dc9a53ed5 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/default_page_size_is_100.json
+++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/default_page_size_is_100.json
@@ -2,7 +2,6 @@
"total": 0,
"p": 1,
"ps": 100,
- "maxResultsReached": false,
"paging": {
"pageIndex": 1,
"pageSize": 100,
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/deprecated_paging.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/deprecated_paging.json
index f67485819f6..1ecb54f2622 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/deprecated_paging.json
+++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/deprecated_paging.json
@@ -1,5 +1,4 @@
{
- "maxResultsReached": false,
"paging": {
"pageIndex": 2,
"pageSize": 9,
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/empty_result.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/empty_result.json
index 4d91f3e640f..787b0028a29 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/empty_result.json
+++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/empty_result.json
@@ -2,7 +2,6 @@
"total": 0,
"p": 1,
"ps": 100,
- "maxResultsReached": false,
"paging": {
"pageIndex": 1,
"pageSize": 100,
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue.json
index ece88f7ed43..ee02f787d29 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue.json
+++ b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issue.json
@@ -1,5 +1,4 @@
{
- "maxResultsReached": false,
"total": 1,
"p": 1,
"ps": 100,