3 * Copyright (C) 2009-2024 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.component.ws;
22 import com.google.common.base.Joiner;
23 import com.tngtech.java.junit.dataprovider.DataProvider;
24 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
25 import com.tngtech.java.junit.dataprovider.UseDataProvider;
26 import java.util.Arrays;
27 import java.util.Date;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Optional;
32 import java.util.function.Consumer;
33 import java.util.stream.IntStream;
34 import java.util.stream.Stream;
35 import javax.annotation.Nullable;
36 import org.junit.Before;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.sonar.api.measures.Metric;
41 import org.sonar.api.resources.Qualifiers;
42 import org.sonar.api.server.ws.WebService;
43 import org.sonar.api.server.ws.WebService.Param;
44 import org.sonar.api.utils.System2;
45 import org.sonar.core.platform.EditionProvider.Edition;
46 import org.sonar.core.platform.PlatformEditionProvider;
47 import org.sonar.db.DbClient;
48 import org.sonar.db.DbSession;
49 import org.sonar.db.DbTester;
50 import org.sonar.db.component.ComponentDto;
51 import org.sonar.db.measure.LiveMeasureDto;
52 import org.sonar.db.metric.MetricDto;
53 import org.sonar.db.project.ProjectDto;
54 import org.sonar.db.property.PropertyDto;
55 import org.sonar.server.component.ws.SearchProjectsAction.RequestBuilder;
56 import org.sonar.server.component.ws.SearchProjectsAction.SearchProjectsRequest;
57 import org.sonar.server.es.EsTester;
58 import org.sonar.server.issue.index.IssueIndexSyncProgressChecker;
59 import org.sonar.server.measure.index.ProjectMeasuresIndex;
60 import org.sonar.server.measure.index.ProjectMeasuresIndexer;
61 import org.sonar.server.permission.index.PermissionIndexerTester;
62 import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
63 import org.sonar.server.qualitygate.ProjectsInWarning;
64 import org.sonar.server.tester.UserSessionRule;
65 import org.sonar.server.ws.TestRequest;
66 import org.sonar.server.ws.WsActionTester;
67 import org.sonarqube.ws.Common;
68 import org.sonarqube.ws.Components.Component;
69 import org.sonarqube.ws.Components.SearchProjectsWsResponse;
71 import static java.util.Arrays.asList;
72 import static java.util.Collections.singletonList;
73 import static java.util.Optional.ofNullable;
74 import static org.assertj.core.api.Assertions.assertThat;
75 import static org.assertj.core.api.Assertions.assertThatThrownBy;
76 import static org.assertj.core.api.Assertions.tuple;
77 import static org.mockito.Mockito.mock;
78 import static org.mockito.Mockito.when;
79 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
80 import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY_KEY;
81 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
82 import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY;
83 import static org.sonar.api.measures.CoreMetrics.NEW_LINES_KEY;
84 import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING_KEY;
85 import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
86 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
87 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
88 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
89 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
90 import static org.sonar.api.measures.Metric.ValueType.DATA;
91 import static org.sonar.api.measures.Metric.ValueType.INT;
92 import static org.sonar.api.measures.Metric.ValueType.LEVEL;
93 import static org.sonar.api.server.ws.WebService.Param.ASCENDING;
94 import static org.sonar.api.server.ws.WebService.Param.FACETS;
95 import static org.sonar.api.server.ws.WebService.Param.FIELDS;
96 import static org.sonar.api.server.ws.WebService.Param.PAGE;
97 import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
98 import static org.sonar.api.server.ws.WebService.Param.SORT;
99 import static org.sonar.api.utils.DateUtils.formatDateTime;
100 import static org.sonar.core.util.stream.MoreCollectors.toList;
101 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
102 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
103 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_003;
104 import static org.sonar.test.JsonAssert.assertJson;
105 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_FILTER;
106 import static org.sonarqube.ws.client.project.ProjectsWsParameters.FILTER_LANGUAGES;
107 import static org.sonarqube.ws.client.project.ProjectsWsParameters.FILTER_QUALIFIER;
108 import static org.sonarqube.ws.client.project.ProjectsWsParameters.FILTER_TAGS;
110 @RunWith(DataProviderRunner.class)
111 public class SearchProjectsActionTest {
113 private static final String NCLOC = "ncloc";
114 private static final String COVERAGE = "coverage";
115 private static final String NEW_COVERAGE = "new_coverage";
116 private static final String LEAK_PROJECTS_KEY = "leak_projects";
117 private static final String QUALITY_GATE_STATUS = "alert_status";
118 private static final String ANALYSIS_DATE = "analysisDate";
121 public final UserSessionRule userSession = UserSessionRule.standalone();
123 public final EsTester es = EsTester.create();
125 public final DbTester db = DbTester.create(System2.INSTANCE);
128 public static Object[][] rating_metric_keys() {
129 return new Object[][]{{SQALE_RATING_KEY}, {RELIABILITY_RATING_KEY}, {SECURITY_RATING_KEY}};
133 public static Object[][] new_rating_metric_keys() {
134 return new Object[][]{{NEW_MAINTAINABILITY_RATING_KEY}, {NEW_RELIABILITY_RATING_KEY}, {NEW_SECURITY_RATING_KEY}};
138 public static Object[][] component_qualifiers_for_valid_editions() {
139 return new Object[][]{
140 {new String[]{Qualifiers.PROJECT}, Edition.COMMUNITY},
141 {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.DEVELOPER},
142 {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.ENTERPRISE},
143 {new String[]{Qualifiers.APP, Qualifiers.PROJECT}, Edition.DATACENTER},
148 public static Object[][] community_or_developer_edition() {
149 return new Object[][]{
156 public static Object[][] enterprise_or_datacenter_edition() {
157 return new Object[][]{
158 {Edition.ENTERPRISE},
159 {Edition.DATACENTER},
163 private DbClient dbClient = db.getDbClient();
164 private DbSession dbSession = db.getSession();
166 private PlatformEditionProvider editionProviderMock = mock(PlatformEditionProvider.class);
167 private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, new ProjectMeasuresIndexer(dbClient, es.client()));
168 private ProjectMeasuresIndex index = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(userSession), System2.INSTANCE);
169 private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client());
170 private ProjectsInWarning projectsInWarning = new ProjectsInWarning();
172 private WsActionTester ws = new WsActionTester(new SearchProjectsAction(dbClient, index, userSession, projectsInWarning, editionProviderMock,
173 new IssueIndexSyncProgressChecker(db.getDbClient())));
175 private RequestBuilder request = SearchProjectsRequest.builder();
178 public void setUp() {
179 projectsInWarning.update(0L);
183 public void verify_definition() {
184 WebService.Action def = ws.getDef();
186 assertThat(def.key()).isEqualTo("search_projects");
187 assertThat(def.since()).isEqualTo("6.2");
188 assertThat(def.isInternal()).isTrue();
189 assertThat(def.isPost()).isFalse();
190 assertThat(def.responseExampleAsString()).isNotEmpty();
191 assertThat(def.params().stream().map(Param::key).collect(toList())).containsOnly("filter", "facets", "s", "asc", "ps", "p", "f");
192 assertThat(def.changelog()).hasSize(2);
194 Param sort = def.param("s");
195 assertThat(sort.defaultValue()).isEqualTo("name");
196 assertThat(sort.possibleValues()).containsExactlyInAnyOrder(
198 "reliability_rating",
199 "duplicated_lines_density",
200 "ncloc_language_distribution",
204 "security_review_rating",
205 "new_security_review_rating",
206 "security_hotspots_reviewed",
207 "new_security_hotspots_reviewed",
208 "new_reliability_rating",
210 "new_security_rating",
212 "new_duplicated_lines_density",
215 "new_maintainability_rating",
219 Param asc = def.param("asc");
220 assertThat(asc.defaultValue()).isEqualTo("true");
221 assertThat(asc.possibleValues()).containsOnly("true", "false", "yes", "no");
223 Param f = def.param("f");
224 assertThat(f.defaultValue()).isNull();
225 assertThat(f.possibleValues()).containsOnly("_all", "analysisDate", "leakPeriodDate");
227 Param facets = def.param("facets");
228 assertThat(facets.defaultValue()).isNull();
229 assertThat(facets.possibleValues()).containsOnly("ncloc", "duplicated_lines_density", "coverage", "sqale_rating", "reliability_rating", "security_rating", "alert_status",
230 "languages", "tags", "qualifier", "new_reliability_rating", "new_security_rating", "new_maintainability_rating", "new_coverage", "new_duplicated_lines_density", "new_lines",
231 "security_review_rating", "security_hotspots_reviewed", "new_security_hotspots_reviewed", "new_security_review_rating");
235 public void json_example() {
237 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType("PERCENT"));
238 ComponentDto project1 = insertProject(
239 c -> c.setKey(KEY_PROJECT_EXAMPLE_001).setName("My Project 1"),
240 p -> p.setTagsString("finance, java"),
241 new Measure(coverage, c -> c.setValue(80d)));
243 db.components().insertProjectBranch(db.components().getProjectDto(project1), branchDto -> branchDto.setNeedIssueSync(true));
245 ComponentDto project2 = insertProject(
246 c -> c.setKey(KEY_PROJECT_EXAMPLE_002).setName("My Project 2"),
247 new Measure(coverage, c -> c.setValue(90d)));
248 ComponentDto project3 = insertProject(
249 c -> c.setKey(KEY_PROJECT_EXAMPLE_003).setName("My Project 3"),
250 p -> p.setTagsString("sales, offshore, java"),
251 new Measure(coverage, c -> c.setValue(20d)));
252 addFavourite(project1);
255 String jsonResult = ws.newRequest()
256 .setParam(FACETS, COVERAGE)
257 .setParam(FIELDS, "_all")
258 .execute().getInput();
260 assertJson(jsonResult).ignoreFields("id").isSimilarTo(ws.getDef().responseExampleAsString());
261 assertJson(ws.getDef().responseExampleAsString()).ignoreFields("id").isSimilarTo(jsonResult);
263 SearchProjectsWsResponse protobufResult = ws.newRequest()
264 .setParam(FACETS, COVERAGE)
265 .executeProtobuf(SearchProjectsWsResponse.class);
267 assertThat(protobufResult.getComponentsList()).extracting(Component::getKey)
268 .containsExactly(project1.getKey(), project2.getKey(), project3.getKey());
272 public void order_by_name_case_insensitive() {
274 insertProject(c -> c.setName("Maven"));
275 insertProject(c -> c.setName("Apache"));
276 insertProject(c -> c.setName("guava"));
279 SearchProjectsWsResponse result = call(request);
281 assertThat(result.getComponentsList()).extracting(Component::getName)
282 .containsExactly("Apache", "guava", "Maven");
286 public void paginate_result() {
288 IntStream.rangeClosed(1, 9).forEach(i -> insertProject(c -> c.setName("PROJECT-" + i)));
291 SearchProjectsWsResponse result = call(request.setPage(2).setPageSize(3));
293 assertThat(result.getPaging().getPageIndex()).isEqualTo(2);
294 assertThat(result.getPaging().getPageSize()).isEqualTo(3);
295 assertThat(result.getPaging().getTotal()).isEqualTo(9);
296 assertThat(result.getComponentsCount()).isEqualTo(3);
297 assertThat(result.getComponentsList())
298 .extracting(Component::getName)
299 .containsExactly("PROJECT-4", "PROJECT-5", "PROJECT-6");
303 public void empty_result() {
306 SearchProjectsWsResponse result = call(request);
308 assertThat(result.getComponentsCount()).isZero();
309 Common.Paging paging = result.getPaging();
310 assertThat(paging.getPageIndex()).isOne();
311 assertThat(paging.getPageSize()).isEqualTo(100);
312 assertThat(paging.getTotal()).isZero();
316 public void filter_projects_with_query() {
318 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType(INT.name()));
319 MetricDto ncloc = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
320 ComponentDto project1 = insertProject(
321 new Measure(coverage, c -> c.setValue(81d)),
322 new Measure(ncloc, c -> c.setValue(10_000d)));
323 ComponentDto project2 = insertProject(
324 new Measure(coverage, c -> c.setValue(80d)),
325 new Measure(ncloc, c -> c.setValue(10_000d)));
326 ComponentDto project3 = insertProject(
327 new Measure(coverage, c -> c.setValue(80d)),
328 new Measure(ncloc, c -> c.setValue(10_001d)));
331 SearchProjectsWsResponse result = call(request.setFilter("coverage <= 80 and ncloc <= 10000"));
333 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactly(project2.getKey());
337 public void filter_projects_by_quality_gate() {
339 MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name()));
340 ComponentDto project1 = insertProject(new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
341 ComponentDto project2 = insertProject(new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
342 ComponentDto project3 = insertProject(new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
345 SearchProjectsWsResponse result = call(request.setFilter("alert_status = OK"));
347 assertThat(result.getComponentsList())
348 .extracting(Component::getKey)
349 .containsExactlyInAnyOrder(project1.getKey(), project2.getKey());
353 public void filter_projects_by_languages() {
355 MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
356 MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
357 ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
358 db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
359 ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=3;xoo=9")));
360 db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(12d));
361 ComponentDto project3 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("xoo=1")));
362 db.measures().insertLiveMeasure(project3, nclocMetric, m -> m.setValue(1d));
363 ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=1;java=5;xoo=13")));
364 db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(19d));
367 SearchProjectsWsResponse result = call(request.setFilter("languages IN (java, js, <null>)"));
369 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project2.getKey(), project4.getKey());
373 @UseDataProvider("rating_metric_keys")
374 public void filter_projects_by_rating(String metricKey) {
376 MetricDto ratingMetric = db.measures().insertMetric(c -> c.setKey(metricKey).setValueType(INT.name()));
377 ComponentDto project1 = insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
378 ComponentDto project2 = insertProject(new Measure(ratingMetric, c -> c.setValue(2d)));
379 ComponentDto project3 = insertProject(new Measure(ratingMetric, c -> c.setValue(3d)));
382 SearchProjectsWsResponse result = call(request.setFilter(metricKey + " = 2"));
384 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactly(project2.getKey());
388 @UseDataProvider("new_rating_metric_keys")
389 public void filter_projects_by_new_rating(String newMetricKey) {
391 MetricDto ratingMetric = db.measures().insertMetric(c -> c.setKey(newMetricKey).setValueType(INT.name()));
392 insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
393 ComponentDto project2 = insertProject(new Measure(ratingMetric, c -> c.setValue(2d)));
394 insertProject(new Measure(ratingMetric, c -> c.setValue(3d)));
397 SearchProjectsWsResponse result = call(request.setFilter(newMetricKey + " = 2"));
399 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactly(project2.getKey());
403 public void filter_projects_by_tags() {
405 ComponentDto project1 = insertProject(defaults(), p -> p.setTags(asList("finance", "platform")));
406 insertProject(defaults(), p -> p.setTags(singletonList("marketing")));
407 ComponentDto project3 = insertProject(defaults(), p -> p.setTags(singletonList("offshore")));
410 SearchProjectsWsResponse result = call(request.setFilter("tags in (finance, offshore)"));
412 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
416 public void filter_projects_by_coverage() {
418 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType("PERCENT"));
419 ComponentDto project1 = insertProject(new Measure(coverage, c -> c.setValue(80d)));
420 ComponentDto project2 = insertProject(new Measure(coverage, c -> c.setValue(85d)));
421 ComponentDto project3 = insertProject(new Measure(coverage, c -> c.setValue(10d)));
424 SearchProjectsWsResponse result = call(request.setFilter("coverage <= 80"));
426 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
430 public void filter_projects_by_new_coverage() {
432 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(NEW_COVERAGE).setValueType("PERCENT"));
433 ComponentDto project1 = insertProject(new Measure(coverage, c -> c.setValue(80d)));
434 ComponentDto project2 = insertProject(new Measure(coverage, c -> c.setValue(85d)));
435 ComponentDto project3 = insertProject(new Measure(coverage, c -> c.setValue(10d)));
438 SearchProjectsWsResponse result = call(request.setFilter("new_coverage <= 80"));
440 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
444 public void filter_projects_by_duplications() {
446 MetricDto duplications = db.measures().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
447 ComponentDto project1 = insertProject(new Measure(duplications, c -> c.setValue(80d)));
448 ComponentDto project2 = insertProject(new Measure(duplications, c -> c.setValue(85d)));
449 ComponentDto project3 = insertProject(new Measure(duplications, c -> c.setValue(10d)));
452 SearchProjectsWsResponse result = call(request.setFilter("duplicated_lines_density <= 80"));
454 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
458 public void filter_projects_by_no_duplication() {
460 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType("PERCENT"));
461 MetricDto duplications = db.measures().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
462 ComponentDto project1 = insertProject(new Measure(coverage, c -> c.setValue(10d)));
463 ComponentDto project2 = insertProject(new Measure(duplications, c -> c.setValue(0d)));
464 ComponentDto project3 = insertProject(new Measure(duplications, c -> c.setValue(79d)));
467 SearchProjectsWsResponse result = call(request.setFilter("duplicated_lines_density = NO_DATA"));
469 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey());
473 public void filter_projects_by_no_duplication_should_not_return_projects_with_duplication() {
475 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType("PERCENT"));
476 MetricDto duplications = db.measures().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
477 insertProject(new Measure(duplications, c -> c.setValue(10d)), new Measure(coverage, c -> c.setValue(50d)));
480 SearchProjectsWsResponse result = call(request.setFilter("duplicated_lines_density = NO_DATA"));
482 assertThat(result.getComponentsList()).extracting(Component::getKey).isEmpty();
486 public void filter_projects_by_new_duplications() {
488 MetricDto newDuplications = db.measures().insertMetric(c -> c.setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
489 ComponentDto project1 = insertProject(new Measure(newDuplications, c -> c.setValue(80d)));
490 ComponentDto project2 = insertProject(new Measure(newDuplications, c -> c.setValue(85d)));
491 ComponentDto project3 = insertProject(new Measure(newDuplications, c -> c.setValue(10d)));
494 SearchProjectsWsResponse result = call(request.setFilter("new_duplicated_lines_density <= 80"));
496 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
500 public void filter_projects_by_ncloc() {
502 MetricDto ncloc = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
503 ComponentDto project1 = insertProject(new Measure(ncloc, c -> c.setValue(80d)));
504 ComponentDto project2 = insertProject(new Measure(ncloc, c -> c.setValue(85d)));
505 ComponentDto project3 = insertProject(new Measure(ncloc, c -> c.setValue(10d)));
508 SearchProjectsWsResponse result = call(request.setFilter("ncloc <= 80"));
510 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
514 public void filter_projects_by_new_lines() {
516 MetricDto newLines = db.measures().insertMetric(c -> c.setKey(NEW_LINES_KEY).setValueType(INT.name()));
517 ComponentDto project1 = insertProject(new Measure(newLines, c -> c.setValue(80d)));
518 ComponentDto project2 = insertProject(new Measure(newLines, c -> c.setValue(85d)));
519 ComponentDto project3 = insertProject(new Measure(newLines, c -> c.setValue(10d)));
522 SearchProjectsWsResponse result = call(request.setFilter("new_lines <= 80"));
524 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(project1.getKey(), project3.getKey());
528 public void filter_projects_by_text_query() {
530 insertProject(c -> c.setKey("sonar-java").setName("Sonar Java"));
531 insertProject(c -> c.setKey("sonar-groovy").setName("Sonar Groovy"));
532 insertProject(c -> c.setKey("sonar-markdown").setName("Sonar Markdown"));
533 insertProject(c -> c.setKey("sonarqube").setName("Sonar Qube"));
536 assertThat(call(request.setFilter("query = \"Groovy\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Groovy");
537 assertThat(call(request.setFilter("query = \"oNar\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java", "Sonar Groovy", "Sonar Markdown",
539 assertThat(call(request.setFilter("query = \"sonar-java\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java");
543 public void filter_projects_on_favorites() {
545 ComponentDto javaProject = insertProject();
546 ComponentDto markDownProject = insertProject();
547 ComponentDto sonarQubeProject = insertProject();
548 Stream.of(javaProject, markDownProject).forEach(this::addFavourite);
551 SearchProjectsWsResponse result = call(request.setFilter("isFavorite"));
553 assertThat(result.getComponentsCount()).isEqualTo(2);
554 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactly(javaProject.getKey(), markDownProject.getKey());
558 public void does_not_fail_on_orphan_favorite() {
560 ComponentDto javaProject = insertProject();
561 ComponentDto markDownProject = insertProject();
562 ComponentDto sonarQubeProject = insertProject();
563 Stream.of(javaProject, markDownProject).forEach(this::addFavourite);
566 addFavourite(null, null, null, null);
568 SearchProjectsWsResponse result = call(request.setFilter("isFavorite"));
570 assertThat(result.getComponentsCount()).isEqualTo(2);
571 assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactly(javaProject.getKey(), markDownProject.getKey());
575 public void filtering_on_favorites_returns_empty_results_if_not_logged_in() {
576 userSession.anonymous();
577 ComponentDto javaProject = insertProject();
578 ComponentDto markDownProject = insertProject();
579 ComponentDto sonarQubeProject = insertProject();
580 Stream.of(javaProject, markDownProject).forEach(this::addFavourite);
583 SearchProjectsWsResponse result = call(request.setFilter("isFavorite"));
585 assertThat(result.getComponentsCount()).isZero();
589 @UseDataProvider("component_qualifiers_for_valid_editions")
590 public void default_filter_projects_and_apps_by_editions(String[] qualifiers, Edition edition) {
591 when(editionProviderMock.get()).thenReturn(Optional.of(edition));
593 ComponentDto portfolio1 = insertPortfolio();
594 ComponentDto portfolio2 = insertPortfolio();
596 ComponentDto application1 = insertApplication();
597 ComponentDto application2 = insertApplication();
598 ComponentDto application3 = insertApplication();
600 ComponentDto project1 = insertProject();
601 ComponentDto project2 = insertProject();
602 ComponentDto project3 = insertProject();
605 SearchProjectsWsResponse result = call(request);
607 assertThat(result.getComponentsCount()).isEqualTo(
608 Stream.of(application1, application2, application3, project1, project2, project3)
609 .filter(c -> Stream.of(qualifiers).anyMatch(s -> s.equals(c.qualifier())))
612 assertThat(result.getComponentsList()).extracting(Component::getKey)
614 Stream.of(application1, application2, application3, project1, project2, project3)
615 .filter(c -> Stream.of(qualifiers).anyMatch(s -> s.equals(c.qualifier())))
616 .map(ComponentDto::getKey)
617 .toArray(String[]::new));
621 public void should_return_projects_only_when_no_edition() {
622 when(editionProviderMock.get()).thenReturn(Optional.empty());
625 ComponentDto portfolio1 = insertPortfolio();
626 ComponentDto portfolio2 = insertPortfolio();
632 ComponentDto project1 = insertProject();
633 ComponentDto project2 = insertProject();
634 ComponentDto project3 = insertProject();
637 SearchProjectsWsResponse result = call(request);
639 assertThat(result.getComponentsCount()).isEqualTo(3);
641 assertThat(result.getComponentsList()).extracting(Component::getKey)
642 .containsExactly(Stream.of(project1, project2, project3).map(ComponentDto::getKey).toArray(String[]::new));
646 @UseDataProvider("enterprise_or_datacenter_edition")
647 public void filter_projects_and_apps_by_APP_qualifier_when_ee_dc(Edition edition) {
648 when(editionProviderMock.get()).thenReturn(Optional.of(edition));
650 ComponentDto application1 = insertApplication();
651 ComponentDto application2 = insertApplication();
652 ComponentDto application3 = insertApplication();
659 SearchProjectsWsResponse result = call(request.setFilter("qualifier = APP"));
661 assertThat(result.getComponentsCount())
664 assertThat(result.getComponentsList()).extracting(Component::getKey)
666 Stream.of(application1, application2, application3)
667 .map(ComponentDto::getKey)
668 .toArray(String[]::new));
672 @UseDataProvider("enterprise_or_datacenter_edition")
673 public void filter_projects_and_apps_by_TRK_qualifier_when_ee_or_dc(Edition edition) {
674 when(editionProviderMock.get()).thenReturn(Optional.of(edition));
681 ComponentDto project1 = insertProject();
682 ComponentDto project2 = insertProject();
683 ComponentDto project3 = insertProject();
686 SearchProjectsWsResponse result = call(request.setFilter("qualifier = TRK"));
688 assertThat(result.getComponentsCount())
691 assertThat(result.getComponentsList()).extracting(Component::getKey)
693 Stream.of(project1, project2, project3)
694 .map(ComponentDto::getKey)
695 .toArray(String[]::new));
699 @UseDataProvider("community_or_developer_edition")
700 public void fail_when_qualifier_filter_by_APP_set_when_ce_or_de(Edition edition) {
701 when(editionProviderMock.get()).thenReturn(Optional.of(edition));
704 assertThatThrownBy(() -> call(request.setFilter("qualifiers = APP")))
705 .isInstanceOf(IllegalArgumentException.class);
709 @UseDataProvider("enterprise_or_datacenter_edition")
710 public void fail_when_qualifier_filter_invalid_when_ee_or_dc(Edition edition) {
711 when(editionProviderMock.get()).thenReturn(Optional.of(edition));
714 assertThatThrownBy(() -> call(request.setFilter("qualifiers = BLA")))
715 .isInstanceOf(IllegalArgumentException.class);
719 public void do_not_return_isFavorite_if_anonymous_user() {
720 userSession.anonymous();
724 SearchProjectsWsResponse result = call(request);
726 assertThat(result.getComponentsList()).extracting(Component::hasIsFavorite).containsExactlyInAnyOrder(false);
730 public void return_nloc_facet() {
732 MetricDto ncloc = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
733 insertProject(new Measure(ncloc, c -> c.setValue(5d)));
734 insertProject(new Measure(ncloc, c -> c.setValue(5d)));
735 insertProject(new Measure(ncloc, c -> c.setValue(10_000d)));
736 insertProject(new Measure(ncloc, c -> c.setValue(500_001d)));
739 SearchProjectsWsResponse result = call(request.setFacets(singletonList(NCLOC)));
741 Common.Facet facet = result.getFacets().getFacetsList().stream()
742 .filter(oneFacet -> NCLOC.equals(oneFacet.getProperty()))
743 .findFirst().orElseThrow(IllegalStateException::new);
744 assertThat(facet.getValuesList())
745 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
747 tuple("*-1000.0", 2L),
748 tuple("1000.0-10000.0", 0L),
749 tuple("10000.0-100000.0", 1L),
750 tuple("100000.0-500000.0", 0L),
751 tuple("500000.0-*", 1L));
755 public void return_new_lines_facet() {
757 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(NEW_LINES_KEY).setValueType(INT.name()));
758 insertProject(new Measure(coverage, c -> c.setValue(100d)));
759 insertProject(new Measure(coverage, c -> c.setValue(15_000d)));
760 insertProject(new Measure(coverage, c -> c.setValue(50_000d)));
763 SearchProjectsWsResponse result = call(request.setFacets(singletonList(NEW_LINES_KEY)));
765 Common.Facet facet = result.getFacets().getFacetsList().stream()
766 .filter(oneFacet -> NEW_LINES_KEY.equals(oneFacet.getProperty()))
767 .findFirst().orElseThrow(IllegalStateException::new);
768 assertThat(facet.getValuesList())
769 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
771 tuple("*-1000.0", 1L),
772 tuple("1000.0-10000.0", 0L),
773 tuple("10000.0-100000.0", 2L),
774 tuple("100000.0-500000.0", 0L),
775 tuple("500000.0-*", 0L));
779 public void return_languages_facet() {
781 MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
782 MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
783 ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6;xoo=18")));
784 db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(26d));
785 ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=5;xoo=19")));
786 db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(24d));
787 ComponentDto project3 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("xoo=1")));
788 db.measures().insertLiveMeasure(project3, nclocMetric, m -> m.setValue(1d));
789 ComponentDto project4 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=1;java=3;xoo=8")));
790 db.measures().insertLiveMeasure(project4, nclocMetric, m -> m.setValue(12d));
793 SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_LANGUAGES)));
795 Common.Facet facet = result.getFacets().getFacetsList().stream()
796 .filter(oneFacet -> FILTER_LANGUAGES.equals(oneFacet.getProperty()))
797 .findFirst().orElseThrow(IllegalStateException::new);
798 assertThat(facet.getValuesList())
799 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
803 tuple("<null>", 2L));
807 public void return_languages_facet_with_language_having_no_project_if_language_is_in_filter() {
809 MetricDto languagesDistributionMetric = db.measures().insertMetric(c -> c.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY).setValueType("DATA"));
810 MetricDto nclocMetric = db.measures().insertMetric(c -> c.setKey(NCLOC).setValueType(INT.name()));
811 ComponentDto project1 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("<null>=2;java=6")));
812 db.measures().insertLiveMeasure(project1, nclocMetric, m -> m.setValue(8d));
813 ComponentDto project2 = insertProject(new Measure(languagesDistributionMetric, c -> c.setValue(null).setData("java=5")));
814 db.measures().insertLiveMeasure(project2, nclocMetric, m -> m.setValue(5d));
817 SearchProjectsWsResponse result = call(request.setFilter("languages = xoo").setFacets(singletonList(FILTER_LANGUAGES)));
819 Common.Facet facet = result.getFacets().getFacetsList().stream()
820 .filter(oneFacet -> FILTER_LANGUAGES.equals(oneFacet.getProperty()))
821 .findFirst().orElseThrow(IllegalStateException::new);
822 assertThat(facet.getValuesList())
823 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
827 tuple("<null>", 1L));
831 public void return_tags_facet() {
833 insertProject(defaults(), p -> p.setTags(asList("finance", "platform")));
834 insertProject(defaults(), p -> p.setTags(singletonList("offshore")));
835 insertProject(defaults(), p -> p.setTags(singletonList("offshore")));
838 SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_TAGS)));
840 Common.Facet facet = result.getFacets().getFacetsList().stream()
841 .filter(oneFacet -> FILTER_TAGS.equals(oneFacet.getProperty()))
842 .findFirst().orElseThrow(IllegalStateException::new);
843 assertThat(facet.getValuesList())
844 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
846 tuple("offshore", 2L),
847 tuple("finance", 1L),
848 tuple("platform", 1L));
852 public void return_tags_facet_with_tags_having_no_project_if_tags_is_in_filter() {
854 insertProject(defaults(), p -> p.setTags(asList("finance", "platform")));
855 insertProject(defaults(), p -> p.setTags(singletonList("offshore")));
856 insertProject(defaults(), p -> p.setTags(singletonList("offshore")));
859 SearchProjectsWsResponse result = call(request.setFilter("tags = marketing").setFacets(singletonList(FILTER_TAGS)));
861 Common.Facet facet = result.getFacets().getFacetsList().stream()
862 .filter(oneFacet -> FILTER_TAGS.equals(oneFacet.getProperty()))
863 .findFirst().orElseThrow(IllegalStateException::new);
864 assertThat(facet.getValuesList())
865 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
867 tuple("offshore", 2L),
868 tuple("finance", 1L),
869 tuple("platform", 1L),
870 tuple("marketing", 0L));
874 public void return_qualifiers_facet() {
875 when(editionProviderMock.get()).thenReturn(Optional.of(Edition.ENTERPRISE));
877 ComponentDto application1 = insertApplication();
878 ComponentDto application2 = insertApplication();
879 ComponentDto application3 = insertApplication();
880 ComponentDto application4 = insertApplication();
882 ComponentDto project1 = insertProject();
883 ComponentDto project2 = insertProject();
884 ComponentDto project3 = insertProject();
887 SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_QUALIFIER)));
889 Common.Facet facet = result.getFacets().getFacetsList().stream()
890 .filter(oneFacet -> FILTER_QUALIFIER.equals(oneFacet.getProperty()))
891 .findFirst().orElseThrow(IllegalStateException::new);
892 assertThat(facet.getValuesList())
893 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
900 public void return_qualifiers_facet_with_qualifiers_having_no_project_if_qualifiers_is_in_filter() {
901 when(editionProviderMock.get()).thenReturn(Optional.of(Edition.ENTERPRISE));
903 ComponentDto application1 = insertApplication();
904 ComponentDto application2 = insertApplication();
905 ComponentDto application3 = insertApplication();
906 ComponentDto application4 = insertApplication();
909 SearchProjectsWsResponse result = call(request.setFilter("qualifier = APP").setFacets(singletonList(FILTER_QUALIFIER)));
911 Common.Facet facet = result.getFacets().getFacetsList().stream()
912 .filter(oneFacet -> FILTER_QUALIFIER.equals(oneFacet.getProperty()))
913 .findFirst().orElseThrow(IllegalStateException::new);
914 assertThat(facet.getValuesList())
915 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
922 @UseDataProvider("rating_metric_keys")
923 public void return_rating_facet(String ratingMetricKey) {
925 MetricDto ratingMetric = db.measures().insertMetric(c -> c.setKey(ratingMetricKey).setValueType("RATING"));
926 insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
927 insertProject(new Measure(ratingMetric, c -> c.setValue(1d)));
928 insertProject(new Measure(ratingMetric, c -> c.setValue(3d)));
929 insertProject(new Measure(ratingMetric, c -> c.setValue(5d)));
932 SearchProjectsWsResponse result = call(request.setFacets(singletonList(ratingMetricKey)));
934 Common.Facet facet = result.getFacets().getFacetsList().stream()
935 .filter(oneFacet -> ratingMetricKey.equals(oneFacet.getProperty()))
936 .findFirst().orElseThrow(IllegalStateException::new);
937 assertThat(facet.getValuesList())
938 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
948 @UseDataProvider("new_rating_metric_keys")
949 public void return_new_rating_facet(String newRatingMetricKey) {
951 MetricDto newRatingMetric = db.measures().insertMetric(c -> c.setKey(newRatingMetricKey).setValueType("RATING"));
952 insertProject(new Measure(newRatingMetric, c -> c.setValue(1d)));
953 insertProject(new Measure(newRatingMetric, c -> c.setValue(1d)));
954 insertProject(new Measure(newRatingMetric, c -> c.setValue(3d)));
955 insertProject(new Measure(newRatingMetric, c -> c.setValue(5d)));
958 SearchProjectsWsResponse result = call(request.setFacets(singletonList(newRatingMetricKey)));
960 Common.Facet facet = result.getFacets().getFacetsList().stream()
961 .filter(oneFacet -> newRatingMetricKey.equals(oneFacet.getProperty()))
962 .findFirst().orElseThrow(IllegalStateException::new);
963 assertThat(facet.getValuesList())
964 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
974 public void return_coverage_facet() {
976 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType("PERCENT"));
978 insertProject(new Measure(coverage, c -> c.setValue(80d)));
979 insertProject(new Measure(coverage, c -> c.setValue(85d)));
980 insertProject(new Measure(coverage, c -> c.setValue(10d)));
983 SearchProjectsWsResponse result = call(request.setFacets(singletonList(COVERAGE)));
985 Common.Facet facet = result.getFacets().getFacetsList().stream()
986 .filter(oneFacet -> COVERAGE.equals(oneFacet.getProperty()))
987 .findFirst().orElseThrow(IllegalStateException::new);
988 assertThat(facet.getValuesList())
989 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
991 tuple("NO_DATA", 1L),
993 tuple("30.0-50.0", 0L),
994 tuple("50.0-70.0", 0L),
995 tuple("70.0-80.0", 0L),
996 tuple("80.0-*", 2L));
1000 public void return_new_coverage_facet() {
1001 userSession.logIn();
1002 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(NEW_COVERAGE).setValueType("PERCENT"));
1004 insertProject(new Measure(coverage, c -> c.setValue(80d)));
1005 insertProject(new Measure(coverage, c -> c.setValue(85d)));
1006 insertProject(new Measure(coverage, c -> c.setValue(10d)));
1009 SearchProjectsWsResponse result = call(request.setFacets(singletonList(NEW_COVERAGE)));
1011 Common.Facet facet = result.getFacets().getFacetsList().stream()
1012 .filter(oneFacet -> NEW_COVERAGE.equals(oneFacet.getProperty()))
1013 .findFirst().orElseThrow(IllegalStateException::new);
1014 assertThat(facet.getValuesList())
1015 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
1017 tuple("NO_DATA", 1L),
1018 tuple("*-30.0", 1L),
1019 tuple("30.0-50.0", 0L),
1020 tuple("50.0-70.0", 0L),
1021 tuple("70.0-80.0", 0L),
1022 tuple("80.0-*", 2L));
1026 public void return_duplications_facet() {
1027 userSession.logIn();
1028 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
1029 insertProject(new Measure(coverage, c -> c.setValue(10d)));
1030 insertProject(new Measure(coverage, c -> c.setValue(15d)));
1031 insertProject(new Measure(coverage, c -> c.setValue(5d)));
1035 SearchProjectsWsResponse result = call(request.setFacets(singletonList(DUPLICATED_LINES_DENSITY_KEY)));
1037 Common.Facet facet = result.getFacets().getFacetsList().stream()
1038 .filter(oneFacet -> DUPLICATED_LINES_DENSITY_KEY.equals(oneFacet.getProperty()))
1039 .findFirst().orElseThrow(IllegalStateException::new);
1040 assertThat(facet.getValuesList())
1041 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
1043 tuple("NO_DATA", 1L),
1045 tuple("3.0-5.0", 0L),
1046 tuple("5.0-10.0", 1L),
1047 tuple("10.0-20.0", 2L),
1048 tuple("20.0-*", 0L));
1052 public void return_new_duplications_facet() {
1053 userSession.logIn();
1054 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setValueType("PERCENT"));
1056 insertProject(new Measure(coverage, c -> c.setValue(10d)));
1057 insertProject(new Measure(coverage, c -> c.setValue(15d)));
1058 insertProject(new Measure(coverage, c -> c.setValue(5d)));
1061 SearchProjectsWsResponse result = call(request.setFacets(singletonList(NEW_DUPLICATED_LINES_DENSITY_KEY)));
1063 Common.Facet facet = result.getFacets().getFacetsList().stream()
1064 .filter(oneFacet -> NEW_DUPLICATED_LINES_DENSITY_KEY.equals(oneFacet.getProperty()))
1065 .findFirst().orElseThrow(IllegalStateException::new);
1066 assertThat(facet.getValuesList())
1067 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
1069 tuple("NO_DATA", 1L),
1071 tuple("3.0-5.0", 0L),
1072 tuple("5.0-10.0", 1L),
1073 tuple("10.0-20.0", 2L),
1074 tuple("20.0-*", 0L));
1078 public void return_quality_gate_facet() {
1079 userSession.logIn();
1080 MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(ALERT_STATUS_KEY).setValueType(LEVEL.name()));
1081 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.ERROR.name()).setValue(null)));
1082 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.ERROR.name()).setValue(null)));
1083 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.WARN.name()).setValue(null)));
1084 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.OK.name()).setValue(null)));
1085 projectsInWarning.update(1L);
1088 SearchProjectsWsResponse result = call(request.setFacets(singletonList(ALERT_STATUS_KEY)));
1090 Common.Facet facet = result.getFacets().getFacetsList().stream()
1091 .filter(oneFacet -> ALERT_STATUS_KEY.equals(oneFacet.getProperty()))
1092 .findFirst().orElseThrow(IllegalStateException::new);
1093 assertThat(facet.getValuesList())
1094 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
1102 public void return_quality_gate_facet_without_warning_when_no_projects_in_warning() {
1103 userSession.logIn();
1104 MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(ALERT_STATUS_KEY).setValueType(LEVEL.name()));
1105 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.ERROR.name()).setValue(null)));
1106 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.ERROR.name()).setValue(null)));
1107 insertProject(new Measure(qualityGateStatus, c -> c.setData(Metric.Level.OK.name()).setValue(null)));
1108 projectsInWarning.update(0L);
1111 SearchProjectsWsResponse result = call(request.setFacets(singletonList(ALERT_STATUS_KEY)));
1113 Common.Facet facet = result.getFacets().getFacetsList().stream()
1114 .filter(oneFacet -> ALERT_STATUS_KEY.equals(oneFacet.getProperty()))
1115 .findFirst().orElseThrow(IllegalStateException::new);
1116 assertThat(facet.getValuesList())
1117 .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
1120 tuple("ERROR", 2L));
1124 public void default_sort_is_by_ascending_name() {
1125 userSession.logIn();
1126 insertProject(c -> c.setName("Sonar Java"));
1127 insertProject(c -> c.setName("Sonar Groovy"));
1128 insertProject(c -> c.setName("Sonar Markdown"));
1129 insertProject(c -> c.setName("Sonar Qube"));
1132 SearchProjectsWsResponse result = call(request);
1134 assertThat(result.getComponentsList()).extracting(Component::getName).containsExactly("Sonar Groovy", "Sonar Java", "Sonar Markdown", "Sonar Qube");
1138 public void sort_by_name() {
1139 userSession.logIn();
1140 insertProject(c -> c.setName("Sonar Java"));
1141 insertProject(c -> c.setName("Sonar Groovy"));
1142 insertProject(c -> c.setName("Sonar Markdown"));
1143 insertProject(c -> c.setName("Sonar Qube"));
1146 assertThat(call(request.setSort("name").setAsc(true)).getComponentsList()).extracting(Component::getName)
1147 .containsExactly("Sonar Groovy", "Sonar Java", "Sonar Markdown", "Sonar Qube");
1148 assertThat(call(request.setSort("name").setAsc(false)).getComponentsList()).extracting(Component::getName)
1149 .containsExactly("Sonar Qube", "Sonar Markdown", "Sonar Java", "Sonar Groovy");
1153 public void sort_by_coverage_then_by_name() {
1154 userSession.logIn();
1155 MetricDto coverage = db.measures().insertMetric(c -> c.setKey(COVERAGE).setValueType(INT.name()));
1156 ComponentDto project1 = insertProject(c -> c.setName("Sonar Java"), new Measure(coverage, c -> c.setValue(81d)));
1157 ComponentDto project2 = insertProject(c -> c.setName("Sonar Groovy"), new Measure(coverage, c -> c.setValue(81d)));
1158 ComponentDto project3 = insertProject(c -> c.setName("Sonar Markdown"), new Measure(coverage, c -> c.setValue(80d)));
1159 ComponentDto project4 = insertProject(c -> c.setName("Sonar Qube"), new Measure(coverage, c -> c.setValue(80d)));
1162 assertThat(call(request.setSort(COVERAGE).setAsc(true)).getComponentsList()).extracting(Component::getKey)
1163 .containsExactly(project3.getKey(), project4.getKey(), project2.getKey(), project1.getKey());
1164 assertThat(call(request.setSort(COVERAGE).setAsc(false)).getComponentsList()).extracting(Component::getKey)
1165 .containsExactly(project2.getKey(), project1.getKey(), project3.getKey(), project4.getKey());
1169 public void sort_by_quality_gate_then_by_name() {
1170 userSession.logIn();
1171 MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name()));
1172 ComponentDto project1 = insertProject(c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
1173 ComponentDto project2 = insertProject(c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
1174 ComponentDto project3 = insertProject(c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
1175 ComponentDto project4 = insertProject(c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
1178 assertThat(call(request.setSort(QUALITY_GATE_STATUS).setAsc(true)).getComponentsList()).extracting(Component::getKey)
1179 .containsExactly(project3.getKey(), project4.getKey(), project2.getKey(), project1.getKey());
1180 assertThat(call(request.setSort(QUALITY_GATE_STATUS).setAsc(false)).getComponentsList()).extracting(Component::getKey)
1181 .containsExactly(project2.getKey(), project1.getKey(), project3.getKey(), project4.getKey());
1185 public void sort_by_last_analysis_date() {
1186 userSession.logIn();
1187 ComponentDto project1 = db.components().insertPublicProject(p -> p.setKey("project1"));
1188 authorizationIndexerTester.allowOnlyAnyone(project1);
1189 ComponentDto project2 = db.components().insertPublicProject(p -> p.setKey("project2"));
1190 db.components().insertSnapshot(project2, snapshot -> snapshot.setCreatedAt(40_000_000_000L).setLast(true));
1191 authorizationIndexerTester.allowOnlyAnyone(project2);
1192 ComponentDto project3 = db.components().insertPublicProject(p -> p.setKey("project3"));
1193 db.components().insertSnapshot(project3, snapshot -> snapshot.setCreatedAt(20_000_000_000L).setLast(true));
1194 authorizationIndexerTester.allowOnlyAnyone(project3);
1195 ComponentDto project4 = db.components().insertPublicProject(p -> p.setKey("project4"));
1196 db.components().insertSnapshot(project4, snapshot -> snapshot.setCreatedAt(10_000_000_000L).setLast(false));
1197 db.components().insertSnapshot(project4, snapshot -> snapshot.setCreatedAt(30_000_000_000L).setLast(true));
1198 authorizationIndexerTester.allowOnlyAnyone(project4);
1201 assertThat(call(request.setSort(ANALYSIS_DATE).setAsc(true)).getComponentsList()).extracting(Component::getKey)
1202 .containsExactly(project3.getKey(), project4.getKey(), project2.getKey(), project1.getKey());
1204 assertThat(call(request.setSort(ANALYSIS_DATE).setAsc(false)).getComponentsList()).extracting(Component::getKey)
1205 .containsExactly(project2.getKey(), project4.getKey(), project3.getKey(), project1.getKey());
1209 public void return_last_analysis_date() {
1210 userSession.logIn();
1211 ComponentDto project1 = db.components().insertPublicProject();
1212 db.components().insertSnapshot(project1, snapshot -> snapshot.setCreatedAt(10_000_000_000L).setLast(false));
1213 db.components().insertSnapshot(project1, snapshot -> snapshot.setCreatedAt(20_000_000_000L).setLast(true));
1214 authorizationIndexerTester.allowOnlyAnyone(project1);
1215 ComponentDto project2 = db.components().insertPublicProject();
1216 db.components().insertSnapshot(project2, snapshot -> snapshot.setCreatedAt(30_000_000_000L).setLast(true));
1217 authorizationIndexerTester.allowOnlyAnyone(project2);
1218 // No snapshot on project 3
1219 ComponentDto project3 = db.components().insertPublicProject();
1220 authorizationIndexerTester.allowOnlyAnyone(project3);
1223 SearchProjectsWsResponse result = call(request.setAdditionalFields(singletonList("analysisDate")));
1225 assertThat(result.getComponentsList()).extracting(Component::getKey, Component::hasAnalysisDate, Component::getAnalysisDate)
1227 tuple(project1.getKey(), true, formatDateTime(new Date(20_000_000_000L))),
1228 tuple(project2.getKey(), true, formatDateTime(new Date(30_000_000_000L))),
1229 tuple(project3.getKey(), false, ""));
1233 public void return_leak_period_date() {
1234 when(editionProviderMock.get()).thenReturn(Optional.of(Edition.ENTERPRISE));
1235 userSession.logIn();
1236 ComponentDto project1 = db.components().insertPublicProject();
1237 db.components().insertSnapshot(project1, snapshot -> snapshot.setPeriodDate(10_000_000_000L));
1238 authorizationIndexerTester.allowOnlyAnyone(project1);
1240 ComponentDto project2 = db.components().insertPublicProject();
1241 db.components().insertSnapshot(project2, snapshot -> snapshot.setPeriodDate(null));
1242 authorizationIndexerTester.allowOnlyAnyone(project2);
1243 // No snapshot on project 3
1244 ComponentDto project3 = db.components().insertPublicProject();
1245 authorizationIndexerTester.allowOnlyAnyone(project3);
1247 MetricDto leakProjects = db.measures().insertMetric(c -> c.setKey(LEAK_PROJECTS_KEY).setValueType(DATA.name()));
1248 ComponentDto application1 = insertApplication(
1249 new Measure(leakProjects, c -> c.setData("{\"leakProjects\":[{\"id\": 1, \"leak\":20000000000}, {\"id\": 2, \"leak\":10000000000}]}")));
1250 db.components().insertSnapshot(application1);
1252 authorizationIndexerTester.allowOnlyAnyone(application1);
1255 SearchProjectsWsResponse result = call(request.setAdditionalFields(singletonList("leakPeriodDate")));
1257 assertThat(result.getComponentsList()).extracting(Component::getKey, Component::hasLeakPeriodDate, Component::getLeakPeriodDate)
1259 tuple(project1.getKey(), true, formatDateTime(new Date(10_000_000_000L))),
1260 tuple(project2.getKey(), false, ""),
1261 tuple(project3.getKey(), false, ""),
1262 tuple(application1.getKey(), true, formatDateTime(new Date(10_000_000_000L))));
1266 public void return_visibility_flag() {
1267 userSession.logIn();
1268 ComponentDto privateProject = db.components().insertPublicProject();
1269 authorizationIndexerTester.allowOnlyAnyone(privateProject);
1270 ComponentDto publicProject = db.components().insertPrivateProject();
1271 authorizationIndexerTester.allowOnlyAnyone(publicProject);
1274 SearchProjectsWsResponse result = call(request);
1276 assertThat(result.getComponentsList()).extracting(Component::getKey, Component::getVisibility)
1278 tuple(privateProject.getKey(), privateProject.isPrivate() ? "private" : "public"),
1279 tuple(publicProject.getKey(), publicProject.isPrivate() ? "private" : "public"));
1283 public void does_not_return_branches() {
1284 ComponentDto project = db.components().insertPublicProject();
1285 authorizationIndexerTester.allowOnlyAnyone(project);
1286 ComponentDto branch = db.components().insertProjectBranch(project);
1289 SearchProjectsWsResponse result = call(request);
1291 assertThat(result.getComponentsList()).extracting(Component::getKey)
1292 .containsExactlyInAnyOrder(project.getKey());
1296 public void use_deprecated_warning_quality_gate_in_filter() {
1297 userSession.logIn();
1298 MetricDto qualityGateStatus = db.measures().insertMetric(c -> c.setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name()));
1299 ComponentDto project1 = insertProject(c -> c.setName("Sonar Java"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("ERROR")));
1300 ComponentDto project2 = insertProject(c -> c.setName("Sonar Groovy"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("WARN")));
1301 ComponentDto project3 = insertProject(c -> c.setName("Sonar Markdown"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("WARN")));
1302 ComponentDto project4 = insertProject(c -> c.setName("Sonar Qube"), new Measure(qualityGateStatus, c -> c.setValue(null).setData("OK")));
1305 List<Component> projects = call(request
1306 .setFilter("alert_status = WARN"))
1307 .getComponentsList();
1309 assertThat(projects)
1310 .extracting(Component::getKey)
1311 .containsExactly(project2.getKey(), project3.getKey());
1315 public void fail_when_filter_metrics_are_unknown() {
1316 userSession.logIn();
1318 request.setFilter("debt > 80");
1320 assertThatThrownBy(() -> call(request))
1321 .isInstanceOf(IllegalArgumentException.class)
1322 .hasMessage("Following metrics are not supported: 'debt'");
1326 public void fail_when_sort_metrics_are_unknown() {
1327 userSession.logIn();
1329 request.setSort("debt");
1331 assertThatThrownBy(() -> call(request))
1332 .isInstanceOf(IllegalArgumentException.class)
1333 .hasMessageContaining("Value of parameter 's' (debt) must be one of: [");
1337 public void fail_if_page_size_greater_than_500() {
1338 userSession.logIn();
1339 request.setPageSize(501);
1340 assertThatThrownBy(() -> call(request))
1341 .isInstanceOf(IllegalArgumentException.class);
1344 private SearchProjectsWsResponse call(RequestBuilder requestBuilder) {
1345 SearchProjectsRequest wsRequest = requestBuilder.build();
1346 TestRequest httpRequest = ws.newRequest();
1347 ofNullable(wsRequest.getFilter()).ifPresent(filter -> httpRequest.setParam(PARAM_FILTER, filter));
1348 ofNullable(wsRequest.getSort()).ifPresent(sort -> httpRequest.setParam(SORT, sort));
1349 ofNullable(wsRequest.getAsc()).ifPresent(asc -> httpRequest.setParam(ASCENDING, Boolean.toString(asc)));
1350 httpRequest.setParam(PAGE, String.valueOf(wsRequest.getPage()));
1351 httpRequest.setParam(PAGE_SIZE, String.valueOf(wsRequest.getPageSize()));
1352 httpRequest.setParam(FACETS, Joiner.on(",").join(wsRequest.getFacets()));
1353 httpRequest.setParam(FIELDS, Joiner.on(",").join(wsRequest.getAdditionalFields()));
1354 return httpRequest.executeProtobuf(SearchProjectsWsResponse.class);
1357 private void addFavourite(ComponentDto project) {
1358 addFavourite(project.uuid(), project.getKey(),
1359 project.name(), project.qualifier());
1362 private void addFavourite(@Nullable String componentUuid, @Nullable String componentKey,
1363 @Nullable String componentName, @Nullable String qualifier) {
1364 dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey("favourite")
1365 .setComponentUuid(componentUuid).setUserUuid(userSession.getUuid()), userSession.getLogin(), componentKey,
1366 componentName, qualifier);
1370 private ComponentDto insertProject(Measure... measures) {
1371 return insertProject(defaults(), defaults(), measures);
1374 private ComponentDto insertProject(Consumer<ComponentDto> componentConsumer, Measure... measures) {
1375 return insertProject(componentConsumer, defaults(), measures);
1378 private ComponentDto insertProject(Consumer<ComponentDto> componentConsumer, Consumer<ProjectDto> projectConsumer,
1379 Measure... measures) {
1380 ComponentDto project = db.components().insertPublicProject(componentConsumer, projectConsumer);
1381 Arrays.stream(measures).forEach(m -> db.measures().insertLiveMeasure(project, m.metric, m.consumer));
1385 private ComponentDto insertApplication(Measure... measures) {
1386 return insertApplication(defaults(), measures);
1389 private ComponentDto insertApplication(Consumer<ComponentDto> componentConsumer, Measure... measures) {
1390 ComponentDto application = db.components().insertPublicApplication(componentConsumer);
1391 Arrays.stream(measures).forEach(m -> db.measures().insertLiveMeasure(application, m.metric, m.consumer));
1395 private void index() {
1396 projectMeasuresIndexer.indexAll();
1397 Set<ComponentDto> roots = dbClient.componentDao().selectComponentsByQualifiers(db.getSession(),
1398 new HashSet<>(asList(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.APP)));
1399 authorizationIndexerTester.allowOnlyAnyone(roots.toArray(new ComponentDto[0]));
1402 private ComponentDto insertPortfolio() {
1403 return db.components().insertPublicPortfolio();
1406 private static class Measure {
1407 private final MetricDto metric;
1408 private final Consumer<LiveMeasureDto> consumer;
1410 public Measure(MetricDto metric, Consumer<LiveMeasureDto> consumer) {
1411 this.metric = metric;
1412 this.consumer = consumer;
1416 private static <T> Consumer<T> defaults() {