diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-05-22 16:57:17 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-05-26 13:43:06 +0200 |
commit | 3c9e53b57a7d5a20d2f47d0462b53c10a587d250 (patch) | |
tree | 21ca9f923877b6132abb75a1c745351f09078b4a /server | |
parent | 958529665bd6e47b0f0cc43e4a73a3d8ca0f72f4 (diff) | |
download | sonarqube-3c9e53b57a7d5a20d2f47d0462b53c10a587d250.tar.gz sonarqube-3c9e53b57a7d5a20d2f47d0462b53c10a587d250.zip |
WS api/metrics/list - SONAR-6570
Diffstat (limited to 'server')
9 files changed, 445 insertions, 1 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MetricDao.java b/server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MetricDao.java index 97758e56759..32bf681229d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MetricDao.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MetricDao.java @@ -20,15 +20,20 @@ package org.sonar.server.measure.persistence; +import com.google.common.collect.Maps; +import org.apache.ibatis.session.RowBounds; import org.sonar.api.server.ServerSide; import org.sonar.core.measure.db.MetricDto; import org.sonar.core.measure.db.MetricMapper; import org.sonar.core.persistence.DaoComponent; import org.sonar.core.persistence.DbSession; +import org.sonar.server.es.SearchOptions; import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import java.util.List; +import java.util.Map; @ServerSide public class MetricDao implements DaoComponent { @@ -42,6 +47,15 @@ public class MetricDao implements DaoComponent { return session.getMapper(MetricMapper.class).selectAllEnabled(); } + public List<MetricDto> selectEnabled(DbSession session, @Nullable Boolean isCustom, SearchOptions searchOptions) { + Map<String, Object> properties = Maps.newHashMapWithExpectedSize(1); + if (isCustom != null) { + properties.put("isCustom", isCustom); + } + + return session.getMapper(MetricMapper.class).selectAllEnabled(properties, new RowBounds(searchOptions.getOffset(), searchOptions.getLimit())); + } + public void insert(DbSession session, MetricDto dto) { session.getMapper(MetricMapper.class).insert(dto); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ListAction.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ListAction.java new file mode 100644 index 00000000000..9ba67c1f013 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ListAction.java @@ -0,0 +1,128 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.measure.ws; + +import org.sonar.api.measures.Metric; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.api.server.ws.WebService.Param; +import org.sonar.api.utils.text.JsonWriter; +import org.sonar.core.measure.db.MetricDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.MyBatis; +import org.sonar.server.db.DbClient; +import org.sonar.server.es.SearchOptions; + +import javax.annotation.Nullable; + +import java.util.List; +import java.util.Set; + +import static com.google.common.collect.Sets.newHashSet; + +public class ListAction implements MetricsWsAction { + + public static final String PARAM_IS_CUSTOM = "is_custom"; + + public static final String FIELD_ID = "id"; + public static final String FIELD_KEY = "key"; + public static final String FIELD_NAME = "name"; + public static final String FIELD_DESCRIPTION = "description"; + public static final String FIELD_DOMAIN = "domain"; + public static final String FIELD_TYPE = "type"; + private static final Set<String> POSSIBLE_FIELDS = newHashSet(FIELD_ID, FIELD_KEY, FIELD_NAME, FIELD_DESCRIPTION, FIELD_DOMAIN, FIELD_TYPE); + + private final DbClient dbClient; + + public ListAction(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction("list") + .setSince("5.2") + .setResponseExample(getClass().getResource("example-list.json")) + .addPagingParams(100) + .addFieldsParam(POSSIBLE_FIELDS) + .setHandler(this); + + action.createParam(PARAM_IS_CUSTOM) + .setExampleValue("true") + .setDescription("Choose custom metrics following 3 cases:" + + "<ul>" + + "<li>true: only custom metrics are returned</li>" + + "<li>false: only non custom metrics are returned</li>" + + "<li>not specified: all metrics are returned</li>" + + "</ul>"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + SearchOptions searchOptions = new SearchOptions() + .setPage(request.mandatoryParamAsInt(Param.PAGE), + request.mandatoryParamAsInt(Param.PAGE_SIZE)); + Boolean isCustom = request.paramAsBoolean(PARAM_IS_CUSTOM); + DbSession dbSession = dbClient.openSession(false); + try { + List<MetricDto> metrics = dbClient.metricDao().selectEnabled(dbSession, isCustom, searchOptions); + JsonWriter json = response.newJsonWriter(); + json.beginObject(); + Set<String> desiredFields = desiredFields(request.paramAsStrings(Param.FIELDS)); + writeMetrics(json, metrics, desiredFields); + json.endObject(); + json.close(); + } finally { + MyBatis.closeQuietly(dbSession); + } + } + + private Set<String> desiredFields(@Nullable List<String> fields) { + if (fields == null || fields.isEmpty()) { + return POSSIBLE_FIELDS; + } + + return newHashSet(fields); + } + + private void writeMetrics(JsonWriter json, List<MetricDto> metrics, Set<String> desiredFields) { + json.name("metrics"); + json.beginArray(); + for (MetricDto metric : metrics) { + json.beginObject(); + json.prop(FIELD_ID, String.valueOf(metric.getId())); + json.prop(FIELD_KEY, metric.getKey()); + writeIfDesired(json, FIELD_NAME, metric.getShortName(), desiredFields); + writeIfDesired(json, FIELD_DESCRIPTION, metric.getDescription(), desiredFields); + writeIfDesired(json, FIELD_DOMAIN, metric.getDomain(), desiredFields); + writeIfDesired(json, FIELD_TYPE, Metric.ValueType.descriptionOf(metric.getValueType()), desiredFields); + json.endObject(); + } + json.endArray(); + } + + private void writeIfDesired(JsonWriter json, String field, String value, Set<String> desiredFields) { + if (desiredFields.contains(field)) { + json.prop(field, value); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWs.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWs.java index ed34355709b..2f352ef3bc6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWs.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWs.java @@ -25,12 +25,21 @@ import org.sonar.api.server.ws.WebService; public class MetricsWs implements WebService { + private final MetricsWsAction[] actions; + + public MetricsWs(MetricsWsAction... actions) { + this.actions = actions; + } + @Override public void define(Context context) { NewController controller = context.createController("api/metrics"); controller.setDescription("Metrics management"); controller.setSince("2.6"); + for (MetricsWsAction action : actions) { + action.define(controller); + } defineIndexAction(controller); controller.done(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWsAction.java new file mode 100644 index 00000000000..61b28ba802b --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/MetricsWsAction.java @@ -0,0 +1,27 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.measure.ws; + +import org.sonar.server.ws.WsAction; + +public interface MetricsWsAction extends WsAction { + // marker interface +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index a09daf2b385..a7af1692d96 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.platformlevel; -import java.util.List; import org.sonar.api.config.EmailSettings; import org.sonar.api.issue.action.Actions; import org.sonar.api.profiles.AnnotationProfileParser; @@ -291,6 +290,8 @@ import org.sonar.server.view.index.ViewIndexer; import org.sonar.server.ws.ListingWs; import org.sonar.server.ws.WebServiceEngine; +import java.util.List; + public class PlatformLevel4 extends PlatformLevel { private final List<Object> level4AddedComponents; @@ -431,6 +432,7 @@ public class PlatformLevel4 extends PlatformLevel { TimeMachineWs.class, ManualMeasuresWs.class, MetricsWs.class, + org.sonar.server.measure.ws.ListAction.class, // quality gates QualityGateDao.class, diff --git a/server/sonar-server/src/main/resources/org/sonar/server/measure/ws/example-list.json b/server/sonar-server/src/main/resources/org/sonar/server/measure/ws/example-list.json new file mode 100644 index 00000000000..3a7a4ddd8d7 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/measure/ws/example-list.json @@ -0,0 +1,23 @@ +{ + "metrics": [ + { + "id": "23", + "key": "team_size", + "name": "Team size", + "description": "Number of people in the team", + "domain": "Management", + "type": "INT" + }, + { + "id": "2", + "key": "uncovered_lines", + "name": "Uncovered lines", + "description": "Uncovered lines", + "domain": "Tests", + "type": "INT" + } + ], + "total": 2, + "p": 1, + "ps": 100 +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ListActionTest.java new file mode 100644 index 00000000000..4bbcb9b1406 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/ListActionTest.java @@ -0,0 +1,162 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.measure.ws; + +import org.apache.commons.lang.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.server.ws.WebService.Param; +import org.sonar.core.measure.db.MetricDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.DbTester; +import org.sonar.server.db.DbClient; +import org.sonar.server.measure.persistence.MetricDao; +import org.sonar.server.ws.WsTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.server.measure.ws.ListAction.PARAM_IS_CUSTOM; + +public class ListActionTest { + + @ClassRule + public static DbTester db = new DbTester(); + DbClient dbClient; + DbSession dbSession; + WsTester ws; + + @Before + public void setUp() { + dbClient = new DbClient(db.database(), db.myBatis(), new MetricDao()); + dbSession = dbClient.openSession(false); + ws = new WsTester(new MetricsWs(new ListAction(dbClient))); + db.truncateTables(); + } + + @After + public void tearDown() { + dbSession.close(); + } + + @Test + public void list_metrics_in_database() throws Exception { + insertNewCustomMetric("1", "2", "3"); + + WsTester.Result result = newRequest().execute(); + + result.assertJson(getClass(), "list_metrics.json"); + } + + @Test + public void list_metrics_ordered_by_name_case_insensitive() throws Exception { + insertNewCustomMetric("3", "1", "2"); + + String firstResult = newRequest().setParam(Param.PAGE, "1").setParam(Param.PAGE_SIZE, "1").execute().outputAsString(); + String secondResult = newRequest().setParam(Param.PAGE, "2").setParam(Param.PAGE_SIZE, "1").execute().outputAsString(); + String thirdResult = newRequest().setParam(Param.PAGE, "3").setParam(Param.PAGE_SIZE, "1").execute().outputAsString(); + + assertThat(firstResult).contains("custom-key-1").doesNotContain("custom-key-2").doesNotContain("custom-key-3"); + assertThat(secondResult).contains("custom-key-2").doesNotContain("custom-key-1").doesNotContain("custom-key-3"); + assertThat(thirdResult).contains("custom-key-3").doesNotContain("custom-key-1").doesNotContain("custom-key-2"); + } + + @Test + public void list_metrics_with_pagination() throws Exception { + insertNewCustomMetric("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"); + + WsTester.Result result = newRequest() + .setParam(Param.PAGE, "3") + .setParam(Param.PAGE_SIZE, "4") + .execute(); + + assertThat(StringUtils.countMatches(result.outputAsString(), "custom-key")).isEqualTo(2); + } + + @Test + public void list_metric_with_is_custom_true() throws Exception { + insertNewCustomMetric("1", "2"); + insertNewNonCustomMetric("3"); + + String result = newRequest() + .setParam(PARAM_IS_CUSTOM, "true").execute().outputAsString(); + + assertThat(result).contains("custom-key-1", "custom-key-2") + .doesNotContain("non-custom-key-3"); + } + + @Test + public void list_metric_with_is_custom_false() throws Exception { + insertNewCustomMetric("1", "2"); + insertNewNonCustomMetric("3"); + + String result = newRequest() + .setParam(PARAM_IS_CUSTOM, "false").execute().outputAsString(); + + assertThat(result).doesNotContain("custom-key-1") + .doesNotContain("custom-key-2") + .contains("non-custom-key-3"); + } + + @Test + public void list_metric_with_chosen_fields() throws Exception { + insertNewCustomMetric("1"); + + String result = newRequest().setParam(Param.FIELDS, "name").execute().outputAsString(); + + assertThat(result).contains("id", "key", "name") + .doesNotContain("domain") + .doesNotContain("description") + .doesNotContain("type"); + } + + private void insertNewNonCustomMetric(String... ids) { + for (String id : ids) { + dbClient.metricDao().insert(dbSession, MetricTesting.newDto() + .setKey("non-custom-key-" + id) + .setEnabled(true) + .setUserManaged(false)); + } + dbSession.commit(); + } + + private void insertNewCustomMetric(String... ids) { + for (String id : ids) { + dbClient.metricDao().insert(dbSession, newCustomMetric(id)); + } + dbSession.commit(); + } + + private MetricDto newCustomMetric(String id) { + return MetricTesting.newDto() + .setKey("custom-key-" + id) + .setShortName("custom-name-" + id) + .setDomain("custom-domain-" + id) + .setDescription("custom-description-" + id) + .setValueType("INT") + .setUserManaged(true) + .setEnabled(true); + } + + private WsTester.TestRequest newRequest() { + return ws.newGetRequest("api/metrics", "list"); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/measure/ws/MetricTesting.java b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/MetricTesting.java new file mode 100644 index 00000000000..753faf4689c --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/measure/ws/MetricTesting.java @@ -0,0 +1,54 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.server.measure.ws; + +import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang.math.RandomUtils; +import org.sonar.api.measures.Metric; +import org.sonar.core.measure.db.MetricDto; + +public class MetricTesting { + private MetricTesting() { + // static stuff only + } + + public static MetricDto newDto() { + Metric.ValueType[] metricTypes = Metric.ValueType.values(); + return new MetricDto() + .setId(RandomUtils.nextInt()) + .setKey(RandomStringUtils.randomAlphanumeric(64)) + .setShortName(RandomStringUtils.randomAlphanumeric(64)) + .setValueType(metricTypes[RandomUtils.nextInt(metricTypes.length - 1)].name()) + .setDomain(RandomStringUtils.randomAlphanumeric(64)) + .setDescription(RandomStringUtils.randomAlphanumeric(250)) + .setBestValue(RandomUtils.nextDouble()) + .setDeleteHistoricalData(RandomUtils.nextBoolean()) + .setDirection(RandomUtils.nextInt()) + .setHidden(RandomUtils.nextBoolean()) + .setEnabled(RandomUtils.nextBoolean()) + .setOptimizedBestValue(RandomUtils.nextBoolean()) + .setQualitative(RandomUtils.nextBoolean()) + .setOrigin(RandomStringUtils.randomAlphabetic(3)) + .setUserManaged(RandomUtils.nextBoolean()) + .setWorstValue(RandomUtils.nextDouble()); + } + +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/measure/ws/ListActionTest/list_metrics.json b/server/sonar-server/src/test/resources/org/sonar/server/measure/ws/ListActionTest/list_metrics.json new file mode 100644 index 00000000000..4f5049c8aeb --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/measure/ws/ListActionTest/list_metrics.json @@ -0,0 +1,25 @@ +{ + "metrics":[ + { + "key":"custom-key-1", + "name":"custom-name-1", + "type":"Integer", + "domain":"custom-domain-1", + "description":"custom-description-1" + }, + { + "key":"custom-key-2", + "name":"custom-name-2", + "type":"Integer", + "domain":"custom-domain-2", + "description":"custom-description-2" + }, + { + "key":"custom-key-3", + "name":"custom-name-3", + "type":"Integer", + "domain":"custom-domain-3", + "description":"custom-description-3" + } + ] +} |