3 * Copyright (C) 2009-2020 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.junit.rules.ExpectedException;
28 import org.sonar.api.measures.CoreMetrics;
29 import org.sonar.api.measures.Metric;
30 import org.sonar.api.server.ws.WebService.Param;
31 import org.sonar.api.utils.System2;
32 import org.sonar.api.web.UserRole;
33 import org.sonar.core.util.stream.MoreCollectors;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbSession;
36 import org.sonar.db.DbTester;
37 import org.sonar.db.component.ComponentDto;
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.db.organization.OrganizationDto;
44 import org.sonar.server.component.ComponentFinder;
45 import org.sonar.server.exceptions.BadRequestException;
46 import org.sonar.server.exceptions.ForbiddenException;
47 import org.sonar.server.exceptions.NotFoundException;
48 import org.sonar.server.l18n.I18nRule;
49 import org.sonar.server.tester.UserSessionRule;
50 import org.sonar.server.ws.WsActionTester;
51 import org.sonarqube.ws.Common;
52 import org.sonarqube.ws.Measures.ComponentTreeWsResponse;
53 import org.sonarqube.ws.Measures.PeriodValue;
55 import static java.lang.Double.parseDouble;
56 import static java.lang.String.format;
57 import static java.util.Collections.singletonList;
58 import static org.assertj.core.api.Assertions.assertThat;
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.ComponentTesting.newDirectory;
75 import static org.sonar.db.component.ComponentTesting.newFileDto;
76 import static org.sonar.db.component.ComponentTesting.newProjectCopy;
77 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
78 import static org.sonar.server.component.ws.MeasuresWsParameters.ADDITIONAL_PERIOD;
79 import static org.sonar.server.component.ws.MeasuresWsParameters.DEPRECATED_ADDITIONAL_PERIODS;
80 import static org.sonar.server.component.ws.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_ID;
81 import static org.sonar.server.component.ws.MeasuresWsParameters.DEPRECATED_PARAM_BASE_COMPONENT_KEY;
82 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_ADDITIONAL_FIELDS;
83 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_BRANCH;
84 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_COMPONENT;
85 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_KEYS;
86 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_PERIOD_SORT;
87 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT;
88 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_METRIC_SORT_FILTER;
89 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_PULL_REQUEST;
90 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_QUALIFIERS;
91 import static org.sonar.server.component.ws.MeasuresWsParameters.PARAM_STRATEGY;
92 import static org.sonar.server.measure.ws.ComponentTreeAction.LEAVES_STRATEGY;
93 import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_PERIOD_SORT;
94 import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_SORT;
95 import static org.sonar.server.measure.ws.ComponentTreeAction.NAME_SORT;
96 import static org.sonar.server.measure.ws.ComponentTreeAction.WITH_MEASURES_ONLY_METRIC_SORT_FILTER;
97 import static org.sonar.test.JsonAssert.assertJson;
98 import static org.sonarqube.ws.Measures.Component;
99 import static org.sonarqube.ws.Measures.Measure;
101 public class ComponentTreeActionTest {
103 public UserSessionRule userSession = UserSessionRule.standalone().logIn().setRoot();
105 public ExpectedException expectedException = ExpectedException.none();
107 public DbTester db = DbTester.create(System2.INSTANCE);
109 private I18nRule i18n = new I18nRule();
110 private ResourceTypesRule resourceTypes = new ResourceTypesRule()
111 .setRootQualifiers(PROJECT)
112 .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
113 private DbClient dbClient = db.getDbClient();
114 private DbSession dbSession = db.getSession();
116 private WsActionTester ws = new WsActionTester(
117 new ComponentTreeAction(
118 dbClient, new ComponentFinder(dbClient, resourceTypes), userSession,
119 i18n, resourceTypes));
122 public void json_example() {
123 ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("MY_PROJECT")
124 .setName("My Project"));
125 SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
126 .setPeriodMode("previous_version")
127 .setPeriodParam("1.0-SNAPSHOT"));
128 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null)
129 .setUuid("AVIwDXE-bJbJqrw6wFv5")
130 .setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl/ElementImpl.java")
131 .setName("ElementImpl.java")
134 .setPath("src/main/java/com/sonarsource/markdown/impl/ElementImpl.java"));
135 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null)
136 .setUuid("AVIwDXE_bJbJqrw6wFwJ")
137 .setDbKey("com.sonarsource:java-markdown:src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java")
138 .setName("ElementImplTest.java")
140 .setQualifier(UNIT_TEST_FILE)
141 .setPath("src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java"));
142 ComponentDto dir = db.components().insertComponent(newDirectory(project, "src/main/java/com/sonarsource/markdown/impl")
143 .setUuid("AVIwDXE-bJbJqrw6wFv8")
144 .setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl")
145 .setQualifier(DIRECTORY));
147 MetricDto complexity = insertComplexityMetric();
148 db.measures().insertLiveMeasure(file1, complexity, m -> m.setValue(12.0d));
149 db.measures().insertLiveMeasure(dir, complexity, m -> m.setValue(35.0d).setVariation(0.0d));
150 db.measures().insertLiveMeasure(project, complexity, m -> m.setValue(42.0d));
152 MetricDto ncloc = insertNclocMetric();
153 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(114.0d));
154 db.measures().insertLiveMeasure(dir, ncloc, m -> m.setValue(217.0d).setVariation(0.0d));
155 db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(1984.0d));
157 MetricDto newViolations = insertNewViolationsMetric();
158 db.measures().insertLiveMeasure(file1, newViolations, m -> m.setVariation(25.0d));
159 db.measures().insertLiveMeasure(dir, newViolations, m -> m.setVariation(25.0d));
160 db.measures().insertLiveMeasure(project, newViolations, m -> m.setVariation(255.0d));
164 String response = ws.newRequest()
165 .setParam(PARAM_COMPONENT, project.getKey())
166 .setParam(PARAM_METRIC_KEYS, "ncloc, complexity, new_violations")
167 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics,period,periods")
171 assertJson(response).isSimilarTo(getClass().getResource("component_tree-example.json"));
175 public void empty_response() {
176 ComponentDto project = db.components().insertPrivateProject();
178 ComponentTreeWsResponse response = ws.newRequest()
179 .setParam(PARAM_COMPONENT, project.getKey())
180 .setParam(PARAM_METRIC_KEYS, "ncloc, complexity")
181 .executeProtobuf(ComponentTreeWsResponse.class);
183 assertThat(response.getBaseComponent().getKey()).isEqualTo(project.getKey());
184 assertThat(response.getComponentsList()).isEmpty();
185 assertThat(response.getMetrics().getMetricsList()).isEmpty();
186 assertThat(response.hasPeriod()).isFalse();
187 assertThat(response.getPeriods().getPeriodsList()).isEmpty();
191 public void load_measures_and_periods() {
192 ComponentDto project = db.components().insertPrivateProject();
193 SnapshotDto projectSnapshot = dbClient.snapshotDao().insert(dbSession,
195 .setPeriodDate(System.currentTimeMillis())
196 .setPeriodMode("last_version")
197 .setPeriodDate(System.currentTimeMillis()));
198 userSession.anonymous().addProjectPermission(UserRole.USER, project);
199 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
200 db.components().insertComponent(directory);
201 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
202 db.components().insertComponent(file);
203 MetricDto ncloc = insertNclocMetric();
204 MetricDto coverage = insertCoverageMetric();
206 db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(5.0d).setVariation(4.0d));
207 db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d));
208 db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(15.5d));
210 ComponentTreeWsResponse response = ws.newRequest()
211 .setParam(PARAM_COMPONENT, project.getKey())
212 .setParam(PARAM_METRIC_KEYS, "ncloc,coverage")
213 .setParam(PARAM_ADDITIONAL_FIELDS, DEPRECATED_ADDITIONAL_PERIODS + "," + ADDITIONAL_PERIOD)
214 .executeProtobuf(ComponentTreeWsResponse.class);
216 assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
218 List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
219 assertThat(fileMeasures).extracting("metric").containsOnly("ncloc", "coverage");
220 assertThat(fileMeasures).extracting("value").containsOnly("5", "15.5");
221 assertThat(response.getPeriod().getMode()).isEqualTo("last_version");
222 assertThat(response.getPeriods().getPeriodsList()).extracting("mode").containsOnly("last_version");
226 public void load_measures_with_best_value() {
227 ComponentDto project = db.components().insertPrivateProject();
228 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
229 userSession.anonymous().addProjectPermission(UserRole.USER, project);
230 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
231 db.components().insertComponent(directory);
232 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
233 db.components().insertComponent(file);
234 MetricDto coverage = insertCoverageMetric();
235 dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
237 .setValueType(INT.name())
238 .setOptimizedBestValue(true)
240 .setWorstValue(1000d));
241 dbClient.metricDao().insert(dbSession, newMetricDto()
242 .setKey("new_violations")
243 .setOptimizedBestValue(true)
244 .setBestValue(1984.0d)
245 .setValueType(INT.name()));
247 db.measures().insertLiveMeasure(file, coverage, m -> m.setValue(15.5d));
248 db.measures().insertLiveMeasure(directory, coverage, m -> m.setValue(42.0d));
250 ComponentTreeWsResponse response = ws.newRequest()
251 .setParam(PARAM_COMPONENT, project.getKey())
252 .setParam(PARAM_METRIC_KEYS, "ncloc,coverage,new_violations")
253 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
254 .executeProtobuf(ComponentTreeWsResponse.class);
256 // directory measures
257 assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
259 List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
260 assertThat(fileMeasures)
261 .extracting(Measure::getMetric, Measure::getValue, Measure::getBestValue, Measure::hasBestValue)
262 .containsExactlyInAnyOrder(tuple("ncloc", "100", true, true),
263 tuple("coverage", "15.5", false, false),
264 tuple("new_violations", "", false, false));
266 List<Common.Metric> metrics = response.getMetrics().getMetricsList();
267 assertThat(metrics).extracting("bestValue").contains("100", "");
268 assertThat(metrics).extracting("worstValue").contains("1000");
272 public void return_is_best_value_on_leak_measures() {
273 ComponentDto project = db.components().insertPrivateProject();
274 db.components().insertSnapshot(project);
275 userSession.anonymous().addProjectPermission(UserRole.USER, project);
276 ComponentDto file = newFileDto(project, null);
277 db.components().insertComponent(file);
279 MetricDto matchingBestValue = db.measures().insertMetric(m -> m
281 .setValueType(INT.name())
282 .setBestValue(100d));
283 MetricDto doesNotMatchBestValue = db.measures().insertMetric(m -> m
284 .setKey("new_lines_2")
285 .setValueType(INT.name())
286 .setBestValue(100d));
287 MetricDto noBestValue = db.measures().insertMetric(m -> m
288 .setKey("new_violations")
289 .setValueType(INT.name())
290 .setBestValue(null));
291 db.measures().insertLiveMeasure(file, matchingBestValue, m -> m.setValue(null).setData((String) null).setVariation(100d));
292 db.measures().insertLiveMeasure(file, doesNotMatchBestValue, m -> m.setValue(null).setData((String) null).setVariation(10d));
293 db.measures().insertLiveMeasure(file, noBestValue, m -> m.setValue(null).setData((String) null).setVariation(42.0d));
295 ComponentTreeWsResponse response = ws.newRequest()
296 .setParam(PARAM_COMPONENT, project.getKey())
297 .setParam(PARAM_METRIC_KEYS, "new_lines,new_lines_2,new_violations")
298 .executeProtobuf(ComponentTreeWsResponse.class);
302 // verify backward compatibility
303 List<Measure> fileMeasures = response.getComponentsList().get(0).getMeasuresList();
304 assertThat(fileMeasures)
305 .extracting(Measure::getMetric, m -> m.getPeriods().getPeriodsValueList())
306 .containsExactlyInAnyOrder(
307 tuple(matchingBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("100").setBestValue(true).build())),
308 tuple(doesNotMatchBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("10").setBestValue(false).build())),
309 tuple(noBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("42").build())));
311 assertThat(fileMeasures)
312 .extracting(Measure::getMetric, Measure::getPeriod)
313 .containsExactlyInAnyOrder(
314 tuple(matchingBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("100").setBestValue(true).build()),
315 tuple(doesNotMatchBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("10").setBestValue(false).build()),
316 tuple(noBestValue.getKey(), PeriodValue.newBuilder().setIndex(1).setValue("42").build()));
320 public void use_best_value_for_rating() {
321 ComponentDto project = db.components().insertPrivateProject();
322 userSession.anonymous().addProjectPermission(UserRole.USER, project);
323 SnapshotDto projectSnapshot = dbClient.snapshotDao().insert(dbSession, newAnalysis(project)
324 .setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
325 .setPeriodMode("previous_version")
326 .setPeriodParam("1.0-SNAPSHOT"));
327 ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
328 db.components().insertComponent(directory);
329 ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
330 db.components().insertComponent(file);
331 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
332 .setKey(NEW_SECURITY_RATING_KEY)
333 .setOptimizedBestValue(true)
335 .setValueType(RATING.name()));
337 db.measures().insertLiveMeasure(directory, metric, m -> m.setVariation(2d));
339 ComponentTreeWsResponse response = ws.newRequest()
340 .setParam(PARAM_COMPONENT, project.getKey())
341 .setParam(PARAM_METRIC_KEYS, NEW_SECURITY_RATING_KEY)
342 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
343 .executeProtobuf(ComponentTreeWsResponse.class);
346 assertThat(response.getComponentsList().get(0).getMeasuresList().get(0).getPeriods().getPeriodsValue(0).getValue()).isEqualTo("2.0");
347 assertThat(response.getComponentsList().get(0).getMeasuresList().get(0).getPeriod().getValue()).isEqualTo("2.0");
349 assertThat(response.getComponentsList().get(1).getMeasuresList().get(0).getPeriods().getPeriodsValue(0).getValue()).isEqualTo("1.0");
350 assertThat(response.getComponentsList().get(1).getMeasuresList().get(0).getPeriod().getValue()).isEqualTo("1.0");
354 public void load_measures_multi_sort_with_metric_key_and_paginated() {
355 ComponentDto project = db.components().insertPrivateProject();
356 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
357 ComponentDto file9 = db.components().insertComponent(newFileDto(project, null, "file-uuid-9").setName("file-1"));
358 ComponentDto file8 = db.components().insertComponent(newFileDto(project, null, "file-uuid-8").setName("file-1"));
359 ComponentDto file7 = db.components().insertComponent(newFileDto(project, null, "file-uuid-7").setName("file-1"));
360 ComponentDto file6 = db.components().insertComponent(newFileDto(project, null, "file-uuid-6").setName("file-1"));
361 ComponentDto file5 = db.components().insertComponent(newFileDto(project, null, "file-uuid-5").setName("file-1"));
362 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4").setName("file-1"));
363 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setName("file-1"));
364 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-1"));
365 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-1"));
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("id").containsExactly("file-uuid-4", "file-uuid-5", "file-uuid-6");
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 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
399 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4"));
400 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
401 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
402 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
403 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
404 dbClient.metricDao().insert(dbSession, ncloc);
406 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setValue(1.0d));
407 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setValue(2.0d));
408 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setValue(3.0d));
410 ComponentTreeWsResponse response = ws.newRequest()
411 .setParam(PARAM_COMPONENT, project.getKey())
412 .setParam(SORT, METRIC_SORT)
413 .setParam(PARAM_METRIC_SORT, "ncloc")
414 .setParam(PARAM_METRIC_KEYS, "ncloc")
415 .executeProtobuf(ComponentTreeWsResponse.class);
417 assertThat(response.getComponentsList()).extracting("id").containsExactly("file-uuid-1", "file-uuid-2", "file-uuid-3", "file-uuid-4");
418 assertThat(response.getPaging().getTotal()).isEqualTo(4);
422 public void remove_components_without_measure_on_the_metric_sort() {
423 ComponentDto project = db.components().insertPrivateProject();
424 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
425 ComponentDto file1 = newFileDto(project, null, "file-uuid-1");
426 ComponentDto file2 = newFileDto(project, null, "file-uuid-2");
427 ComponentDto file3 = newFileDto(project, null, "file-uuid-3");
428 ComponentDto file4 = newFileDto(project, null, "file-uuid-4");
429 db.components().insertComponent(file1);
430 db.components().insertComponent(file2);
431 db.components().insertComponent(file3);
432 db.components().insertComponent(file4);
433 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
434 dbClient.metricDao().insert(dbSession, ncloc);
435 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(1.0d).setVariation(null));
436 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(2.0d).setVariation(null));
437 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(3.0d).setVariation(null));
438 // measure on period 1
439 db.measures().insertLiveMeasure(file4, ncloc, m -> m.setData((String) null).setValue(null).setVariation(4.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("id")
451 .containsExactly(file1.uuid(), file2.uuid(), file3.uuid())
452 .doesNotContain(file4.uuid());
453 assertThat(response.getPaging().getTotal()).isEqualTo(3);
457 public void sort_by_metric_period() {
458 ComponentDto project = db.components().insertPrivateProject();
459 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
460 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
461 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
462 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
463 MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
464 dbClient.metricDao().insert(dbSession, ncloc);
466 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setVariation(1.0d));
467 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setVariation(2.0d));
468 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setVariation(3.0d));
470 ComponentTreeWsResponse response = ws.newRequest()
471 .setParam(PARAM_COMPONENT, project.getKey())
472 .setParam(SORT, METRIC_PERIOD_SORT)
473 .setParam(PARAM_METRIC_SORT, "ncloc")
474 .setParam(PARAM_METRIC_KEYS, "ncloc")
475 .setParam(PARAM_METRIC_PERIOD_SORT, "1")
476 .executeProtobuf(ComponentTreeWsResponse.class);
478 assertThat(response.getComponentsList()).extracting("id").containsExactly("file-uuid-1", "file-uuid-2", "file-uuid-3");
482 public void remove_components_without_measure_on_the_metric_period_sort() {
483 ComponentDto project = db.components().insertPrivateProject();
484 SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
485 ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4"));
486 ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
487 ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
488 ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
489 MetricDto ncloc = newMetricDto().setKey("new_ncloc").setValueType(INT.name()).setDirection(1);
490 dbClient.metricDao().insert(dbSession, ncloc);
491 db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(null).setVariation(1.0d));
492 db.measures().insertLiveMeasure(file2, ncloc, m -> m.setData((String) null).setValue(null).setVariation(2.0d));
493 db.measures().insertLiveMeasure(file3, ncloc, m -> m.setData((String) null).setValue(null).setVariation(3.0d));
494 // file 4 measure is on absolute value
495 db.measures().insertLiveMeasure(file4, ncloc, m -> m.setData((String) null).setValue(4.0d).setVariation(null));
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("id")
508 .containsExactly("file-uuid-1", "file-uuid-2", "file-uuid-3")
509 .doesNotContain("file-uuid-4");
513 public void load_measures_when_no_leave_qualifier() {
514 resourceTypes.setLeavesQualifiers();
515 ComponentDto project = db.components().insertPrivateProject();
516 db.components().insertSnapshot(project);
517 db.components().insertComponent(newFileDto(project, null));
520 ComponentTreeWsResponse result = ws.newRequest()
521 .setParam(PARAM_COMPONENT, project.getKey())
522 .setParam(PARAM_STRATEGY, LEAVES_STRATEGY)
523 .setParam(PARAM_METRIC_KEYS, "ncloc")
524 .executeProtobuf(ComponentTreeWsResponse.class);
526 assertThat(result.getBaseComponent().getKey()).isEqualTo(project.getKey());
527 assertThat(result.getComponentsCount()).isZero();
531 public void branch() {
532 OrganizationDto organization = db.organizations().insert();
533 ComponentDto project = db.components().insertPrivateProject(organization);
534 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
535 SnapshotDto analysis = db.components().insertSnapshot(branch);
536 ComponentDto file = db.components().insertComponent(newFileDto(branch));
537 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
538 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d));
540 ComponentTreeWsResponse response = ws.newRequest()
541 .setParam(PARAM_COMPONENT, file.getKey())
542 .setParam(PARAM_BRANCH, file.getBranch())
543 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
544 .executeProtobuf(ComponentTreeWsResponse.class);
546 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
547 .containsExactlyInAnyOrder(file.getKey(), file.getBranch());
548 assertThat(response.getBaseComponent().getMeasuresList())
549 .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
550 .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
554 public void pull_request() {
555 OrganizationDto organization = db.organizations().insert();
556 ComponentDto project = db.components().insertPrivateProject(organization);
557 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
558 SnapshotDto analysis = db.components().insertSnapshot(branch);
559 ComponentDto file = db.components().insertComponent(newFileDto(branch));
560 MetricDto complexity = db.measures().insertMetric(m -> m.setValueType(INT.name()));
561 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, complexity, m -> m.setValue(12.0d));
563 ComponentTreeWsResponse response = ws.newRequest()
564 .setParam(PARAM_COMPONENT, file.getKey())
565 .setParam(PARAM_PULL_REQUEST, "pr-123")
566 .setParam(PARAM_METRIC_KEYS, complexity.getKey())
567 .executeProtobuf(ComponentTreeWsResponse.class);
569 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
570 .containsExactlyInAnyOrder(file.getKey(), "pr-123");
571 assertThat(response.getBaseComponent().getMeasuresList())
572 .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
573 .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
577 public void fix_pull_request_new_issue_count_metrics() {
578 OrganizationDto organization = db.organizations().insert();
579 ComponentDto project = db.components().insertPrivateProject(organization);
580 ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("pr-123").setBranchType(PULL_REQUEST));
581 SnapshotDto analysis = db.components().insertSnapshot(branch);
582 ComponentDto file = db.components().insertComponent(newFileDto(branch));
583 MetricDto bug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.BUGS_KEY));
584 MetricDto newBug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.NEW_BUGS_KEY));
586 LiveMeasureDto measure = db.measures().insertLiveMeasure(file, bug, m -> m.setValue(12.0d));
588 ComponentTreeWsResponse response = ws.newRequest()
589 .setParam(PARAM_COMPONENT, file.getKey())
590 .setParam(PARAM_PULL_REQUEST, "pr-123")
591 .setParam(PARAM_METRIC_KEYS, newBug.getKey())
592 .executeProtobuf(ComponentTreeWsResponse.class);
594 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
595 .containsExactlyInAnyOrder(file.getKey(), "pr-123");
596 assertThat(response.getBaseComponent().getMeasuresList())
597 .extracting(Measure::getMetric, m -> parseDouble(m.getPeriods().getPeriodsValue(0).getValue()), Measure::getValue)
598 .containsExactlyInAnyOrder(tuple(newBug.getKey(), measure.getValue(), ""));
600 assertThat(response.getBaseComponent().getMeasuresList())
601 .extracting(Measure::getMetric, m -> parseDouble(m.getPeriod().getValue()), Measure::getValue)
602 .containsExactlyInAnyOrder(tuple(newBug.getKey(), measure.getValue(), ""));
606 public void new_issue_count_measures_are_not_transformed_if_they_dont_exist_in_pr() {
607 OrganizationDto organization = db.organizations().insert();
608 ComponentDto project = db.components().insertPrivateProject(organization);
609 ComponentDto pr = db.components().insertProjectBranch(project, b -> b.setKey("pr").setBranchType(PULL_REQUEST));
610 SnapshotDto analysis = db.components().insertSnapshot(pr);
611 ComponentDto file = db.components().insertComponent(newFileDto(pr));
612 MetricDto bug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.BUGS_KEY));
613 MetricDto newBug = db.measures().insertMetric(m -> m.setValueType(INT.name()).setKey(CoreMetrics.NEW_BUGS_KEY));
615 ComponentTreeWsResponse response = ws.newRequest()
616 .setParam(PARAM_COMPONENT, file.getKey())
617 .setParam(PARAM_PULL_REQUEST, "pr")
618 .setParam(PARAM_METRIC_KEYS, newBug.getKey() + "," + bug.getKey())
619 .executeProtobuf(ComponentTreeWsResponse.class);
621 assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
622 .containsExactlyInAnyOrder(file.getKey(), "pr");
623 assertThat(response.getBaseComponent().getMeasuresList())
628 public void return_deprecated_id_in_the_response() {
629 ComponentDto project = db.components().insertPrivateProject();
630 SnapshotDto analysis = db.components().insertSnapshot(project);
631 ComponentDto file = db.components().insertComponent(newFileDto(project));
632 MetricDto ncloc = insertNclocMetric();
633 db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(2d));
635 ComponentTreeWsResponse response = ws.newRequest()
636 .setParam(PARAM_COMPONENT, project.getKey())
637 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
638 .executeProtobuf(ComponentTreeWsResponse.class);
640 assertThat(response.getBaseComponent().getId()).isEqualTo(project.uuid());
641 assertThat(response.getComponentsList()).extracting(Component::getId)
642 .containsExactlyInAnyOrder(file.uuid());
646 public void use_deprecated_base_component_id_parameter() {
647 ComponentDto project = db.components().insertPrivateProject();
648 userSession.addProjectPermission(USER, project);
651 ComponentTreeWsResponse response = ws.newRequest()
652 .setParam("baseComponentId", project.uuid())
653 .setParam(PARAM_METRIC_KEYS, "ncloc")
654 .executeProtobuf(ComponentTreeWsResponse.class);
656 assertThat(response.getBaseComponent().getKey()).isEqualTo(project.getKey());
660 public void use_deprecated_base_component_key_parameter() {
661 ComponentDto project = db.components().insertPrivateProject();
662 userSession.addProjectPermission(USER, project);
665 ComponentTreeWsResponse response = ws.newRequest()
666 .setParam("baseComponentKey", project.getKey())
667 .setParam(PARAM_METRIC_KEYS, "ncloc")
668 .executeProtobuf(ComponentTreeWsResponse.class);
670 assertThat(response.getBaseComponent().getKey()).isEqualTo(project.getKey());
674 public void metric_without_a_domain() {
675 ComponentDto project = db.components().insertPrivateProject();
676 SnapshotDto analysis = db.getDbClient().snapshotDao().insert(dbSession, newAnalysis(project));
677 MetricDto metricWithoutDomain = db.measures().insertMetric(m -> m
678 .setValueType(Metric.ValueType.INT.name())
680 db.measures().insertLiveMeasure(project, metricWithoutDomain);
682 ComponentTreeWsResponse result = ws.newRequest()
683 .setParam(PARAM_COMPONENT, project.getKey())
684 .setParam(PARAM_METRIC_KEYS, metricWithoutDomain.getKey())
685 .setParam(PARAM_ADDITIONAL_FIELDS, "metrics")
686 .executeProtobuf(ComponentTreeWsResponse.class);
688 assertThat(result.getBaseComponent().getMeasures(0).getMetric()).isEqualTo(metricWithoutDomain.getKey());
689 Common.Metric responseMetric = result.getMetrics().getMetrics(0);
690 assertThat(responseMetric.getKey()).isEqualTo(metricWithoutDomain.getKey());
691 assertThat(responseMetric.hasDomain()).isFalse();
695 public void project_reference_from_portfolio() {
696 ComponentDto project = db.components().insertPrivateProject();
697 ComponentDto view = db.components().insertPrivatePortfolio(db.getDefaultOrganization());
698 SnapshotDto viewAnalysis = db.components().insertSnapshot(view);
699 ComponentDto projectCopy = db.components().insertComponent(newProjectCopy(project, view));
700 MetricDto ncloc = insertNclocMetric();
701 db.measures().insertLiveMeasure(projectCopy, ncloc, m -> m.setValue(5d));
703 ComponentTreeWsResponse result = ws.newRequest()
704 .setParam(PARAM_COMPONENT, view.getKey())
705 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
706 .executeProtobuf(ComponentTreeWsResponse.class);
708 assertThat(result.getComponentsList())
709 .extracting(Component::getKey, Component::getRefId, Component::getRefKey)
710 .containsExactlyInAnyOrder(tuple(projectCopy.getKey(), project.uuid(), project.getKey()));
714 public void project_branch_reference_from_application_branch() {
715 MetricDto ncloc = insertNclocMetric();
716 ComponentDto application = db.components().insertPublicProject(c -> c.setQualifier(APP).setDbKey("app-key"));
717 ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey("app-branch"));
718 ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("project-key"));
719 ComponentDto projectBranch = db.components().insertProjectBranch(project, b -> b.setKey("project-branch"));
720 ComponentDto techProjectBranch = db.components().insertComponent(newProjectCopy(projectBranch, applicationBranch)
721 .setDbKey(applicationBranch.getKey() + applicationBranch.getBranch() + projectBranch.getDbKey()));
722 SnapshotDto applicationBranchAnalysis = db.components().insertSnapshot(applicationBranch);
723 db.measures().insertLiveMeasure(applicationBranch, ncloc, m -> m.setValue(5d));
724 db.measures().insertLiveMeasure(techProjectBranch, ncloc, m -> m.setValue(1d));
726 ComponentTreeWsResponse result = ws.newRequest()
727 .setParam(PARAM_COMPONENT, applicationBranch.getKey())
728 .setParam(PARAM_BRANCH, applicationBranch.getBranch())
729 .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
730 .executeProtobuf(ComponentTreeWsResponse.class);
732 assertThat(result.getBaseComponent())
733 .extracting(Component::getKey, Component::getBranch)
734 .containsExactlyInAnyOrder(applicationBranch.getKey(), applicationBranch.getBranch());
735 assertThat(result.getComponentsList())
736 .extracting(Component::getKey, Component::getBranch, Component::getRefId, Component::getRefKey)
737 .containsExactlyInAnyOrder(tuple(techProjectBranch.getKey(), projectBranch.getBranch(), projectBranch.uuid(), project.getKey()));
741 public void fail_when_metric_keys_parameter_is_empty() {
742 ComponentDto project = db.components().insertPrivateProject();
743 db.components().insertSnapshot(project);
745 expectedException.expect(BadRequestException.class);
746 expectedException.expectMessage("The 'metricKeys' parameter must contain at least one metric key");
749 .setParam(PARAM_COMPONENT, project.getKey())
750 .setParam(PARAM_METRIC_KEYS, "")
751 .executeProtobuf(ComponentTreeWsResponse.class);
755 public void fail_when_a_metric_is_not_found() {
756 ComponentDto project = db.components().insertPrivateProject();
757 db.components().insertSnapshot(project);
759 insertNewViolationsMetric();
760 expectedException.expect(NotFoundException.class);
761 expectedException.expectMessage("The following metric keys are not found: unknown-metric, another-unknown-metric");
764 .setParam(PARAM_COMPONENT, project.getKey())
765 .setParam(PARAM_METRIC_KEYS, "ncloc, new_violations, unknown-metric, another-unknown-metric").executeProtobuf(ComponentTreeWsResponse.class);
769 public void fail_when_using_DISTRIB_metrics() {
770 ComponentDto project = db.components().insertPrivateProject();
771 db.components().insertSnapshot(project);
772 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("distrib1").setValueType(DISTRIB.name()));
773 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("distrib2").setValueType(DISTRIB.name()));
776 expectedException.expect(IllegalArgumentException.class);
777 expectedException.expectMessage("Metrics distrib1, distrib2 can't be requested in this web service. Please use api/measures/component");
780 .setParam(PARAM_COMPONENT, project.getKey())
781 .setParam(PARAM_METRIC_KEYS, "distrib1,distrib2")
786 public void fail_when_using_DATA_metrics() {
787 ComponentDto project = db.components().insertPrivateProject();
788 db.components().insertSnapshot(project);
790 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("data1").setValueType(DISTRIB.name()));
791 dbClient.metricDao().insert(dbSession, newMetricDto().setKey("data2").setValueType(DISTRIB.name()));
794 expectedException.expect(IllegalArgumentException.class);
795 expectedException.expectMessage("Metrics data1, data2 can't be requested in this web service. Please use api/measures/component");
798 .setParam(PARAM_COMPONENT, project.getKey())
799 .setParam(PARAM_METRIC_KEYS, "data1,data2")
804 public void fail_when_setting_more_than_15_metric_keys() {
805 ComponentDto project = db.components().insertPrivateProject();
806 db.components().insertSnapshot(project);
807 List<String> metrics = IntStream.range(0, 20)
808 .mapToObj(i -> "metric" + i)
809 .collect(MoreCollectors.toList());
812 expectedException.expect(IllegalArgumentException.class);
813 expectedException.expectMessage("'metricKeys' can contains only 15 values, got 20");
816 .setParam(PARAM_COMPONENT, project.getKey())
817 .setParam(PARAM_METRIC_KEYS, Joiner.on(",").join(metrics))
822 public void fail_when_search_query_have_less_than_3_characters() {
823 ComponentDto project = db.components().insertPrivateProject();
824 db.components().insertSnapshot(project);
826 insertNewViolationsMetric();
827 expectedException.expect(IllegalArgumentException.class);
828 expectedException.expectMessage("'q' length (2) is shorter than the minimum authorized (3)");
831 .setParam(PARAM_COMPONENT, project.getKey())
832 .setParam(PARAM_METRIC_KEYS, "ncloc, new_violations")
833 .setParam(Param.TEXT_QUERY, "fi")
834 .executeProtobuf(ComponentTreeWsResponse.class);
838 public void fail_when_insufficient_privileges() {
840 ComponentDto project = db.components().insertPrivateProject();
841 db.components().insertSnapshot(project);
843 expectedException.expect(ForbiddenException.class);
846 .setParam(PARAM_COMPONENT, project.getKey())
847 .setParam(PARAM_METRIC_KEYS, "ncloc")
848 .executeProtobuf(ComponentTreeWsResponse.class);
852 public void fail_when_sort_by_metric_and_no_metric_sort_provided() {
853 ComponentDto project = db.components().insertPrivateProject();
854 db.components().insertSnapshot(project);
855 expectedException.expect(BadRequestException.class);
857 .expectMessage("To sort by a metric, the 's' parameter must contain 'metric' or 'metricPeriod', and a metric key must be provided in the 'metricSort' parameter");
860 .setParam(PARAM_COMPONENT, project.getKey())
861 .setParam(PARAM_METRIC_KEYS, "ncloc")
862 // PARAM_METRIC_SORT is not set
863 .setParam(SORT, METRIC_SORT)
864 .executeProtobuf(ComponentTreeWsResponse.class);
868 public void fail_when_sort_by_metric_and_not_in_the_list_of_metric_keys() {
869 ComponentDto project = db.components().insertPrivateProject();
870 db.components().insertSnapshot(project);
872 expectedException.expect(BadRequestException.class);
873 expectedException.expectMessage("To sort by the 'complexity' metric, it must be in the list of metric keys in the 'metricKeys' parameter");
876 .setParam(PARAM_COMPONENT, project.getKey())
877 .setParam(PARAM_METRIC_KEYS, "ncloc,violations")
878 .setParam(PARAM_METRIC_SORT, "complexity")
879 .setParam(SORT, METRIC_SORT)
880 .executeProtobuf(ComponentTreeWsResponse.class);
884 public void fail_when_sort_by_metric_period_and_no_metric_period_sort_provided() {
885 ComponentDto project = db.components().insertPrivateProject();
886 db.components().insertSnapshot(project);
888 expectedException.expect(BadRequestException.class);
889 expectedException.expectMessage("To sort by a metric period, the 's' parameter must contain 'metricPeriod' and the 'metricPeriodSort' must be provided.");
892 .setParam(PARAM_COMPONENT, project.getKey())
893 .setParam(PARAM_METRIC_KEYS, "ncloc")
894 .setParam(PARAM_METRIC_SORT, "ncloc")
895 // PARAM_METRIC_PERIOD_SORT_IS_NOT_SET
896 .setParam(SORT, METRIC_PERIOD_SORT)
897 .executeProtobuf(ComponentTreeWsResponse.class);
901 public void fail_when_paging_parameter_is_too_big() {
902 ComponentDto project = db.components().insertPrivateProject();
903 db.components().insertSnapshot(project);
906 expectedException.expect(IllegalArgumentException.class);
907 expectedException.expectMessage("'ps' value (2540) must be less than 500");
910 .setParam(PARAM_COMPONENT, project.getKey())
911 .setParam(PARAM_METRIC_KEYS, "ncloc")
912 .setParam(Param.PAGE_SIZE, "2540")
917 public void fail_when_with_measures_only_and_no_metric_sort() {
918 ComponentDto project = db.components().insertPrivateProject();
919 db.components().insertSnapshot(project);
922 expectedException.expect(BadRequestException.class);
924 .expectMessage("To filter components based on the sort metric, the 's' parameter must contain 'metric' or 'metricPeriod' and the 'metricSort' parameter must be provided");
927 .setParam(PARAM_COMPONENT, project.getKey())
928 .setParam(PARAM_METRIC_KEYS, "ncloc")
929 .setParam(PARAM_METRIC_SORT_FILTER, WITH_MEASURES_ONLY_METRIC_SORT_FILTER)
930 .executeProtobuf(ComponentTreeWsResponse.class);
934 public void fail_when_component_does_not_exist() {
937 expectedException.expect(NotFoundException.class);
938 expectedException.expectMessage("Component key 'project-key' not found");
941 .setParam(DEPRECATED_PARAM_BASE_COMPONENT_KEY, "project-key")
942 .setParam(PARAM_METRIC_KEYS, "ncloc")
947 public void fail_when_component_is_removed() {
948 ComponentDto project = db.components().insertPrivateProject();
949 db.components().insertSnapshot(project);
950 ComponentDto file = db.components().insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false));
951 userSession.anonymous().addProjectPermission(UserRole.USER, project);
954 expectedException.expect(NotFoundException.class);
955 expectedException.expectMessage(format("Component key '%s' not found", file.getKey()));
958 .setParam(PARAM_COMPONENT, file.getKey())
959 .setParam(PARAM_METRIC_KEYS, "ncloc")
964 public void fail_if_branch_does_not_exist() {
965 ComponentDto project = db.components().insertPrivateProject();
966 ComponentDto file = db.components().insertComponent(newFileDto(project));
967 userSession.addProjectPermission(UserRole.USER, project);
968 db.components().insertProjectBranch(project, b -> b.setKey("my_branch"));
970 expectedException.expect(NotFoundException.class);
971 expectedException.expectMessage(String.format("Component '%s' on branch '%s' not found", file.getKey(), "another_branch"));
974 .setParam(PARAM_COMPONENT, file.getKey())
975 .setParam(PARAM_BRANCH, "another_branch")
976 .setParam(PARAM_METRIC_KEYS, "ncloc")
981 public void fail_when_using_branch_db_key() throws Exception {
982 OrganizationDto organization = db.organizations().insert();
983 ComponentDto project = db.components().insertPrivateProject(organization);
984 userSession.logIn().addProjectPermission(UserRole.USER, project);
985 ComponentDto branch = db.components().insertProjectBranch(project);
988 expectedException.expect(NotFoundException.class);
989 expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
992 .setParam(PARAM_COMPONENT, branch.getDbKey())
993 .setParam(PARAM_METRIC_KEYS, "ncloc")
998 public void fail_when_using_branch_uuid() {
999 OrganizationDto organization = db.organizations().insert();
1000 ComponentDto project = db.components().insertPrivateProject(organization);
1001 userSession.logIn().addProjectPermission(UserRole.USER, project);
1002 ComponentDto branch = db.components().insertProjectBranch(project);
1003 insertNclocMetric();
1005 expectedException.expect(NotFoundException.class);
1006 expectedException.expectMessage(format("Component id '%s' not found", branch.uuid()));
1009 .setParam(DEPRECATED_PARAM_BASE_COMPONENT_ID, branch.uuid())
1010 .setParam(PARAM_METRIC_KEYS, "ncloc")
1014 private static MetricDto newMetricDto() {
1015 return MetricTesting.newMetricDto()
1016 .setWorstValue(null)
1018 .setOptimizedBestValue(false)
1019 .setUserManaged(false);
1022 private MetricDto insertNewViolationsMetric() {
1023 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1024 .setKey("new_violations")
1025 .setShortName("New issues")
1026 .setDescription("New Issues")
1027 .setDomain("Issues")
1028 .setValueType("INT")
1030 .setQualitative(true)
1032 .setUserManaged(false)
1033 .setOptimizedBestValue(true)
1034 .setBestValue(0.0d));
1039 private MetricDto insertNclocMetric() {
1040 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1042 .setShortName("Lines of code")
1043 .setDescription("Non Commenting Lines of Code")
1045 .setValueType(INT.name())
1047 .setQualitative(false)
1049 .setUserManaged(false));
1054 private MetricDto insertComplexityMetric() {
1055 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1056 .setKey("complexity")
1057 .setShortName("Complexity")
1058 .setDescription("Cyclomatic complexity")
1059 .setDomain("Complexity")
1060 .setValueType(INT.name())
1062 .setQualitative(false)
1064 .setUserManaged(false));
1069 private MetricDto insertCoverageMetric() {
1070 MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
1072 .setShortName("Coverage")
1073 .setDescription("Code Coverage")
1074 .setDomain("Coverage")
1075 .setValueType(FLOAT.name())
1077 .setQualitative(false)
1079 .setUserManaged(false));