aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2017-07-03 12:06:57 +0200
committerTeryk Bellahsene <teryk@users.noreply.github.com>2017-07-28 17:05:09 +0200
commite9b7afec1168add068654242c4cdc8d7e7131cda (patch)
treecdfdeb874be02b1a08aadd1ef38c6a9745ce41a5 /server
parent422912b59e4ffd99d05f45eae4b9289f2e7f6646 (diff)
downloadsonarqube-e9b7afec1168add068654242c4cdc8d7e7131cda.tar.gz
sonarqube-e9b7afec1168add068654242c4cdc8d7e7131cda.zip
SONAR-8890 Restrict ps parameter of WS api/issues/tags
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java329
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/TagsAction.java26
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java26
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java4
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java31
5 files changed, 210 insertions, 206 deletions
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 a19ce5bb2be..df819023a29 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
@@ -70,7 +70,9 @@ import org.sonar.server.user.UserSession;
import org.sonar.server.view.index.ViewIndexDefinition;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
+import static java.util.Collections.emptyList;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@@ -106,8 +108,6 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TYPES;
*/
public class IssueIndex {
- private static final String SUBSTRING_MATCH_REGEXP = ".*%s.*";
-
public static final List<String> SUPPORTED_FACETS = ImmutableList.of(
PARAM_SEVERITIES,
PARAM_STATUSES,
@@ -126,23 +126,18 @@ public class IssueIndex {
PARAM_TAGS,
PARAM_TYPES,
PARAM_CREATED_AT);
-
+ public static final String AGGREGATION_NAME_FOR_TAGS = "tags__issues";
+ private static final String SUBSTRING_MATCH_REGEXP = ".*%s.*";
// TODO to be documented
// TODO move to Facets ?
private static final String FACET_SUFFIX_MISSING = "_missing";
-
private static final String IS_ASSIGNED_FILTER = "__isAssigned";
-
private static final SumBuilder EFFORT_AGGREGATION = AggregationBuilders.sum(FACET_MODE_EFFORT).field(IssueIndexDefinition.FIELD_ISSUE_EFFORT);
private static final Order EFFORT_AGGREGATION_ORDER = Order.aggregation(FACET_MODE_EFFORT, false);
-
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);
-
- public static final String AGGREGATION_NAME_FOR_TAGS = "tags__issues";
-
private final Sorting sorting;
private final EsClient client;
private final System2 system;
@@ -176,6 +171,160 @@ public class IssueIndex {
this.sorting.addDefault(IssueIndexDefinition.FIELD_ISSUE_KEY);
}
+ /**
+ * Optimization - do not send ES request to all shards when scope is restricted
+ * to a set of projects. Because project UUID is used for routing, the request
+ * can be sent to only the shards containing the specified projects.
+ * Note that sticky facets may involve all projects, so this optimization must be
+ * disabled when facets are enabled.
+ */
+ private static void configureRouting(IssueQuery query, SearchOptions options, SearchRequestBuilder requestBuilder) {
+ Collection<String> uuids = query.projectUuids();
+ if (!uuids.isEmpty() && options.getFacets().isEmpty()) {
+ requestBuilder.setRouting(uuids.toArray(new String[uuids.size()]));
+ }
+ }
+
+ private static void configurePagination(SearchOptions options, SearchRequestBuilder esSearch) {
+ esSearch.setFrom(options.getOffset()).setSize(options.getLimit());
+ }
+
+ private static void addComponentRelatedFilters(IssueQuery query, Map<String, QueryBuilder> filters) {
+ QueryBuilder viewFilter = createViewFilter(query.viewUuids());
+ QueryBuilder componentFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids());
+ QueryBuilder projectFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids());
+ QueryBuilder moduleRootFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, query.moduleRootUuids());
+ QueryBuilder moduleFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids());
+ QueryBuilder directoryFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories());
+ QueryBuilder fileFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids());
+
+ if (BooleanUtils.isTrue(query.onComponentOnly())) {
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentFilter);
+ } else {
+ filters.put("__view", viewFilter);
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, projectFilter);
+ filters.put("__module", moduleRootFilter);
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter);
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter);
+ if (fileFilter != null) {
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter);
+ } else {
+ filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentFilter);
+ }
+ }
+ }
+
+ @CheckForNull
+ private static QueryBuilder createViewFilter(Collection<String> viewUuids) {
+ if (viewUuids.isEmpty()) {
+ return null;
+ }
+
+ BoolQueryBuilder viewsFilter = boolQuery();
+ for (String viewUuid : viewUuids) {
+ viewsFilter.should(QueryBuilders.termsLookupQuery(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID)
+ .lookupIndex(ViewIndexDefinition.INDEX_TYPE_VIEW.getIndex())
+ .lookupType(ViewIndexDefinition.INDEX_TYPE_VIEW.getType())
+ .lookupId(viewUuid)
+ .lookupPath(ViewIndexDefinition.FIELD_PROJECTS));
+ }
+ return viewsFilter;
+ }
+
+ private static StickyFacetBuilder newStickyFacetBuilder(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
+ if (hasQueryEffortFacet(query)) {
+ return new StickyFacetBuilder(esQuery, filters, EFFORT_AGGREGATION, EFFORT_AGGREGATION_ORDER);
+ }
+ return new StickyFacetBuilder(esQuery, filters);
+ }
+
+ private static void addSimpleStickyFacetIfNeeded(SearchOptions options, StickyFacetBuilder stickyFacetBuilder, SearchRequestBuilder esSearch,
+ String facetName, String fieldName, Object... selectedValues) {
+ if (options.getFacets().contains(facetName)) {
+ esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(fieldName, facetName, DEFAULT_FACET_SIZE, selectedValues));
+ }
+ }
+
+ private static AggregationBuilder addEffortAggregationIfNeeded(IssueQuery query, AggregationBuilder aggregation) {
+ if (hasQueryEffortFacet(query)) {
+ aggregation.subAggregation(EFFORT_AGGREGATION);
+ }
+ return aggregation;
+ }
+
+ private static boolean hasQueryEffortFacet(IssueQuery query) {
+ return FACET_MODE_EFFORT.equals(query.facetMode()) || DEPRECATED_FACET_MODE_DEBT.equals(query.facetMode());
+ }
+
+ private static AggregationBuilder createAssigneesFacet(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder queryBuilder) {
+ String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE;
+ String facetName = PARAM_ASSIGNEES;
+
+ // Same as in super.stickyFacetBuilder
+ Map<String, QueryBuilder> assigneeFilters = Maps.newHashMap(filters);
+ assigneeFilters.remove(IS_ASSIGNED_FILTER);
+ assigneeFilters.remove(fieldName);
+ StickyFacetBuilder assigneeFacetBuilder = newStickyFacetBuilder(query, assigneeFilters, queryBuilder);
+ BoolQueryBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
+ FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
+
+ Collection<String> assigneesEscaped = escapeValuesForFacetInclusion(query.assignees());
+ if (!assigneesEscaped.isEmpty()) {
+ facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, t -> t, assigneesEscaped.toArray());
+ }
+
+ // Add missing facet for unassigned issues
+ facetTopAggregation.subAggregation(
+ addEffortAggregationIfNeeded(query, AggregationBuilders
+ .missing(facetName + FACET_SUFFIX_MISSING)
+ .field(fieldName)));
+
+ return AggregationBuilders
+ .global(facetName)
+ .subAggregation(facetTopAggregation);
+ }
+
+ private static Collection<String> escapeValuesForFacetInclusion(@Nullable Collection<String> values) {
+ if (values == null) {
+ return Collections.emptyList();
+ }
+ return values.stream().map(Pattern::quote).collect(MoreCollectors.toArrayList(values.size()));
+ }
+
+ private static AggregationBuilder createResolutionFacet(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
+ String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION;
+ String facetName = PARAM_RESOLUTIONS;
+
+ // Same as in super.stickyFacetBuilder
+ Map<String, QueryBuilder> resolutionFilters = Maps.newHashMap(filters);
+ resolutionFilters.remove("__isResolved");
+ resolutionFilters.remove(fieldName);
+ StickyFacetBuilder assigneeFacetBuilder = newStickyFacetBuilder(query, resolutionFilters, esQuery);
+ BoolQueryBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
+ FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
+ facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, t -> t);
+
+ // Add missing facet for unresolved issues
+ facetTopAggregation.subAggregation(
+ addEffortAggregationIfNeeded(query, AggregationBuilders
+ .missing(facetName + FACET_SUFFIX_MISSING)
+ .field(fieldName)));
+
+ return AggregationBuilders
+ .global(facetName)
+ .subAggregation(facetTopAggregation);
+ }
+
+ @CheckForNull
+ private static QueryBuilder createTermsFilter(String field, Collection<?> values) {
+ return values.isEmpty() ? null : termsQuery(field, values);
+ }
+
+ @CheckForNull
+ private static QueryBuilder createTermFilter(String field, @Nullable String value) {
+ return value == null ? null : termQuery(field, value);
+ }
+
public SearchResponse search(IssueQuery query, SearchOptions options) {
SearchRequestBuilder requestBuilder = client.prepareSearch(INDEX_TYPE_ISSUE);
@@ -202,20 +351,6 @@ public class IssueIndex {
return requestBuilder.get();
}
- /**
- * Optimization - do not send ES request to all shards when scope is restricted
- * to a set of projects. Because project UUID is used for routing, the request
- * can be sent to only the shards containing the specified projects.
- * Note that sticky facets may involve all projects, so this optimization must be
- * disabled when facets are enabled.
- */
- private static void configureRouting(IssueQuery query, SearchOptions options, SearchRequestBuilder requestBuilder) {
- Collection<String> uuids = query.projectUuids();
- if (!uuids.isEmpty() && options.getFacets().isEmpty()) {
- requestBuilder.setRouting(uuids.toArray(new String[uuids.size()]));
- }
- }
-
private void configureSorting(IssueQuery query, SearchRequestBuilder esRequest) {
String sortField = query.sort();
if (sortField != null) {
@@ -226,10 +361,6 @@ public class IssueIndex {
}
}
- private static void configurePagination(SearchOptions options, SearchRequestBuilder esSearch) {
- esSearch.setFrom(options.getOffset()).setSize(options.getLimit());
- }
-
private Map<String, QueryBuilder> createFilters(IssueQuery query) {
Map<String, QueryBuilder> filters = new HashMap<>();
filters.put("__authorization", createAuthorizationFilter(query.checkAuthorization()));
@@ -270,48 +401,6 @@ public class IssueIndex {
return filters;
}
- private static void addComponentRelatedFilters(IssueQuery query, Map<String, QueryBuilder> filters) {
- QueryBuilder viewFilter = createViewFilter(query.viewUuids());
- QueryBuilder componentFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids());
- QueryBuilder projectFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids());
- QueryBuilder moduleRootFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, query.moduleRootUuids());
- QueryBuilder moduleFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids());
- QueryBuilder directoryFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories());
- QueryBuilder fileFilter = createTermsFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids());
-
- if (BooleanUtils.isTrue(query.onComponentOnly())) {
- filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentFilter);
- } else {
- filters.put("__view", viewFilter);
- filters.put(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, projectFilter);
- filters.put("__module", moduleRootFilter);
- filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter);
- filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter);
- if (fileFilter != null) {
- filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter);
- } else {
- filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentFilter);
- }
- }
- }
-
- @CheckForNull
- private static QueryBuilder createViewFilter(Collection<String> viewUuids) {
- if (viewUuids.isEmpty()) {
- return null;
- }
-
- BoolQueryBuilder viewsFilter = boolQuery();
- for (String viewUuid : viewUuids) {
- viewsFilter.should(QueryBuilders.termsLookupQuery(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID)
- .lookupIndex(ViewIndexDefinition.INDEX_TYPE_VIEW.getIndex())
- .lookupType(ViewIndexDefinition.INDEX_TYPE_VIEW.getType())
- .lookupId(viewUuid)
- .lookupPath(ViewIndexDefinition.FIELD_PROJECTS));
- }
- return viewsFilter;
- }
-
private QueryBuilder createAuthorizationFilter(boolean checkAuthorization) {
if (checkAuthorization) {
return authorizationTypeSupport.createQueryFilter();
@@ -395,31 +484,6 @@ public class IssueIndex {
}
}
- private static StickyFacetBuilder newStickyFacetBuilder(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
- if (hasQueryEffortFacet(query)) {
- return new StickyFacetBuilder(esQuery, filters, EFFORT_AGGREGATION, EFFORT_AGGREGATION_ORDER);
- }
- return new StickyFacetBuilder(esQuery, filters);
- }
-
- private static void addSimpleStickyFacetIfNeeded(SearchOptions options, StickyFacetBuilder stickyFacetBuilder, SearchRequestBuilder esSearch,
- String facetName, String fieldName, Object... selectedValues) {
- if (options.getFacets().contains(facetName)) {
- esSearch.addAggregation(stickyFacetBuilder.buildStickyFacet(fieldName, facetName, DEFAULT_FACET_SIZE, selectedValues));
- }
- }
-
- private static AggregationBuilder addEffortAggregationIfNeeded(IssueQuery query, AggregationBuilder aggregation) {
- if (hasQueryEffortFacet(query)) {
- aggregation.subAggregation(EFFORT_AGGREGATION);
- }
- return aggregation;
- }
-
- private static boolean hasQueryEffortFacet(IssueQuery query) {
- return FACET_MODE_EFFORT.equals(query.facetMode()) || DEPRECATED_FACET_MODE_DEBT.equals(query.facetMode());
- }
-
private Optional<AggregationBuilder> getCreatedAtFacet(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
long startTime;
Date createdAfter = query.createdAfter();
@@ -483,41 +547,6 @@ public class IssueIndex {
return Optional.of(actualValue.longValue());
}
- private static AggregationBuilder createAssigneesFacet(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder queryBuilder) {
- String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE;
- String facetName = PARAM_ASSIGNEES;
-
- // Same as in super.stickyFacetBuilder
- Map<String, QueryBuilder> assigneeFilters = Maps.newHashMap(filters);
- assigneeFilters.remove(IS_ASSIGNED_FILTER);
- assigneeFilters.remove(fieldName);
- StickyFacetBuilder assigneeFacetBuilder = newStickyFacetBuilder(query, assigneeFilters, queryBuilder);
- BoolQueryBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
- FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
-
- Collection<String> assigneesEscaped = escapeValuesForFacetInclusion(query.assignees());
- if (!assigneesEscaped.isEmpty()) {
- facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, t -> t, assigneesEscaped.toArray());
- }
-
- // Add missing facet for unassigned issues
- facetTopAggregation.subAggregation(
- addEffortAggregationIfNeeded(query, AggregationBuilders
- .missing(facetName + FACET_SUFFIX_MISSING)
- .field(fieldName)));
-
- return AggregationBuilders
- .global(facetName)
- .subAggregation(facetTopAggregation);
- }
-
- private static Collection<String> escapeValuesForFacetInclusion(@Nullable Collection<String> values) {
- if (values == null) {
- return Collections.emptyList();
- }
- return values.stream().map(Pattern::quote).collect(MoreCollectors.toArrayList(values.size()));
- }
-
private void addAssignedToMeFacetIfNeeded(SearchRequestBuilder builder, SearchOptions options, IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder queryBuilder) {
String login = userSession.getLogin();
@@ -544,41 +573,13 @@ public class IssueIndex {
.subAggregation(facetTopAggregation));
}
- private static AggregationBuilder createResolutionFacet(IssueQuery query, Map<String, QueryBuilder> filters, QueryBuilder esQuery) {
- String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION;
- String facetName = PARAM_RESOLUTIONS;
-
- // Same as in super.stickyFacetBuilder
- Map<String, QueryBuilder> resolutionFilters = Maps.newHashMap(filters);
- resolutionFilters.remove("__isResolved");
- resolutionFilters.remove(fieldName);
- StickyFacetBuilder assigneeFacetBuilder = newStickyFacetBuilder(query, resolutionFilters, esQuery);
- BoolQueryBuilder facetFilter = assigneeFacetBuilder.getStickyFacetFilter(fieldName);
- FilterAggregationBuilder facetTopAggregation = assigneeFacetBuilder.buildTopFacetAggregation(fieldName, facetName, facetFilter, DEFAULT_FACET_SIZE);
- facetTopAggregation = assigneeFacetBuilder.addSelectedItemsToFacet(fieldName, facetName, facetTopAggregation, t -> t);
-
- // Add missing facet for unresolved issues
- facetTopAggregation.subAggregation(
- addEffortAggregationIfNeeded(query, AggregationBuilders
- .missing(facetName + FACET_SUFFIX_MISSING)
- .field(fieldName)));
-
- return AggregationBuilders
- .global(facetName)
- .subAggregation(facetTopAggregation);
- }
-
- @CheckForNull
- private static QueryBuilder createTermsFilter(String field, Collection<?> values) {
- return values.isEmpty() ? null : termsQuery(field, values);
- }
-
- @CheckForNull
- private static QueryBuilder createTermFilter(String field, @Nullable String value) {
- return value == null ? null : termQuery(field, value);
- }
+ public List<String> listTags(OrganizationDto organization, @Nullable String textQuery, int size) {
+ int maxPageSize = 500;
+ checkArgument(size <= maxPageSize, "Page size must be lower than or equals to " + maxPageSize);
+ if (size <= 0) {
+ return emptyList();
+ }
- public List<String> listTags(OrganizationDto organization, @Nullable String textQuery, int maxNumberOfTags) {
SearchRequestBuilder requestBuilder = client
.prepareSearch(INDEX_TYPE_ISSUE)
.setQuery(boolQuery()
@@ -588,7 +589,7 @@ public class IssueIndex {
TermsBuilder termsAggregation = AggregationBuilders.terms(AGGREGATION_NAME_FOR_TAGS)
.field(IssueIndexDefinition.FIELD_ISSUE_TAGS)
- .size(maxNumberOfTags)
+ .size(size)
.order(Terms.Order.term(true))
.minDocCount(1L);
if (textQuery != null) {
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 fd97bac9dd8..0359656f0ed 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
@@ -41,7 +41,6 @@ import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.rule.index.RuleIndex;
import org.sonar.server.ws.WsUtils;
-import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION;
/**
@@ -62,6 +61,14 @@ public class TagsAction implements IssuesWsAction {
this.defaultOrganizationProvider = defaultOrganizationProvider;
}
+ private static void writeResponse(Response response, List<String> tags) {
+ try (JsonWriter json = response.newJsonWriter()) {
+ json.beginObject().name("tags").beginArray();
+ tags.forEach(json::value);
+ json.endArray().endObject();
+ }
+ }
+
@Override
public void define(WebService.NewController controller) {
NewAction action = controller.createAction("tags")
@@ -69,13 +76,8 @@ public class TagsAction implements IssuesWsAction {
.setSince("5.1")
.setDescription("List tags matching a given query")
.setResponseExample(Resources.getResource(getClass(), "tags-example.json"));
- action.createParam(Param.TEXT_QUERY)
- .setDescription("A pattern to match tags against")
- .setExampleValue("misra");
- action.createParam(PAGE_SIZE)
- .setDescription("The size of the list to return")
- .setExampleValue("25")
- .setDefaultValue("10");
+ action.createSearchQuery("misra", "tags");
+ action.createPageSize(10, 100);
action.createParam(PARAM_ORGANIZATION)
.setDescription("Organization key")
.setRequired(false)
@@ -114,12 +116,4 @@ public class TagsAction implements IssuesWsAction {
}
}
- private static void writeResponse(Response response, List<String> tags) {
- try (JsonWriter json = response.newJsonWriter()) {
- json.beginObject().name("tags").beginArray();
- tags.forEach(json::value);
- json.endArray().endObject();
- }
- }
-
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
index 416f253ef7e..7e68dac492b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
@@ -77,20 +77,20 @@ import static org.sonar.server.issue.IssueDocTesting.newDoc;
public class IssueIndexTest {
- private System2 system2 = mock(System2.class);
private MapSettings settings = new MapSettings();
+
@Rule
public EsTester es = new EsTester(
new IssueIndexDefinition(settings.asConfig()),
new ViewIndexDefinition(settings.asConfig()),
new RuleIndexDefinition(settings.asConfig()));
@Rule
- public DbTester db = DbTester.create(system2);
- @Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();
-
+ private System2 system2 = mock(System2.class);
+ @Rule
+ public DbTester db = DbTester.create(system2);
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), db.getDbClient(), new IssueIteratorFactory(db.getDbClient()));
private ViewIndexer viewIndexer = new ViewIndexer(db.getDbClient(), es.client());
private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient());
@@ -1083,12 +1083,22 @@ public class IssueIndexTest {
newDoc("I3", file).setOrganizationUuid(org.getUuid()).setRuleKey(r2.getKey().toString()),
newDoc("I4", file).setOrganizationUuid(org.getUuid()).setRuleKey(r1.getKey().toString()).setTags(of("convention")));
- assertThat(underTest.listTags(org, null, Integer.MAX_VALUE)).containsOnly("convention", "java8", "bug");
+ assertThat(underTest.listTags(org, null, 100)).containsOnly("convention", "java8", "bug");
assertThat(underTest.listTags(org, null, 2)).containsOnly("bug", "convention");
- assertThat(underTest.listTags(org, "vent", Integer.MAX_VALUE)).containsOnly("convention");
+ assertThat(underTest.listTags(org, "vent", 100)).containsOnly("convention");
assertThat(underTest.listTags(org, null, 1)).containsOnly("bug");
- assertThat(underTest.listTags(org, null, Integer.MAX_VALUE)).containsOnly("convention", "java8", "bug");
- assertThat(underTest.listTags(org, "invalidRegexp[", Integer.MAX_VALUE)).isEmpty();
+ assertThat(underTest.listTags(org, null, 100)).containsOnly("convention", "java8", "bug");
+ assertThat(underTest.listTags(org, "invalidRegexp[", 100)).isEmpty();
+ }
+
+ @Test
+ public void fail_to_list_tags_when_size_greater_than_500() {
+ OrganizationDto organization = db.organizations().insert();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Page size must be lower than or equals to 500");
+
+ underTest.listTags(organization, null, 501);
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
index 0535e58ed6b..20cf8e1ea69 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
@@ -45,11 +45,11 @@ public class SearchActionTest {
private SearchResponseLoader searchResponseLoader = mock(SearchResponseLoader.class);
private SearchResponseFormat searchResponseFormat = mock(SearchResponseFormat.class);
private SearchAction underTest = new SearchAction(userSession, index, issueQueryFactory, searchResponseLoader, searchResponseFormat);
- private WsActionTester wsTester = new WsActionTester(underTest);
+ private WsActionTester ws = new WsActionTester(underTest);
@Test
public void test_definition() {
- WebService.Action def = wsTester.getDef();
+ WebService.Action def = ws.getDef();
assertThat(def.key()).isEqualTo("search");
assertThat(def.isInternal()).isFalse();
assertThat(def.isPost()).isFalse();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java
index b861d7840a0..69d49c14489 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/TagsActionTest.java
@@ -70,7 +70,7 @@ public class TagsActionTest {
private IssueIndex issueIndex = new IssueIndex(esTester.client(), System2.INSTANCE, userSession, new AuthorizationTypeSupport(userSession));
private RuleIndex ruleIndex = new RuleIndex(esTester.client());
- private WsActionTester tester = new WsActionTester(new TagsAction(issueIndex, ruleIndex, dbTester.getDbClient(), TestDefaultOrganizationProvider.from(dbTester)));
+ private WsActionTester ws = new WsActionTester(new TagsAction(issueIndex, ruleIndex, dbTester.getDbClient(), TestDefaultOrganizationProvider.from(dbTester)));
private OrganizationDto organization;
@Before
@@ -84,7 +84,7 @@ public class TagsActionTest {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag1", "tag2");
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag3", "tag4", "tag5");
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]}");
@@ -103,7 +103,7 @@ public class TagsActionTest {
dbTester.rules().insertOrUpdateMetadata(r2, organization, setTags("tag4", "tag5"));
ruleIndexer.commitAndIndex(dbTester.getSession(), r2.getKey(), organization);
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"]}");
@@ -120,7 +120,7 @@ public class TagsActionTest {
dbTester.rules().insertOrUpdateMetadata(r, organization, setTags("tag7"));
ruleIndexer.commitAndIndex(dbTester.getSession(), r.getKey(), organization);
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\", \"tag6\", \"tag7\"]}");
@@ -132,7 +132,7 @@ public class TagsActionTest {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag1", "tag2");
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag3", "tag4", "tag5");
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("ps", "2")
.setParam("organization", organization.getKey())
.execute().getInput();
@@ -145,7 +145,7 @@ public class TagsActionTest {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag1", "tag2");
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag12", "tag4", "tag5");
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("q", "ag1")
.setParam("organization", organization.getKey())
.execute().getInput();
@@ -158,7 +158,7 @@ public class TagsActionTest {
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "tag1", "tag2");
insertIssueWithoutBrowsePermission(insertRuleWithoutTags(), "tag3", "tag4");
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[\"tag1\", \"tag2\"]}");
@@ -166,14 +166,14 @@ public class TagsActionTest {
}
@Test
- public void return_empty_list() throws Exception {
+ public void empty_list() throws Exception {
userSession.logIn();
- String result = tester.newRequest().execute().getInput();
+ String result = ws.newRequest().execute().getInput();
assertJson(result).isSimilarTo("{\"tags\":[]}");
}
@Test
- public void test_example() throws Exception {
+ public void json_example() throws Exception {
userSession.logIn();
insertIssueWithBrowsePermission(insertRuleWithoutTags(), "convention");
@@ -182,16 +182,17 @@ public class TagsActionTest {
dbTester.rules().insertOrUpdateMetadata(r, organization, setTags("security"));
ruleIndexer.commitAndIndex(dbTester.getSession(), r.getKey(), organization);
- String result = tester.newRequest()
+ String result = ws.newRequest()
.setParam("organization", organization.getKey())
.execute().getInput();
- assertJson(result).isSimilarTo(tester.getDef().responseExampleAsString());
+
+ assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString());
}
@Test
- public void test_definition() {
+ public void definition() {
userSession.logIn();
- Action action = tester.getDef();
+ Action action = ws.getDef();
assertThat(action.description()).isNotEmpty();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.isPost()).isFalse();
@@ -199,13 +200,11 @@ public class TagsActionTest {
assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("q", "ps", "organization");
Param query = action.param("q");
- assertThat(query).isNotNull();
assertThat(query.isRequired()).isFalse();
assertThat(query.description()).isNotEmpty();
assertThat(query.exampleValue()).isNotEmpty();
Param pageSize = action.param("ps");
- assertThat(pageSize).isNotNull();
assertThat(pageSize.isRequired()).isFalse();
assertThat(pageSize.defaultValue()).isEqualTo("10");
assertThat(pageSize.description()).isNotEmpty();