From e9b7afec1168add068654242c4cdc8d7e7131cda Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Mon, 3 Jul 2017 12:06:57 +0200 Subject: [PATCH] SONAR-8890 Restrict ps parameter of WS api/issues/tags --- .../sonar/server/issue/index/IssueIndex.java | 329 +++++++++--------- .../org/sonar/server/issue/ws/TagsAction.java | 26 +- .../server/issue/index/IssueIndexTest.java | 26 +- .../server/issue/ws/SearchActionTest.java | 4 +- .../sonar/server/issue/ws/TagsActionTest.java | 31 +- 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 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 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 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 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 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 filters, QueryBuilder queryBuilder) { + String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE; + String facetName = PARAM_ASSIGNEES; + + // Same as in super.stickyFacetBuilder + Map 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 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 escapeValuesForFacetInclusion(@Nullable Collection 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 filters, QueryBuilder esQuery) { + String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION; + String facetName = PARAM_RESOLUTIONS; + + // Same as in super.stickyFacetBuilder + Map 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 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 createFilters(IssueQuery query) { Map 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 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 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 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 getCreatedAtFacet(IssueQuery query, Map 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 filters, QueryBuilder queryBuilder) { - String fieldName = IssueIndexDefinition.FIELD_ISSUE_ASSIGNEE; - String facetName = PARAM_ASSIGNEES; - - // Same as in super.stickyFacetBuilder - Map 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 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 escapeValuesForFacetInclusion(@Nullable Collection 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 filters, QueryBuilder queryBuilder) { String login = userSession.getLogin(); @@ -544,41 +573,13 @@ public class IssueIndex { .subAggregation(facetTopAggregation)); } - private static AggregationBuilder createResolutionFacet(IssueQuery query, Map filters, QueryBuilder esQuery) { - String fieldName = IssueIndexDefinition.FIELD_ISSUE_RESOLUTION; - String facetName = PARAM_RESOLUTIONS; - - // Same as in super.stickyFacetBuilder - Map 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 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 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 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 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(); -- 2.39.5