aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-09-26 16:17:22 +0200
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2016-09-30 14:16:55 +0200
commitc06807de9d0825b95d3752bf5e1480400a50c7a8 (patch)
tree5c46d90fd5ee42d9f68709d38508e84249c9a4cd
parent2bbfd0c6ca169d20ae2d51e7cbb029ad3f9ea73b (diff)
downloadsonarqube-c06807de9d0825b95d3752bf5e1480400a50c7a8.tar.gz
sonarqube-c06807de9d0825b95d3752bf5e1480400a50c7a8.zip
SONAR-8120 WS measures/search check request
- all metrics exist - all component ids or keys exist - at least one metric provided - at least one component provided etc.
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java30
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java130
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/measure/SearchRequest.java10
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/measure/SearchRequestTest.java2
4 files changed, 165 insertions, 7 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java
index 8d290cfa9b0..cc22ec4e42e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchAction.java
@@ -21,8 +21,11 @@
package org.sonar.server.measure.ws;
import com.google.common.collect.ImmutableMultimap;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import org.sonar.api.server.ws.Request;
@@ -52,11 +55,11 @@ import static org.sonar.server.ws.KeyExamples.KEY_FILE_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_FILE_EXAMPLE_002;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_002;
+import static org.sonar.server.ws.WsUtils.checkRequest;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_KEYS;
public class SearchAction implements MeasuresWsAction {
- private static final int MAX_NB_COMPONENTS = 100;
static final String PARAM_COMPONENT_IDS = "componentIds";
static final String PARAM_COMPONENT_KEYS = "componentKeys";
@@ -79,7 +82,7 @@ public class SearchAction implements MeasuresWsAction {
" <li>'Administer' rights on the provided components</li>" +
" <li>'Browse' on the provided components</li>" +
"</ul>",
- MAX_NB_COMPONENTS, PARAM_COMPONENT_IDS, PARAM_COMPONENT_KEYS)
+ SearchRequest.MAX_NB_COMPONENTS, PARAM_COMPONENT_IDS, PARAM_COMPONENT_KEYS)
.setSince("6.1")
.setResponseExample(getClass().getResource("search-example.json"))
.setHandler(this);
@@ -142,18 +145,26 @@ public class SearchAction implements MeasuresWsAction {
private List<MetricDto> searchMetrics() {
requireNonNull(request);
- return dbClient.metricDao().selectByKeys(dbSession, request.getMetricKeys());
+ List<MetricDto> dbMetrics = dbClient.metricDao().selectByKeys(dbSession, request.getMetricKeys());
+ List<String> metricKeys = dbMetrics.stream().map(MetricDto::getKey).collect(Collectors.toList());
+ checkRequest(request.getMetricKeys().size() == dbMetrics.size(), "The following metrics are not found: %s",
+ String.join(", ", difference(request.getMetricKeys(), metricKeys)));
+ return dbMetrics;
}
private List<ComponentDto> searchComponents() {
requireNonNull(request);
if (request.hasComponentIds()) {
List<ComponentDto> componentsByUuid = searchByComponentUuids(dbSession, request.getComponentIds());
- checkArgument(componentsByUuid.size() == request.getComponentIds().size(), "Some components are not found in: '%s'", String.join(", ", request.getComponentIds()));
+ List<String> componentUuids = componentsByUuid.stream().map(ComponentDto::uuid).collect(Collectors.toList());
+ checkArgument(componentsByUuid.size() == request.getComponentIds().size(), "The following component ids are not found: %s",
+ String.join(", ", difference(request.getComponentIds(), componentUuids)));
return componentsByUuid;
} else {
List<ComponentDto> componentsByKey = searchByComponentKeys(dbSession, request.getComponentKeys());
- checkArgument(componentsByKey.size() == request.getComponentKeys().size(), "Some components are not found in: '%s'", String.join(", ", request.getComponentKeys()));
+ List<String> componentKeys = componentsByKey.stream().map(ComponentDto::key).collect(Collectors.toList());
+ checkArgument(componentsByKey.size() == request.getComponentKeys().size(), "The following component keys are not found: %s",
+ String.join(", ", difference(request.getComponentKeys(), componentKeys)));
return componentsByKey;
}
}
@@ -176,6 +187,15 @@ public class SearchAction implements MeasuresWsAction {
.build());
}
+ private List<String> difference(Collection<String> expected, Collection<String> actual) {
+ Set<String> actualSet = new HashSet<>(actual);
+
+ return expected.stream()
+ .filter(value -> !actualSet.contains(value))
+ .sorted(String::compareTo)
+ .collect(Collectors.toList());
+ }
+
private SearchWsResponse buildResponse() {
requireNonNull(metrics);
requireNonNull(measures);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java
index 9563cf615d5..a9bbb40b7c5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/SearchActionTest.java
@@ -23,9 +23,12 @@ package org.sonar.server.measure.ws;
import com.google.common.base.Throwables;
import java.io.IOException;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ws.WebService;
@@ -37,11 +40,14 @@ import org.sonar.db.component.ComponentDbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto;
import org.sonar.db.metric.MetricDto;
+import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.WsMeasures.Component;
import org.sonarqube.ws.WsMeasures.SearchWsResponse;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.utils.DateUtils.parseDateTime;
@@ -60,6 +66,8 @@ import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_METRIC_
public class SearchActionTest {
@Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
public DbTester db = DbTester.create(System2.INSTANCE);
ComponentDbTester componentDb = new ComponentDbTester(db);
DbClient dbClient = db.getDbClient();
@@ -115,6 +123,128 @@ public class SearchActionTest {
}
@Test
+ public void fail_if_no_metric() {
+ ComponentDto project = componentDb.insertProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The 'metricKeys' parameter is missing");
+
+ callByComponentUuids(singletonList(project.uuid()), null);
+ }
+
+ @Test
+ public void fail_if_empty_metric() {
+ ComponentDto project = componentDb.insertProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Metric keys must be provided");
+
+ callByComponentUuids(singletonList(project.uuid()), emptyList());
+ }
+
+ @Test
+ public void fail_if_unknown_metric() {
+ ComponentDto project = componentDb.insertProject();
+ insertComplexityMetric();
+
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("The following metrics are not found: ncloc, violations");
+
+ callByComponentUuids(singletonList(project.uuid()), newArrayList("violations", "complexity", "ncloc"));
+ }
+
+ @Test
+ public void fail_if_no_component() {
+ insertComplexityMetric();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Either component ids or component keys must be provided, not both");
+
+ call(null, null, singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_empty_component_uuid() {
+ insertComplexityMetric();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Either component ids or component keys must be provided, not both");
+
+ callByComponentUuids(emptyList(), singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_empty_component_key() {
+ insertComplexityMetric();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Either component ids or component keys must be provided, not both");
+
+ callByComponentKeys(emptyList(), singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_unknown_component_uuid() {
+ insertComplexityMetric();
+ ComponentDto project = componentDb.insertProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The following component ids are not found: ANOTHER_PROJECT_ID, YOUR_PROJECT_ID");
+
+ callByComponentUuids(newArrayList("YOUR_PROJECT_ID", project.uuid(), "ANOTHER_PROJECT_ID"), singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_unknown_component_key() {
+ insertComplexityMetric();
+ ComponentDto project = componentDb.insertProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("The following component keys are not found: ANOTHER_PROJECT_KEY, YOUR_PROJECT_KEY");
+
+ callByComponentKeys(newArrayList("YOUR_PROJECT_KEY", project.key(), "ANOTHER_PROJECT_KEY"), singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_component_id_and_key() {
+ ComponentDto project = componentDb.insertProject();
+ ComponentDto anotherProject = componentDb.insertProject();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Either component ids or component keys must be provided, not both");
+
+ call(singletonList(project.uuid()), singletonList(anotherProject.key()), singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_more_than_100_component_id() {
+ List<String> uuids = IntStream.rangeClosed(1, 101)
+ .mapToObj(i -> componentDb.insertProject())
+ .map(ComponentDto::uuid)
+ .collect(Collectors.toList());
+ insertComplexityMetric();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("101 components provided, more than maximum authorized (100)");
+
+ callByComponentUuids(uuids, singletonList("complexity"));
+ }
+
+ @Test
+ public void fail_if_more_than_100_component_key() {
+ List<String> keys = IntStream.rangeClosed(1, 101)
+ .mapToObj(i -> componentDb.insertProject())
+ .map(ComponentDto::key)
+ .collect(Collectors.toList());
+ insertComplexityMetric();
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("101 components provided, more than maximum authorized (100)");
+
+ callByComponentKeys(keys, singletonList("complexity"));
+ }
+
+ @Test
public void definition() {
WebService.Action result = ws.getDef();
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/measure/SearchRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/measure/SearchRequest.java
index ad16a8c3a5b..7beedebec9f 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/measure/SearchRequest.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/measure/SearchRequest.java
@@ -26,6 +26,8 @@ import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
public class SearchRequest {
+ public static final int MAX_NB_COMPONENTS = 100;
+
private final List<String> metricKeys;
private final List<String> componentIds;
private final List<String> componentKeys;
@@ -89,7 +91,13 @@ public class SearchRequest {
checkArgument(
(componentIds != null && !componentIds.isEmpty())
^ (componentKeys != null && !componentKeys.isEmpty()),
- "Either component ids or component keys must be provided, not both.");
+ "Either component ids or component keys must be provided, not both");
+ int nbComponents = componentIds == null ? componentKeys.size() : componentIds.size();
+ checkArgument((componentIds != null && componentIds.size() < MAX_NB_COMPONENTS)
+ || (componentKeys != null && componentKeys.size() < MAX_NB_COMPONENTS),
+ "%s components provided, more than maximum authorized (%s)",
+ nbComponents,
+ MAX_NB_COMPONENTS);
return new SearchRequest(this);
}
}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/measure/SearchRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/measure/SearchRequestTest.java
index 7cffedb9471..ee6de73dfd5 100644
--- a/sonar-ws/src/test/java/org/sonarqube/ws/client/measure/SearchRequestTest.java
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/measure/SearchRequestTest.java
@@ -118,6 +118,6 @@ public class SearchRequestTest {
private void expectExceptionOnComponents() {
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Either component ids or component keys must be provided, not both.");
+ expectedException.expectMessage("Either component ids or component keys must be provided, not both");
}
}