3 * Copyright (C) 2009-2023 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.measure.ws;
22 import com.google.common.base.Joiner;
23 import java.util.List;
24 import java.util.stream.IntStream;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.measures.CoreMetrics;
28 import org.sonar.api.measures.Metric;
29 import org.sonar.api.server.ws.WebService.Param;
30 import org.sonar.api.utils.System2;
31 import org.sonar.core.util.stream.MoreCollectors;
32 import org.sonar.db.DbClient;
33 import org.sonar.db.DbSession;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.BranchDto;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.db.component.ComponentTesting;
38 import org.sonar.db.component.ResourceTypesRule;
39 import org.sonar.db.component.SnapshotDto;
40 import org.sonar.db.measure.LiveMeasureDto;
41 import org.sonar.db.metric.MetricDto;
42 import org.sonar.db.metric.MetricTesting;
43 import org.sonar.server.component.ComponentFinder;
44 import org.sonar.server.exceptions.BadRequestException;
45 import org.sonar.server.exceptions.ForbiddenException;
46 import org.sonar.server.exceptions.NotFoundException;
47 import org.sonar.server.l18n.I18nRule;
48 import org.sonar.server.tester.UserSessionRule;
49 import org.sonar.server.ws.WsActionTester;
50 import org.sonarqube.ws.Common;
51 import org.sonarqube.ws.Measures.ComponentTreeWsResponse;
52 import org.sonarqube.ws.Measures.PeriodValue;
54 import static java.lang.Double.parseDouble;
55 import static java.lang.String.format;
56 import static java.util.Collections.singletonList;
57 import static org.assertj.core.api.Assertions.assertThat;
58 import static org.assertj.core.api.Assertions.assertThatThrownBy;
59 import static org.assertj.core.api.Assertions.tuple;
60 import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY;
61 import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
62 import static org.sonar.api.measures.Metric.ValueType.FLOAT;
63 import static org.sonar.api.measures.Metric.ValueType.INT;
64 import static org.sonar.api.measures.Metric.ValueType.RATING;
65 import static org.sonar.api.resources.Qualifiers.APP;
66 import static org.sonar.api.resources.Qualifiers.DIRECTORY;
67 import static org.sonar.api.resources.Qualifiers.FILE;
68 import static org.sonar.api.resources.Qualifiers.PROJECT;
69 import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
70 import static org.sonar.api.server.ws.WebService.Param.SORT;
71 import static org.sonar.api.utils.DateUtils.parseDateTime;
72 import static org.sonar.api.web.UserRole.USER;
73 import static org.sonar.db.component.BranchType.PULL_REQUEST;
74 import static org.sonar.db.component.ComponentDbTester.toProjectDto;
75 import static org.sonar.db.component.ComponentTesting.newDirectory;
76 import static org.sonar.db.component.ComponentTesting.newFileDto;
77 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
78 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
79 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIOD;
80 import static org.sonar.server.component.ws.MeasuresWsParameters.DEPRECATED_ADDITIONAL_PERIODS;
81 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
82 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH;
83 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_COMPONENT;
84 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KEYS;
85 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_PERIOD_SORT;
86 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT;
87 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT_FILTER;
88 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST;
89 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_QUALIFIERS;
90 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_STRATEGY;
91 import static org.sonar.server.measure.ws.ComponentTreeAction.LEAVES_STRATEGY;
92 import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_PERIOD_SORT;
93 import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_SORT;
94 import static org.sonar.server.measure.ws.ComponentTreeAction.NAME_SORT;
95 import static org.sonar.server.measure.ws.ComponentTreeAction.WITH_MEASURES_ONLY_METRIC_SORT_FILTER;
96 import static org.sonar.test.JsonAssert.assertJson;
97 import static org.sonarqube.ws.Measures.Component;
98 import static org.sonarqube.ws.Measures.Measure;
100 public class ComponentTreeActionTest {
102 public UserSessionRule userSession = UserSessionRule.standalone().logIn();
104 public DbTester db = DbTester.create(System2.INSTANCE);
106 private final I18nRule i18n = new I18nRule();
107 private final ResourceTypesRule resourceTypes = new ResourceTypesRule()
108 .setRootQualifiers(PROJECT)
109 .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
110 private final DbClient dbClient = db.getDbClient();
111 private final DbSession dbSession = db.getSession();
113 private final WsActionTester ws = new WsActionTester(
114 new ComponentTreeAction(
115 dbClient, new ComponentFinder(dbClient, resourceTypes), userSession,
116 i18n, resourceTypes));
119 public void json_example() {
120 ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("MY_PROJECT")
121 .setName("My Project"));
122 userSession.addProjectPermission(USER, project);
123 SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
124 .setPeriodMode("previous_version")
125 .setPeriodParam("1.0-SNAPSHOT"));
126 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null)
127 .setUuid("AVIwDXE-bJbJqrw6wFv5")
128 .setKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl/ElementImpl.java")
129 .setName("ElementImpl.java")
132 .setPath("src/main/java/com/sonarsource/markdown/impl/ElementImpl.java"));
133 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null)
134 .setUuid("AVIwDXE_bJbJqrw6wFwJ")
135 .setKey("com.sonarsource:java-markdown:src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java")
136 .setName("ElementImplTest.java")
138 .setQualifier(UNIT_TEST_FILE)
139 .setPath("src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java"));
140 ComponentDto dir = db.components().insertComponent(newDirectory(project, "src/main/java/com/sonarsource/markdown/impl")
141 .setUuid("AVIwDXE-bJbJqrw6wFv8")
142 .setKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl")
143 .setQualifier(DIRECTORY));
145 MetricDto complexity = insertComplexityMetric();
146 db.measures().insertLiveMeasure(file1, complexity, m -> m.setValue(12.0d));
147 db.measures().insertLiveMeasure(dir, complexity, m -> m.setValue(35.0d));
148 db.measures().insertLiveMeasure(project, complexity, m -> m.setValue(42.0d));
150 MetricDto ncloc = insertNclocMetric();
151 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(114.0d));
152 db.measures().insertLiveMeasure(dir, ncloc, m -> m.setValue(217.0d));
153 db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(1984.0d));
155 MetricDto newViolations = insertNewViolationsMetric();
156 db.measures().insertLiveMeasure(file1, newViolations, m -> m.setValue(25.0d));
157 db.measures().insertLiveMeasure(dir, newViolations, m -> m.setValue(25.0d));
158 db.measures().insertLiveMeasure(project, newViolations, m -> m.setValue(255.0d));
162 String response = ws.newRequest()
163 .setParam(PARAM_COMPONENT, project.getKey())
164 .setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations")
165 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics,period,periods")
169 assertJson(response).isSimilarTo(getClass().getResource("component_tree-example.json"));
173 public void empty_response() {
174 ComponentDto project = db.components().insertPrivateProject();
175 userSession.addProjectPermission(USER, project);
177 ComponentTreeWsResponse response = ws.newRequest()
178 .setParam(PARAM_COMPONENT, project.getKey())
179 .setParam(PARAM_METRIC_KEYS, "ncloc, complexity")
180 .executeProtobuf(ComponentTreeWsResponse.class);
182 assertThat(response.getBaseComponent().getKey()).isEqualTo(project.getKey());
183 assertThat(response.getComponentsList()).isEmpty();
184 assertThat(response.getMetrics().getMetricsList()).isEmpty();
185 assertThat(response.hasPeriod()).isFalse();
186 assertThat(response.getPeriods().getPeriodsList()).isEmpty();
190 public void load_measures_and_periods() {
191 ComponentDto project = db.components().insertPrivateProject();
192 SnapshotDto projectSnapshot = dbClient.snapshotDao().insert(dbSession,
194 .setPeriodDate(System.currentTimeMillis())
195 .setPeriodMode("last_version")
196 .setPeriodDate(System.currentTimeMillis()));
197 userSession.anonymous().addProjectPermission(USER, project);
198 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
199 db.components().insertComponent(directory);
200 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
201 db.components().insertComponent(file);
202 MetricDto ncloc = insertNclocMetric();
203 MetricDto coverage = insertCoverageMetric();
205 db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(5.0d));
206 db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d));
207 db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(15.5d));
209 ComponentTreeWsResponse response = ws.newRequest()
210 .setParam(PARAM_COMPONENT, project.getKey())
211 .setParam(PARAM_METRIC_KEYS, "ncloc,coverage")
212 .setParam(PARAM_ADDITIONAL_FIELDS, DEPRECATED_ADDITIONAL_PERIODS + "," + ADDITIONAL_PERIOD)
213 .executeProtobuf(ComponentTreeWsResponse.class);
215 assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
217 List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
218 assertThat(fileMeasures).extracting("metric").containsOnly("ncloc", "coverage");
219 assertThat(fileMeasures).extracting("value").containsOnly("5", "15.5");
220 assertThat(response.getPeriod().getMode()).isEqualTo("last_version");
221 assertThat(response.getPeriods().getPeriodsList()).extracting("mode").containsOnly("last_version");
225 public void load_measures_with_best_value() {
226 ComponentDto project = db.components().insertPrivateProject();
227 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
228 userSession.anonymous().addProjectPermission(USER, project);
229 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
230 db.components().insertComponent(directory);
231 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
232 db.components().insertComponent(file);
233 MetricDto coverage = insertCoverageMetric();
234 dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
236 .setValueType(INT.name())
237 .setOptimizedBestValue(true)
239 .setWorstValue(1000d));
240 dbClient.metricDao().insert(dbSession, newMetricDto()
241 .setKey("new_violations")
242 .setOptimizedBestValue(true)
243 .setBestValue(1984.0d)
244 .setValueType(INT.name()));
246 db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d));
247 db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(42.0d));
249 ComponentTreeWsResponse response = ws.newRequest()
250 .setParam(PARAM_COMPONENT, project.getKey())
251 .setParam(PARAM_METRIC_KEYS, "ncloc,coverage,new_violations")
252 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
253 .executeProtobuf(ComponentTreeWsResponse.class);
255 // directory measures
256 assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
258 List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
259 assertThat(fileMeasures)
260 .extracting(Measure::getMetric, Measure::getValue, Measure::getBestValue, Measure::hasBestValue)
261 .containsExactlyInAnyOrder(tuple("ncloc", "100", true, true),
262 tuple("coverage", "15.5", false, false),
263 tuple("new_violations", "", false, false));
265 List<Common.Metric> metrics = response.getMetrics().getMetricsList();
266 assertThat(metrics).extracting("bestValue").contains("100", "");
267 assertThat(metrics).extracting("worstValue").contains("1000");
271 public void return_is_best_value_on_leak_measures() {
272 ComponentDto project = db.components().insertPrivateProject();
273 db.components().insertSnapshot(project);
274 userSession.anonymous().addProjectPermission(USER, project);
275 ComponentDto file = newFileDto(project, null);
276 db.components().insertComponent(file);
278 MetricDto matchingBestValue = db.measures().insertMetric(m -> m
280 .setValueType(INT.name())
281 .setBestValue(100d));
282 MetricDto doesNotMatchBestValue = db.measures().insertMetric(m -> m
283 .setKey("new_lines_2")
284 .setValueType(INT.name())
285 .setBestValue(100d));
286 MetricDto noBestValue = db.measures().insertMetric(m -> m
287 .setKey("new_violations")
288 .setValueType(INT.name())
289 .setBestValue(null));
290 db.measures().insertLiveMeasure(file, matchingBestValue, m -> m.setData((String) null).setValue(100d));
291 db.measures().insertLiveMeasure(file, doesNotMatchBestValue, m -> m.setData((String) null).setValue(10d));
292 db.measures().insertLiveMeasure(file, noBestValue, m -> m.setData((String) null).setValue(42.0d));
294 ComponentTreeWsResponse response = ws.newRequest()
295 .setParam(PARAM_COMPONENT, project.getKey())
296 .setParam(PARAM_METRIC_KEYS, "new_lines,new_lines_2,new_violations")
297 .executeProtobuf(ComponentTreeWsResponse.class);
301 // verify backward compatibility
302 List<Measure> fileMeasures = response.getComponentsList().get(0).getMeasuresList();
303 assertThat(fileMeasures)
304 .extracting(Measure::getMetric, m -> m.getPeriods().getPeriodsValueList())
305 .containsExactlyInAnyOrder(
306 tuple(matchingBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("100").setBestValue(true).build())),
307 tuple(doesNotMatchBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("10").setBestValue(false).build())),
308 tuple(noBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("42").build())));
310 assertThat(fileMeasures)
311 .extracting(Measure::getMetric, Measure::getPeriod)
312 .containsExactlyInAnyOrder(
313 tuple(matchingBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("100").setBestValue(true).build()),
314 tuple(doesNotMatchBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("10").setBestValue(false).build()),
315 tuple(noBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("42").build()));
319 public void use_best_value_for_rating() {
320 ComponentDto project = db.components().insertPrivateProject();
321 userSession.anonymous().addProjectPermission(USER, project);
322 SnapshotDto projectSnapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
323 .setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
324 .setPeriodMode("previous_version")
325 .setPeriodParam("1.0-SNAPSHOT"));
326 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
327 db.components().insertComponent(directory);
328 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
329 db.components().insertComponent(file);
330 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
331 .setKey(NEW_SECURITY_RATING_KEY)
332 .setOptimizedBestValue(true)
334 .setValueType(RATING.name()));
336 db.measures().insertLiveMeasure(directory, metric, m -> m.setValue(2d));
338 ComponentTreeWsResponse response = ws.newRequest()
339 .setParam(PARAM_COMPONENT, project.getKey())
340 .setParam(PARAM_METRIC_KEYS, NEW_SECURITY_RATING_KEY)
341 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
342 .executeProtobuf(ComponentTreeWsResponse.class);
345 assertThat(response.getComponentsList().get(0).getMeasuresList().get(0).getPeriods().getPeriodsValue(0).getValue()).isEqualTo("2.0");
346 assertThat(response.getComponentsList().get(0).getMeasuresList().get(0).getPeriod().getValue()).isEqualTo("2.0");
348 assertThat(response.getComponentsList().get(1).getMeasuresList().get(0).getPeriods().getPeriodsValue(0).getValue()).isEqualTo("1.0");
349 assertThat(response.getComponentsList().get(1).getMeasuresList().get(0).getPeriod().getValue()).isEqualTo("1.0");
353 public void load_measures_multi_sort_with_metric_key_and_paginated() {
354 ComponentDto project = db.components().insertPrivateProject();
355 userSession.addProjectPermission(USER, project);
356 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
357 ComponentDto file9 = db.components().insertComponent(newFileDto(project, null, "file-uuid-9").setName("file-1").setKey("file-9-key"));
358 ComponentDto file8 = db.components().insertComponent(newFileDto(project, null, "file-uuid-8").setName("file-1").setKey("file-8-key"));
359 ComponentDto file7 = db.components().insertComponent(newFileDto(project, null, "file-uuid-7").setName("file-1").setKey("file-7-key"));
360 ComponentDto file6 = db.components().insertComponent(newFileDto(project, null, "file-uuid-6").setName("file-1").setKey("file-6-key"));
361 ComponentDto file5 = db.components().insertComponent(newFileDto(project, null, "file-uuid-5").setName("file-1").setKey("file-5-key"));
362 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4").setName("file-1").setKey("file-4-key"));
363 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setName("file-1").setKey("file-3-key"));
364 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-1").setKey("file-2-key"));
365 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-1").setKey("file-1-key"));
366 MetricDto coverage = insertCoverageMetric();
368 db.measures().insertLiveMeasure(file1, coverage, m -> m.setValue(1.0d));
369 db.measures().insertLiveMeasure(file2, coverage, m -> m.setValue(2.0d));
370 db.measures().insertLiveMeasure(file3, coverage, m -> m.setValue(3.0d));
371 db.measures().insertLiveMeasure(file4, coverage, m -> m.setValue(4.0d));
372 db.measures().insertLiveMeasure(file5, coverage, m -> m.setValue(5.0d));
373 db.measures().insertLiveMeasure(file6, coverage, m -> m.setValue(6.0d));
374 db.measures().insertLiveMeasure(file7, coverage, m -> m.setValue(7.0d));
375 db.measures().insertLiveMeasure(file8, coverage, m -> m.setValue(8.0d));
376 db.measures().insertLiveMeasure(file9, coverage, m -> m.setValue(9.0d));
378 ComponentTreeWsResponse response = ws.newRequest()
379 .setParam(PARAM_COMPONENT, project.getKey())
380 .setParam(SORT, NAME_SORT + ", " + METRIC_SORT)
381 .setParam(PARAM_METRIC_SORT, "coverage")
382 .setParam(PARAM_METRIC_KEYS, "coverage")
383 .setParam(PARAM_STRATEGY, "leaves")
384 .setParam(PARAM_QUALIFIERS, "FIL,UTS")
385 .setParam(Param.PAGE, "2")
386 .setParam(Param.PAGE_SIZE, "3")
387 .executeProtobuf(ComponentTreeWsResponse.class);
389 assertThat(response.getComponentsList()).extracting("key").containsExactly("file-4-key", "file-5-key", "file-6-key");
390 assertThat(response.getPaging().getPageIndex()).isEqualTo(2);
391 assertThat(response.getPaging().getPageSize()).isEqualTo(3);
392 assertThat(response.getPaging().getTotal()).isEqualTo(9);
396 public void sort_by_metric_value() {
397 ComponentDto project = db.components().insertPrivateProject();
398 userSession.addProjectPermission(USER, project);
399 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
400 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4").setKey("file-4-key"));
401 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setKey("file-3-key"));
402 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setKey("file-1-key"));
403 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setKey("file-2-key"));
404 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
405 dbClient.metricDao().insert(dbSession, ncloc);
407 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(1.0d));
408 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setValue(2.0d));
409 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setValue(3.0d));
411 ComponentTreeWsResponse response = ws.newRequest()
412 .setParam(PARAM_COMPONENT, project.getKey())
413 .setParam(SORT, METRIC_SORT)
414 .setParam(PARAM_METRIC_SORT, "ncloc")
415 .setParam(PARAM_METRIC_KEYS, "ncloc")
416 .executeProtobuf(ComponentTreeWsResponse.class);
418 assertThat(response.getComponentsList()).extracting("key").containsExactly("file-1-key", "file-2-key", "file-3-key", "file-4-key");
419 assertThat(response.getPaging().getTotal()).isEqualTo(4);
423 public void remove_components_without_measure_on_the_metric_sort() {
424 ComponentDto project = db.components().insertPrivateProject();
425 userSession.addProjectPermission(USER, project);
426 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
427 ComponentDto file1 = newFileDto(project, null, "file-uuid-1").setKey("file-1-key");
428 ComponentDto file2 = newFileDto(project, null, "file-uuid-2").setKey("file-2-key");
429 ComponentDto file3 = newFileDto(project, null, "file-uuid-3").setKey("file-3-key");
430 ComponentDto file4 = newFileDto(project, null, "file-uuid-4").setKey("file-4-key");
431 db.components().insertComponent(file1);
432 db.components().insertComponent(file2);
433 db.components().insertComponent(file3);
434 db.components().insertComponent(file4);
435 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
436 dbClient.metricDao().insert(dbSession, ncloc);
437 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(1.0d));
438 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(2.0d));
439 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(3.0d));
442 ComponentTreeWsResponse response = ws.newRequest()
443 .setParam(PARAM_COMPONENT, project.getKey())
444 .setParam(SORT, METRIC_SORT)
445 .setParam(PARAM_METRIC_SORT, "ncloc")
446 .setParam(PARAM_METRIC_KEYS, "ncloc")
447 .setParam(PARAM_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER)
448 .executeProtobuf(ComponentTreeWsResponse.class);
450 assertThat(response.getComponentsList()).extracting("key")
451 .containsExactly(file1.getKey(), file2.getKey(), file3.getKey())
452 .doesNotContain(file4.getKey());
453 assertThat(response.getPaging().getTotal()).isEqualTo(3);
457 public void sort_by_metric_period() {
458 ComponentDto project = db.components().insertPrivateProject();
459 userSession.addProjectPermission(USER, project);
460 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
461 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setKey("file-3-key"));
462 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setKey("file-1-key"));
463 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setKey("file-2-key"));
464 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
465 dbClient.metricDao().insert(dbSession, ncloc);
467 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(1.0d));
468 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setValue(2.0d));
469 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setValue(3.0d));
471 ComponentTreeWsResponse response = ws.newRequest()
472 .setParam(PARAM_COMPONENT, project.getKey())
473 .setParam(SORT, METRIC_PERIOD_SORT)
474 .setParam(PARAM_METRIC_SORT, "ncloc")
475 .setParam(PARAM_METRIC_KEYS, "ncloc")
476 .setParam(PARAM_METRIC_PERIOD_SORT, "1")
477 .executeProtobuf(ComponentTreeWsResponse.class);
479 assertThat(response.getComponentsList()).extracting("key").containsExactly("file-1-key", "file-2-key", "file-3-key");
483 public void remove_components_without_measure_on_the_metric_period_sort() {
484 ComponentDto project = db.components().insertPrivateProject();
485 userSession.addProjectPermission(USER, project);
486 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
487 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4").setKey("file-4-key"));
488 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setKey("file-3-key"));
489 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setKey("file-2-key"));
490 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setKey("file-1-key"));
491 MetricDto ncloc = newMetricDto().setKey("new_ncloc").setValueType(INT.name()).setDirection(1);
492 dbClient.metricDao().insert(dbSession, ncloc);
493 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(1.0d));
494 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(2.0d));
495 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(3.0d));
498 ComponentTreeWsResponse response = ws.newRequest()
499 .setParam(PARAM_COMPONENT, project.getKey())
500 .setParam(SORT, METRIC_PERIOD_SORT + "," + NAME_SORT)
501 .setParam(PARAM_METRIC_SORT, "new_ncloc")
502 .setParam(PARAM_METRIC_KEYS, "new_ncloc")
503 .setParam(PARAM_METRIC_PERIOD_SORT, "1")
504 .setParam(PARAM_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER)
505 .executeProtobuf(ComponentTreeWsResponse.class);
507 assertThat(response.getComponentsList()).extracting("key")
508 .containsExactly("file-1-key", "file-2-key", "file-3-key")
509 .doesNotContain("file-4-key");
513 public void load_measures_when_no_leave_qualifier() {
514 resourceTypes.setLeavesQualifiers();
515 ComponentDto project = db.components().insertPrivateProject();
516 userSession.addProjectPermission(USER, project);
517 db.components().insertSnapshot(project);
518 db.components().insertComponent(newFileDto(project, null));
521 ComponentTreeWsResponse result = ws.newRequest()
522 .setParam(PARAM_COMPONENT, project.getKey())
523 .setParam(PARAM_STRATEGY, LEAVES_STRATEGY)
524 .setParam(PARAM_METRIC_KEYS, "ncloc")
525 .executeProtobuf(ComponentTreeWsResponse.class);
527 assertThat(result.getBaseComponent().getKey()).isEqualTo(project.getKey());
528 assertThat(result.getComponentsCount()).isZero();
532 public void branch() {
533 ComponentDto project = db.components().insertPrivateProject();
534 userSession.addProjectPermission(USER, project);
535 String branchName = "my-branch";
536 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey(branchName));
537 db.components().insertSnapshot(branch);
538 ComponentDto file = db.components().insertComponent(newFileDto(branch));
539 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
540 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d));
542 ComponentTreeWsResponse response = ws.newRequest()
543 .setParam(PARAM_COMPONENT, file.getKey())
544 .setParam(PARAM_BRANCH, branchName)
545 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
546 .executeProtobuf(ComponentTreeWsResponse.class);
548 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
549 .containsExactlyInAnyOrder(file.getKey(), branchName);
550 assertThat(response.getBaseComponent().getMeasuresList())
551 .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
552 .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
556 public void dont_show_branch_if_main_branch() {
557 ComponentDto project = db.components().insertPrivateProject();
558 userSession.addProjectPermission(USER, project);
559 ComponentDto file = db.components().insertComponent(newFileDto(project));
560 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
562 ComponentTreeWsResponse response = ws.newRequest()
563 .setParam(PARAM_COMPONENT, file.getKey())
564 .setParam(PARAM_BRANCH, BranchDto.DEFAULT_MAIN_BRANCH_NAME)
565 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
566 .executeProtobuf(ComponentTreeWsResponse.class);
568 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
569 .containsExactlyInAnyOrder(file.getKey(), "");
573 public void show_branch_on_empty_response_if_not_main_branch() {
574 ComponentDto mainProjectBranch = db.components().insertPrivateProject();
575 ComponentDto project = db.components().insertProjectBranch(mainProjectBranch, b -> b.setKey("develop"));
576 userSession.addProjectPermission(USER, mainProjectBranch);
577 ComponentDto file = db.components().insertComponent(newFileDto(project));
578 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
580 ComponentTreeWsResponse response = ws.newRequest()
581 .setParam(PARAM_COMPONENT, file.getKey())
582 .setParam(PARAM_BRANCH, "develop")
583 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
584 .executeProtobuf(ComponentTreeWsResponse.class);
586 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
587 .containsExactlyInAnyOrder(file.getKey(), "develop");
591 public void pull_request() {
592 ComponentDto project = db.components().insertPrivateProject();
593 userSession.addProjectPermission(USER, project);
594 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
595 SnapshotDto analysis = db.components().insertSnapshot(branch);
596 ComponentDto file = db.components().insertComponent(newFileDto(branch));
597 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
598 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d));
600 ComponentTreeWsResponse response = ws.newRequest()
601 .setParam(PARAM_COMPONENT, file.getKey())
602 .setParam(PARAM_PULL_REQUEST, "pr-123")
603 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
604 .executeProtobuf(ComponentTreeWsResponse.class);
606 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
607 .containsExactlyInAnyOrder(file.getKey(), "pr-123");
608 assertThat(response.getBaseComponent().getMeasuresList())
609 .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
610 .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
614 public void fix_pull_request_new_issue_count_metrics() {
615 ComponentDto project = db.components().insertPrivateProject();
616 userSession.addProjectPermission(USER, project);
617 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
618 SnapshotDto analysis = db.components().insertSnapshot(branch);
619 ComponentDto file = db.components().insertComponent(newFileDto(branch));
620 MetricDto bug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.BUGS_KEY));
621 MetricDto newBug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.NEW_BUGS_KEY));
623 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, bug, m -> m.setValue(12.0d));
625 ComponentTreeWsResponse response = ws.newRequest()
626 .setParam(PARAM_COMPONENT, file.getKey())
627 .setParam(PARAM_PULL_REQUEST, "pr-123")
628 .setParam(PARAM_METRIC_KEYS, newBug.getKey())
629 .executeProtobuf(ComponentTreeWsResponse.class);
631 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
632 .containsExactlyInAnyOrder(file.getKey(), "pr-123");
633 assertThat(response.getBaseComponent().getMeasuresList())
634 .extracting(Measure::getMetric, m -> parseDouble(m.getPeriods().getPeriodsValue(0).getValue()), Measure::getValue)
635 .containsExactlyInAnyOrder(tuple(newBug.getKey(), measure.getValue(), ""));
637 assertThat(response.getBaseComponent().getMeasuresList())
638 .extracting(Measure::getMetric, m -> parseDouble(m.getPeriod().getValue()), Measure::getValue)
639 .containsExactlyInAnyOrder(tuple(newBug.getKey(), measure.getValue(), ""));
643 public void new_issue_count_measures_are_not_transformed_if_they_dont_exist_in_pr() {
644 ComponentDto project = db.components().insertPrivateProject();
645 userSession.addProjectPermission(USER, project);
646 ComponentDto pr = db.components().insertProjectBranch(project, b -> b.setKey("pr").setBranchType(PULL_REQUEST));
647 SnapshotDto analysis = db.components().insertSnapshot(pr);
648 ComponentDto file = db.components().insertComponent(newFileDto(pr));
649 MetricDto bug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.BUGS_KEY));
650 MetricDto newBug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.NEW_BUGS_KEY));
652 ComponentTreeWsResponse response = ws.newRequest()
653 .setParam(PARAM_COMPONENT, file.getKey())
654 .setParam(PARAM_PULL_REQUEST, "pr")
655 .setParam(PARAM_METRIC_KEYS, newBug.getKey() + "," + bug.getKey())
656 .executeProtobuf(ComponentTreeWsResponse.class);
658 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
659 .containsExactlyInAnyOrder(file.getKey(), "pr");
660 assertThat(response.getBaseComponent().getMeasuresList())
665 public void metric_without_a_domain() {
666 ComponentDto project = db.components().insertPrivateProject();
667 userSession.addProjectPermission(USER, project);
668 SnapshotDto analysis = db.getDbClient().snapshotDao().insert(dbSession, newAnalysis(project));
669 MetricDto metricWithoutDomain = db.measures().insertMetric(m -> m
670 .setValueType(Metric.ValueType.INT.name())
672 db.measures().insertLiveMeasure(project, metricWithoutDomain);
674 ComponentTreeWsResponse result = ws.newRequest()
675 .setParam(PARAM_COMPONENT, project.getKey())
676 .setParam(PARAM_METRIC_KEYS, metricWithoutDomain.getKey())
677 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
678 .executeProtobuf(ComponentTreeWsResponse.class);
680 assertThat(result.getBaseComponent().getMeasures(0).getMetric()).isEqualTo(metricWithoutDomain.getKey());
681 Common.Metric responseMetric = result.getMetrics().getMetrics(0);
682 assertThat(responseMetric.getKey()).isEqualTo(metricWithoutDomain.getKey());
683 assertThat(responseMetric.hasDomain()).isFalse();
687 public void project_reference_from_portfolio() {
688 ComponentDto project = db.components().insertPrivateProject();
689 userSession.addProjectPermission(USER, project);
690 ComponentDto view = db.components().insertPrivatePortfolio();
691 userSession.addProjectPermission(USER, view);
692 SnapshotDto viewAnalysis = db.components().insertSnapshot(view);
693 ComponentDto projectCopy = db.components().insertComponent(newProjectCopy(project, view));
694 MetricDto ncloc = insertNclocMetric();
695 db.measures().insertLiveMeasure(projectCopy, ncloc, m -> m.setValue(5d));
697 ComponentTreeWsResponse result = ws.newRequest()
698 .setParam(PARAM_COMPONENT, view.getKey())
699 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
700 .executeProtobuf(ComponentTreeWsResponse.class);
702 assertThat(result.getComponentsList())
703 .extracting(Component::getKey, Component::getRefKey)
704 .containsExactlyInAnyOrder(tuple(projectCopy.getKey(), project.getKey()));
708 public void portfolio_local_reference_in_portfolio() {
709 ComponentDto view = db.components().insertComponent(ComponentTesting.newPortfolio("VIEW1-UUID")
710 .setKey("Apache-Projects").setName("Apache Projects"));
711 userSession.registerComponents(view);
712 ComponentDto view2 = db.components().insertPrivatePortfolio();
713 userSession.addProjectPermission(USER, view2);
714 ComponentDto localView = db.components().insertComponent(
715 ComponentTesting.newSubPortfolio(view, "SUB-VIEW-UUID", "All-Projects").setName("All projects").setCopyComponentUuid(view2.uuid()));
716 db.components().insertSnapshot(view);
717 MetricDto ncloc = insertNclocMetric();
718 db.measures().insertLiveMeasure(localView, ncloc, m -> m.setValue(5d));
720 ComponentTreeWsResponse result = ws.newRequest()
721 .setParam(PARAM_COMPONENT, view.getKey())
722 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
723 .executeProtobuf(ComponentTreeWsResponse.class);
725 assertThat(result.getComponentsList())
726 .extracting(Component::getKey, Component::getRefKey, Component::getQualifier)
727 .containsExactlyInAnyOrder(tuple(localView.getKey(), view2.getKey(), "SVW"));
731 public void application_local_reference_in_portfolio() {
732 ComponentDto apache_projects = ComponentTesting.newPortfolio("VIEW1-UUID")
733 .setKey("Apache-Projects").setName("Apache Projects").setPrivate(true);
734 userSession.addProjectPermission(USER, apache_projects);
735 ComponentDto view = db.components().insertComponent(apache_projects);
736 ComponentDto application = db.components().insertPrivateApplication();
737 userSession.addProjectPermission(USER, application);
738 ComponentDto localView = db.components().insertComponent(
739 ComponentTesting.newSubPortfolio(view, "SUB-VIEW-UUID", "All-Projects").setName("All projects").setCopyComponentUuid(application.uuid()));
740 db.components().insertSnapshot(view);
741 MetricDto ncloc = insertNclocMetric();
742 db.measures().insertLiveMeasure(localView, ncloc, m -> m.setValue(5d));
744 ComponentTreeWsResponse result = ws.newRequest()
745 .setParam(PARAM_COMPONENT, view.getKey())
746 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
747 .executeProtobuf(ComponentTreeWsResponse.class);
749 assertThat(result.getComponentsList())
750 .extracting(Component::getKey, Component::getRefKey, Component::getQualifier)
751 .containsExactlyInAnyOrder(tuple(localView.getKey(), application.getKey(), "APP"));
755 public void project_branch_reference_from_application_branch() {
756 MetricDto ncloc = insertNclocMetric();
757 ComponentDto application = db.components().insertPublicProject(c -> c.setQualifier(APP).setKey("app-key"));
758 userSession.registerApplication(application);
759 String branchName = "app-branch";
760 ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey(branchName), a -> a.setUuid("custom-uuid"));
761 ComponentDto project = db.components().insertPrivateProject(p -> p.setKey("project-key"));
762 ComponentDto projectBranch = db.components().insertProjectBranch(project, b -> b.setKey("project-branch"));
763 ComponentDto techProjectBranch = db.components().insertComponent(newProjectCopy(projectBranch, applicationBranch)
764 .setKey(applicationBranch.getKey() + branchName + projectBranch.getKey()));
765 SnapshotDto applicationBranchAnalysis = db.components().insertSnapshot(applicationBranch);
766 db.measures().insertLiveMeasure(applicationBranch, ncloc, m -> m.setValue(5d));
767 db.measures().insertLiveMeasure(techProjectBranch, ncloc, m -> m.setValue(1d));
769 ComponentTreeWsResponse result = ws.newRequest()
770 .setParam(PARAM_COMPONENT, applicationBranch.getKey())
771 .setParam(PARAM_BRANCH, branchName)
772 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
773 .executeProtobuf(ComponentTreeWsResponse.class);
775 assertThat(result.getBaseComponent())
776 .extracting(Component::getKey, Component::getBranch)
777 .containsExactlyInAnyOrder(applicationBranch.getKey(), branchName);
778 assertThat(result.getComponentsList())
779 .extracting(Component::getKey, Component::getBranch, Component::getRefKey)
780 .containsExactlyInAnyOrder(tuple(techProjectBranch.getKey(), "project-branch", project.getKey()));
784 public void fail_when_metric_keys_parameter_is_empty() {
785 ComponentDto project = db.components().insertPrivateProject();
786 db.components().insertSnapshot(project);
788 assertThatThrownBy(() -> {
790 .setParam(PARAM_COMPONENT, project.getKey())
791 .setParam(PARAM_METRIC_KEYS, "")
792 .executeProtobuf(ComponentTreeWsResponse.class);
794 .isInstanceOf(BadRequestException.class)
795 .hasMessage("The 'metricKeys' parameter must contain at least one metric key");
799 public void fail_when_a_metric_is_not_found() {
800 ComponentDto project = db.components().insertPrivateProject();
801 userSession.addProjectPermission(USER, project);
802 db.components().insertSnapshot(project);
804 insertNewViolationsMetric();
806 assertThatThrownBy(() -> {
808 .setParam(PARAM_COMPONENT, project.getKey())
809 .setParam(PARAM_METRIC_KEYS, "ncloc, new_violations, unknown-metric, another-unknown-metric").executeProtobuf(ComponentTreeWsResponse.class);
811 .isInstanceOf(NotFoundException.class)
812 .hasMessage("The following metric keys are not found: unknown-metric, another-unknown-metric");
816 public void fail_when_using_DISTRIB_metrics() {
817 ComponentDto project = db.components().insertPrivateProject();
818 userSession.addProjectPermission(USER, project);
819 db.components().insertSnapshot(project);
820 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("distrib1").setValueType(DISTRIB.name()));
821 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("distrib2").setValueType(DISTRIB.name()));
824 assertThatThrownBy(() -> {
826 .setParam(PARAM_COMPONENT, project.getKey())
827 .setParam(PARAM_METRIC_KEYS, "distrib1,distrib2")
830 .isInstanceOf(IllegalArgumentException.class)
831 .hasMessage("Metrics distrib1, distrib2 can't be requested in this web service. Please use api/measures/component");
835 public void fail_when_using_DATA_metrics() {
836 ComponentDto project = db.components().insertPrivateProject();
837 userSession.addProjectPermission(USER, project);
838 db.components().insertSnapshot(project);
840 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("data1").setValueType(DISTRIB.name()));
841 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("data2").setValueType(DISTRIB.name()));
844 assertThatThrownBy(() -> {
846 .setParam(PARAM_COMPONENT, project.getKey())
847 .setParam(PARAM_METRIC_KEYS, "data1,data2")
850 .isInstanceOf(IllegalArgumentException.class)
851 .hasMessage("Metrics data1, data2 can't be requested in this web service. Please use api/measures/component");
855 public void fail_when_setting_more_than_15_metric_keys() {
856 ComponentDto project = db.components().insertPrivateProject();
857 db.components().insertSnapshot(project);
858 List<String> metrics = IntStream.range(0, 20)
859 .mapToObj(i -> "metric" + i)
860 .collect(MoreCollectors.toList());
863 assertThatThrownBy(() -> {
865 .setParam(PARAM_COMPONENT, project.getKey())
866 .setParam(PARAM_METRIC_KEYS, Joiner.on(",").join(metrics))
869 .isInstanceOf(IllegalArgumentException.class)
870 .hasMessage("'metricKeys' can contains only 15 values, got 20");
874 public void fail_when_search_query_have_less_than_3_characters() {
875 ComponentDto project = db.components().insertPrivateProject();
876 db.components().insertSnapshot(project);
878 insertNewViolationsMetric();
880 assertThatThrownBy(() -> {
882 .setParam(PARAM_COMPONENT, project.getKey())
883 .setParam(PARAM_METRIC_KEYS, "ncloc, new_violations")
884 .setParam(Param.TEXT_QUERY, "fi")
885 .executeProtobuf(ComponentTreeWsResponse.class);
887 .isInstanceOf(IllegalArgumentException.class)
888 .hasMessage("'q' length (2) is shorter than the minimum authorized (3)");
892 public void fail_when_insufficient_privileges() {
894 ComponentDto project = db.components().insertPrivateProject();
895 db.components().insertSnapshot(project);
897 var request = ws.newRequest()
898 .setParam(PARAM_COMPONENT, project.getKey())
899 .setParam(PARAM_METRIC_KEYS, "ncloc");
900 assertThatThrownBy(() -> request.executeProtobuf(ComponentTreeWsResponse.class))
901 .isInstanceOf(ForbiddenException.class);
905 public void fail_when_app_with_insufficient_privileges_for_projects() {
907 ComponentDto app = db.components().insertPrivateApplication();
908 ComponentDto project1 = db.components().insertPrivateProject();
909 ComponentDto project2 = db.components().insertPrivateProject();
910 db.components().insertSnapshot(app);
912 userSession.registerApplication(
913 toProjectDto(app, 1L),
914 toProjectDto(project1, 1L),
915 toProjectDto(project2, 1L));
917 userSession.addProjectPermission(USER, app, project1);
919 var request = ws.newRequest()
920 .setParam(PARAM_COMPONENT, app.getKey())
921 .setParam(PARAM_METRIC_KEYS, "ncloc");
922 assertThatThrownBy(() -> request.executeProtobuf(ComponentTreeWsResponse.class))
923 .isInstanceOf(ForbiddenException.class);
927 public void fail_when_sort_by_metric_and_no_metric_sort_provided() {
928 ComponentDto project = db.components().insertPrivateProject();
929 db.components().insertSnapshot(project);
931 assertThatThrownBy(() -> {
933 .setParam(PARAM_COMPONENT, project.getKey())
934 .setParam(PARAM_METRIC_KEYS, "ncloc")
935 // PARAM_METRIC_SORT is not set
936 .setParam(SORT, METRIC_SORT)
937 .executeProtobuf(ComponentTreeWsResponse.class);
939 .isInstanceOf(BadRequestException.class)
940 .hasMessage("To sort by a metric, the 's' parameter must contain 'metric' or 'metricPeriod', and a metric key must be provided in the 'metricSort' parameter");
944 public void fail_when_sort_by_metric_and_not_in_the_list_of_metric_keys() {
945 ComponentDto project = db.components().insertPrivateProject();
946 db.components().insertSnapshot(project);
948 assertThatThrownBy(() -> {
950 .setParam(PARAM_COMPONENT, project.getKey())
951 .setParam(PARAM_METRIC_KEYS, "ncloc,violations")
952 .setParam(PARAM_METRIC_SORT, "complexity")
953 .setParam(SORT, METRIC_SORT)
954 .executeProtobuf(ComponentTreeWsResponse.class);
956 .isInstanceOf(BadRequestException.class)
957 .hasMessage("To sort by the 'complexity' metric, it must be in the list of metric keys in the 'metricKeys' parameter");
961 public void fail_when_sort_by_metric_period_and_no_metric_period_sort_provided() {
962 ComponentDto project = db.components().insertPrivateProject();
963 db.components().insertSnapshot(project);
965 assertThatThrownBy(() -> {
967 .setParam(PARAM_COMPONENT, project.getKey())
968 .setParam(PARAM_METRIC_KEYS, "ncloc")
969 .setParam(PARAM_METRIC_SORT, "ncloc")
970 // PARAM_METRIC_PERIOD_SORT_IS_NOT_SET
971 .setParam(SORT, METRIC_PERIOD_SORT)
972 .executeProtobuf(ComponentTreeWsResponse.class);
974 .isInstanceOf(BadRequestException.class)
975 .hasMessage("To sort by a metric period, the 's' parameter must contain 'metricPeriod' and the 'metricPeriodSort' must be provided.");
979 public void fail_when_paging_parameter_is_too_big() {
980 ComponentDto project = db.components().insertPrivateProject();
981 db.components().insertSnapshot(project);
984 assertThatThrownBy(() -> {
986 .setParam(PARAM_COMPONENT, project.getKey())
987 .setParam(PARAM_METRIC_KEYS, "ncloc")
988 .setParam(Param.PAGE_SIZE, "2540")
991 .isInstanceOf(IllegalArgumentException.class)
992 .hasMessage("'ps' value (2540) must be less than 500");
996 public void fail_when_with_measures_only_and_no_metric_sort() {
997 ComponentDto project = db.components().insertPrivateProject();
998 db.components().insertSnapshot(project);
1001 assertThatThrownBy(() -> {
1003 .setParam(PARAM_COMPONENT, project.getKey())
1004 .setParam(PARAM_METRIC_KEYS, "ncloc")
1005 .setParam(PARAM_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER)
1006 .executeProtobuf(ComponentTreeWsResponse.class);
1008 .isInstanceOf(BadRequestException.class)
1009 .hasMessage("To filter components based on the sort metric, the 's' parameter must contain 'metric' or 'metricPeriod' and the 'metricSort' parameter must be provided");
1013 public void fail_when_component_does_not_exist() {
1014 insertNclocMetric();
1016 assertThatThrownBy(() -> {
1018 .setParam(PARAM_COMPONENT, "project-key")
1019 .setParam(PARAM_METRIC_KEYS, "ncloc")
1022 .isInstanceOf(NotFoundException.class)
1023 .hasMessage("Component key 'project-key' not found");
1027 public void fail_when_component_is_removed() {
1028 ComponentDto project = db.components().insertPrivateProject();
1029 db.components().insertSnapshot(project);
1030 ComponentDto file = db.components().insertComponent(newFileDto(project).setKey("file-key").setEnabled(false));
1031 userSession.anonymous().addProjectPermission(USER, project);
1032 insertNclocMetric();
1034 assertThatThrownBy(() -> {
1036 .setParam(PARAM_COMPONENT, file.getKey())
1037 .setParam(PARAM_METRIC_KEYS, "ncloc")
1040 .isInstanceOf(NotFoundException.class)
1041 .hasMessage(format("Component key '%s' not found", file.getKey()));
1045 public void fail_if_branch_does_not_exist() {
1046 ComponentDto project = db.components().insertPrivateProject();
1047 ComponentDto file = db.components().insertComponent(newFileDto(project));
1048 userSession.addProjectPermission(USER, project);
1049 db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
1051 assertThatThrownBy(() -> {
1053 .setParam(PARAM_COMPONENT, file.getKey())
1054 .setParam(PARAM_BRANCH, "another_branch")
1055 .setParam(PARAM_METRIC_KEYS, "ncloc")
1058 .isInstanceOf(NotFoundException.class)
1059 .hasMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch"));
1062 private static MetricDto newMetricDto() {
1063 return MetricTesting.newMetricDto()
1064 .setWorstValue(null)
1066 .setOptimizedBestValue(false);
1069 private MetricDto insertNewViolationsMetric() {
1070 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1071 .setKey("new_violations")
1072 .setShortName("New issues")
1073 .setDescription("New Issues")
1074 .setDomain("Issues")
1075 .setValueType("INT")
1077 .setQualitative(true)
1079 .setOptimizedBestValue(true)
1080 .setBestValue(0.0d));
1085 private MetricDto insertNclocMetric() {
1086 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1088 .setShortName("Lines of code")
1089 .setDescription("Non Commenting Lines of Code")
1091 .setValueType(INT.name())
1093 .setQualitative(false)
1099 private MetricDto insertComplexityMetric() {
1100 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1101 .setKey("complexity")
1102 .setShortName("Complexity")
1103 .setDescription("Cyclomatic complexity")
1104 .setDomain("Complexity")
1105 .setValueType(INT.name())
1107 .setQualitative(false)
1113 private MetricDto insertCoverageMetric() {
1114 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1116 .setShortName("Coverage")
1117 .setDescription("Code Coverage")
1118 .setDomain("Coverage")
1119 .setValueType(FLOAT.name())
1121 .setQualitative(false)