aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2015-06-01 18:16:21 +0200
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>2015-06-02 14:15:01 +0200
commit0638cd03da8e0bbb88f670a103a661d0c18540a6 (patch)
tree8644220aab84aa65acab2e37515c2723ad4a0675
parentc0f8ed1eca7185bcb63454ba8757a0290721e1dc (diff)
downloadsonarqube-0638cd03da8e0bbb88f670a103a661d0c18540a6.tar.gz
sonarqube-0638cd03da8e0bbb88f670a103a661d0c18540a6.zip
SONAR-6571 WS api/metrics/create create or reactivate a custom metric
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java24
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java196
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/ws/DeleteAction.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java8
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/metric/ws/CreateActionTest.java290
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/metric/ws/DeleteActionTest.java6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/metric/ws/CreateActionTest/metric.json7
-rw-r--r--sonar-core/src/main/java/org/sonar/core/metric/db/MetricMapper.java2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/metric/db/MetricMapper.xml11
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java26
12 files changed, 548 insertions, 28 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
index b77c55704f7..5cd1ae314cc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
@@ -52,7 +52,7 @@ public class PersistDuplicationsStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(true);
try {
- MetricDto duplicationMetric = dbClient.metricDao().selectByKey(session, CoreMetrics.DUPLICATIONS_DATA_KEY);
+ MetricDto duplicationMetric = dbClient.metricDao().selectNullableByKey(session, CoreMetrics.DUPLICATIONS_DATA_KEY);
DuplicationContext duplicationContext = new DuplicationContext(duplicationMetric, session);
int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
recursivelyProcessComponent(duplicationContext, rootComponentRef);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java b/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
index 175592fbff2..32abdb0fa67 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
@@ -44,10 +44,19 @@ import static com.google.common.collect.Lists.newArrayList;
public class MetricDao implements DaoComponent {
@CheckForNull
- public MetricDto selectByKey(DbSession session, String key) {
+ public MetricDto selectNullableByKey(DbSession session, String key) {
return mapper(session).selectByKey(key);
}
+ public List<MetricDto> selectNullableByKeys(final DbSession session, List<String> keys) {
+ return DaoUtils.executeLargeInputs(keys, new Function<List<String>, List<MetricDto>>() {
+ @Override
+ public List<MetricDto> apply(@Nonnull List<String> input) {
+ return mapper(session).selectByKeys(input);
+ }
+ });
+ }
+
public List<MetricDto> selectEnabled(DbSession session) {
return mapper(session).selectAllEnabled();
}
@@ -78,15 +87,6 @@ public class MetricDao implements DaoComponent {
return session.getMapper(MetricMapper.class);
}
- public List<MetricDto> selectByKeys(final DbSession session, List<String> keys) {
- return DaoUtils.executeLargeInputs(keys, new Function<List<String>, List<MetricDto>>() {
- @Override
- public List<MetricDto> apply(@Nonnull List<String> input) {
- return mapper(session).selectByKeys(input);
- }
- });
- }
-
public void disable(final DbSession session, List<Integer> ids) {
DaoUtils.executeLargeInputsWithoutOutput(ids, new Function<List<Integer>, Void>() {
@Override
@@ -100,4 +100,8 @@ public class MetricDao implements DaoComponent {
public int countCustom(DbSession session) {
return mapper(session).countCustom();
}
+
+ public void update(DbSession session, MetricDto metric) {
+ mapper(session).update(metric);
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java
new file mode 100644
index 00000000000..d1511cea26c
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java
@@ -0,0 +1,196 @@
+/*
+ * 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.metric.ws;
+
+import java.net.HttpURLConnection;
+import javax.annotation.Nullable;
+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.utils.text.JsonWriter;
+import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ServerException;
+import org.sonar.server.user.UserSession;
+
+public class CreateAction implements MetricsWsAction {
+ private static final String ACTION = "create";
+ public static final String PARAM_NAME = "name";
+ public static final String PARAM_KEY = "key";
+ public static final String PARAM_TYPE = "type";
+ public static final String PARAM_DESCRIPTION = "description";
+ public static final String PARAM_DOMAIN = "domain";
+
+ private static final String FIELD_ID = "id";
+ private static final String FIELD_NAME = PARAM_NAME;
+ private static final String FIELD_KEY = PARAM_KEY;
+ private static final String FIELD_TYPE = PARAM_TYPE;
+ private static final String FIELD_DESCRIPTION = PARAM_DESCRIPTION;
+ private static final String FIELD_DOMAIN = PARAM_DOMAIN;
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+
+ public CreateAction(DbClient dbClient, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction(ACTION)
+ .setPost(true)
+ .setDescription("Create custom metric.<br /> Requires 'Administer System' permission.")
+ .setSince("5.2")
+ .setHandler(this);
+
+ action.createParam(PARAM_NAME)
+ .setRequired(true)
+ .setDescription("Name")
+ .setExampleValue("Team Size");
+
+ action.createParam(PARAM_KEY)
+ .setRequired(true)
+ .setDescription("Key")
+ .setExampleValue("team_size");
+
+ action.createParam(PARAM_TYPE)
+ .setRequired(true)
+ .setDescription("Metric type key")
+ .setPossibleValues(Metric.ValueType.names())
+ .setExampleValue(Metric.ValueType.INT.name());
+
+ action.createParam(PARAM_DESCRIPTION)
+ .setDescription("Description")
+ .setExampleValue("Size of the team");
+
+ action.createParam(PARAM_DOMAIN)
+ .setDescription("Domain")
+ .setExampleValue("Tests");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ userSession.checkLoggedIn().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+ String key = request.mandatoryParam(PARAM_KEY);
+
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ MetricDto metricTemplate = newMetricTemplate(request);
+ MetricDto metricInDb = dbClient.metricDao().selectNullableByKey(dbSession, key);
+ checkMetricInDbAndTemplate(metricInDb, metricTemplate);
+
+ if (metricInDb == null) {
+ metricInDb = insertNewMetric(dbSession, metricTemplate);
+ } else {
+ updateMetric(dbSession, metricInDb, metricTemplate);
+ }
+
+ JsonWriter json = response.newJsonWriter();
+ writeMetric(json, metricInDb);
+ json.close();
+ } finally {
+ MyBatis.closeQuietly(dbSession);
+ }
+ }
+
+ private MetricDto newMetricTemplate(Request request) {
+ String key = request.mandatoryParam(PARAM_KEY);
+ String name = request.mandatoryParam(PARAM_NAME);
+ String type = Metric.ValueType.valueOf(request.mandatoryParam(PARAM_TYPE)).name();
+ String domain = request.param(PARAM_DOMAIN);
+ String description = request.param(PARAM_DESCRIPTION);
+
+ MetricDto metricTemplate = new MetricDto()
+ .setKey(key)
+ .setShortName(name)
+ .setValueType(type);
+ if (domain != null) {
+ metricTemplate.setDomain(domain);
+ }
+ if (description != null) {
+ metricTemplate.setDescription(description);
+ }
+ return metricTemplate;
+ }
+
+ private void updateMetric(DbSession dbSession, MetricDto metricInDb, MetricDto metricTemplate) {
+ metricInDb
+ .setShortName(metricTemplate.getShortName())
+ .setValueType(metricTemplate.getValueType())
+ .setDomain(metricTemplate.getDomain())
+ .setDescription(metricTemplate.getDescription())
+ .setEnabled(true);
+ dbClient.metricDao().update(dbSession, metricInDb);
+ dbSession.commit();
+ }
+
+ private MetricDto insertNewMetric(DbSession dbSession, MetricDto metricTemplate) {
+ MetricDto metric = new MetricDto()
+ .setKey(metricTemplate.getKey())
+ .setShortName(metricTemplate.getShortName())
+ .setValueType(metricTemplate.getValueType())
+ .setDomain(metricTemplate.getDomain())
+ .setDescription(metricTemplate.getDescription())
+ .setEnabled(true)
+ .setUserManaged(true)
+ .setDirection(0)
+ .setQualitative(false)
+ .setOrigin("GUI");
+
+ dbClient.metricDao().insert(dbSession, metric);
+ dbSession.commit();
+ return metric;
+ }
+
+ private void checkMetricInDbAndTemplate(@Nullable MetricDto metricInDb, MetricDto template) {
+ if (template.getValueType().isEmpty() || template.getShortName().isEmpty() || template.getKey().isEmpty()) {
+ throw new IllegalArgumentException(String.format("The mandatory arguments '%s','%s' and '%s' must not be empty", PARAM_KEY, PARAM_NAME, PARAM_TYPE));
+ }
+ if (metricInDb == null) {
+ return;
+ }
+ if (metricInDb.isEnabled()) {
+ throw new ServerException(HttpURLConnection.HTTP_CONFLICT, "An active metric already exist with key: " + metricInDb.getKey());
+ }
+ if (!metricInDb.isUserManaged()) {
+ throw new ServerException(HttpURLConnection.HTTP_CONFLICT, "An non custom metric already exist with key: " + metricInDb.getKey());
+ }
+ if (!metricInDb.getValueType().equals(template.getValueType())) {
+ throw new ServerException(HttpURLConnection.HTTP_CONFLICT, "An existing metric exist with a different type: " + metricInDb.getValueType());
+ }
+ }
+
+ private void writeMetric(JsonWriter json, MetricDto metric) {
+ json.beginObject();
+ json.prop(FIELD_ID, metric.getId());
+ json.prop(FIELD_KEY, metric.getKey());
+ json.prop(FIELD_NAME, metric.getShortName());
+ json.prop(FIELD_TYPE, metric.getValueType());
+ json.prop(FIELD_DOMAIN, metric.getDomain());
+ json.prop(FIELD_DESCRIPTION, metric.getDescription());
+ json.endObject();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/DeleteAction.java
index 0d06f10d576..95430acaf10 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/DeleteAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/DeleteAction.java
@@ -94,7 +94,7 @@ public class DeleteAction implements MetricsWsAction {
}
});
} else if (keys != null) {
- ids = Lists.transform(dbClient.metricDao().selectByKeys(dbSession, keys), new Function<MetricDto, Integer>() {
+ ids = Lists.transform(dbClient.metricDao().selectNullableByKeys(dbSession, keys), new Function<MetricDto, Integer>() {
@Override
public Integer apply(@Nonnull MetricDto input) {
return input.getId();
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 7e0ace0d843..73972ef1ed7 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
@@ -499,6 +499,8 @@ public class PlatformLevel4 extends PlatformLevel {
org.sonar.server.metric.ws.TypesAction.class,
org.sonar.server.metric.ws.DomainsAction.class,
org.sonar.server.metric.ws.DeleteAction.class,
+ org.sonar.server.metric.ws.CreateAction.class,
+
// quality gates
QualityGateDao.class,
diff --git a/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
index ee5913e8ff1..1f77cf7c866 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
@@ -58,7 +58,7 @@ public class MetricDaoTest {
public void get_by_key() {
dbTester.prepareDbUnit(getClass(), "shared.xml");
- MetricDto result = dao.selectByKey(session, "coverage");
+ MetricDto result = dao.selectNullableByKey(session, "coverage");
assertThat(result.getId()).isEqualTo(2);
assertThat(result.getKey()).isEqualTo("coverage");
assertThat(result.getShortName()).isEqualTo("Coverage");
@@ -77,7 +77,7 @@ public class MetricDaoTest {
assertThat(result.isEnabled()).isTrue();
// Disabled metrics are returned
- result = dao.selectByKey(session, "disabled");
+ result = dao.selectNullableByKey(session, "disabled");
assertThat(result.getId()).isEqualTo(3);
assertThat(result.isEnabled()).isFalse();
}
@@ -86,7 +86,7 @@ public class MetricDaoTest {
public void get_manual_metric() {
dbTester.prepareDbUnit(getClass(), "manual_metric.xml");
- MetricDto result = dao.selectByKey(session, "manual");
+ MetricDto result = dao.selectNullableByKey(session, "manual");
assertThat(result.getId()).isEqualTo(1);
assertThat(result.getKey()).isEqualTo("manual");
assertThat(result.getShortName()).isEqualTo("Manual metric");
@@ -132,7 +132,7 @@ public class MetricDaoTest {
.setDeleteHistoricalData(true)
.setEnabled(true));
- MetricDto result = dao.selectByKey(session, "coverage");
+ MetricDto result = dao.selectNullableByKey(session, "coverage");
assertThat(result.getId()).isNotNull();
assertThat(result.getKey()).isEqualTo("coverage");
assertThat(result.getShortName()).isEqualTo("Coverage");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/metric/ws/CreateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/metric/ws/CreateActionTest.java
new file mode 100644
index 00000000000..d1daf99d554
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/metric/ws/CreateActionTest.java
@@ -0,0 +1,290 @@
+/*
+ * 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.metric.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.measures.Metric.ValueType;
+import org.sonar.core.metric.db.MetricDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.ServerException;
+import org.sonar.server.metric.persistence.MetricDao;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsTester;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.metric.ws.CreateAction.PARAM_DESCRIPTION;
+import static org.sonar.server.metric.ws.CreateAction.PARAM_DOMAIN;
+import static org.sonar.server.metric.ws.CreateAction.PARAM_KEY;
+import static org.sonar.server.metric.ws.CreateAction.PARAM_NAME;
+import static org.sonar.server.metric.ws.CreateAction.PARAM_TYPE;
+
+@Category(DbTests.class)
+public class CreateActionTest {
+
+ private static final String DEFAULT_KEY = "custom-metric-key";
+ private static final String DEFAULT_NAME = "custom-metric-name";
+ private static final String DEFAULT_DOMAIN = "custom-metric-domain";
+ private static final String DEFAULT_DESCRIPTION = "custom-metric-description";
+ private static final String DEFAULT_TYPE = ValueType.INT.name();
+
+ @ClassRule
+ public static DbTester db = new DbTester();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ WsTester ws;
+ DbClient dbClient;
+ DbSession dbSession;
+
+ @Before
+ public void setUp() {
+ dbClient = new DbClient(db.database(), db.myBatis(), new MetricDao());
+ dbSession = dbClient.openSession(false);
+ db.truncateTables();
+
+ ws = new WsTester(new MetricsWs(new CreateAction(dbClient, userSessionRule)));
+ userSessionRule.login("login").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ @After
+ public void tearDown() {
+ dbSession.close();
+ }
+
+ @Test
+ public void insert_new_minimalist_metric() throws Exception {
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .execute();
+
+ MetricDto metric = dbClient.metricDao().selectNullableByKey(dbSession, DEFAULT_KEY);
+
+ assertThat(metric.getKey()).isEqualTo(DEFAULT_KEY);
+ assertThat(metric.getShortName()).isEqualTo(DEFAULT_NAME);
+ assertThat(metric.getValueType()).isEqualTo(DEFAULT_TYPE);
+ assertThat(metric.getDescription()).isNull();
+ assertThat(metric.getDomain()).isNull();
+ assertThat(metric.isUserManaged()).isTrue();
+ assertThat(metric.isEnabled()).isTrue();
+ assertThat(metric.getDirection()).isEqualTo(0);
+ assertThat(metric.isQualitative()).isFalse();
+ assertThat(metric.getOrigin()).isEqualTo("GUI");
+ }
+
+ @Test
+ public void insert_new_full_metric() throws Exception {
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .setParam(PARAM_DOMAIN, DEFAULT_DOMAIN)
+ .setParam(PARAM_DESCRIPTION, DEFAULT_DESCRIPTION)
+ .execute();
+
+ MetricDto metric = dbClient.metricDao().selectNullableByKey(dbSession, DEFAULT_KEY);
+
+ assertThat(metric.getKey()).isEqualTo(DEFAULT_KEY);
+ assertThat(metric.getDescription()).isEqualTo(DEFAULT_DESCRIPTION);
+ assertThat(metric.getDomain()).isEqualTo(DEFAULT_DOMAIN);
+ }
+
+ @Test
+ public void return_metric_with_id() throws Exception {
+ WsTester.Result result = newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .setParam(PARAM_DOMAIN, DEFAULT_DOMAIN)
+ .setParam(PARAM_DESCRIPTION, DEFAULT_DESCRIPTION)
+ .execute();
+
+ result.assertJson(getClass(), "metric.json");
+ result.outputAsString().matches("\"id\"\\s*:\\s*\"\\w+\"");
+ }
+
+ @Test
+ public void update_existing_metric_when_custom_and_disabled() throws Exception {
+ MetricDto metricInDb = MetricTesting.newMetricDto()
+ .setKey(DEFAULT_KEY)
+ .setValueType(DEFAULT_TYPE)
+ .setUserManaged(true)
+ .setEnabled(false);
+ dbClient.metricDao().insert(dbSession, metricInDb);
+ dbSession.commit();
+
+ WsTester.Result result = newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .setParam(PARAM_DESCRIPTION, DEFAULT_DESCRIPTION)
+ .setParam(PARAM_DOMAIN, DEFAULT_DOMAIN)
+ .execute();
+
+ result.assertJson(getClass(), "metric.json");
+ result.outputAsString().matches("\"id\"\\s*:\\s*\"" + metricInDb.getId() + "\"");
+ MetricDto metricAfterWs = dbClient.metricDao().selectNullableByKey(dbSession, DEFAULT_KEY);
+ assertThat(metricAfterWs.getId()).isEqualTo(metricInDb.getId());
+ assertThat(metricAfterWs.getDomain()).isEqualTo(DEFAULT_DOMAIN);
+ assertThat(metricAfterWs.getDescription()).isEqualTo(DEFAULT_DESCRIPTION);
+ assertThat(metricAfterWs.getValueType()).isEqualTo(DEFAULT_TYPE);
+ assertThat(metricAfterWs.getShortName()).isEqualTo(DEFAULT_NAME);
+ }
+
+ @Test
+ public void fail_when_existing_activated_metric_with_same_key() throws Exception {
+ expectedException.expect(ServerException.class);
+ dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
+ .setKey(DEFAULT_KEY)
+ .setValueType(DEFAULT_TYPE)
+ .setUserManaged(true)
+ .setEnabled(true));
+ dbSession.commit();
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, "any-name")
+ .setParam(PARAM_TYPE, DEFAULT_TYPE).execute();
+ }
+
+ @Test
+ public void fail_when_existing_non_custom_metric_with_same_key() throws Exception {
+ expectedException.expect(ServerException.class);
+ dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
+ .setKey(DEFAULT_KEY)
+ .setValueType(DEFAULT_TYPE)
+ .setUserManaged(false)
+ .setEnabled(false));
+ dbSession.commit();
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, "any-name")
+ .setParam(PARAM_TYPE, DEFAULT_TYPE).execute();
+ }
+
+ @Test
+ public void fail_when_metric_type_is_changed() throws Exception {
+ expectedException.expect(ServerException.class);
+ dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
+ .setKey(DEFAULT_KEY)
+ .setValueType(ValueType.BOOL.name())
+ .setUserManaged(true)
+ .setEnabled(false)
+ );
+ dbSession.commit();
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, "any-name")
+ .setParam(PARAM_TYPE, ValueType.INT.name())
+ .execute();
+ }
+
+ @Test
+ public void fail_when_missing_key() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE).execute();
+ }
+
+ @Test
+ public void fail_when_missing_name() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE).execute();
+ }
+
+ @Test
+ public void fail_when_missing_type() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_KEY, DEFAULT_KEY).execute();
+ }
+
+ @Test
+ public void fail_when_insufficient_privileges() throws Exception {
+ expectedException.expect(ForbiddenException.class);
+ userSessionRule.login("login");
+
+ newRequest()
+ .setParam(PARAM_KEY, "any-key")
+ .setParam(PARAM_NAME, "any-name")
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .execute();
+ }
+
+ @Test
+ public void fail_when_empty_key() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_KEY, "")
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .execute();
+ }
+
+ @Test
+ public void fail_when_empty_name() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, "")
+ .setParam(PARAM_TYPE, DEFAULT_TYPE)
+ .execute();
+ }
+
+ @Test
+ public void fail_when_empty_type() throws Exception {
+ expectedException.expect(IllegalArgumentException.class);
+
+ newRequest()
+ .setParam(PARAM_KEY, DEFAULT_KEY)
+ .setParam(PARAM_NAME, DEFAULT_NAME)
+ .setParam(PARAM_TYPE, "")
+ .execute();
+ }
+
+ private WsTester.TestRequest newRequest() {
+ return ws.newPostRequest("api/metrics", "create");
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/metric/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/metric/ws/DeleteActionTest.java
index ddbc0fb5287..a72f8fc2508 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/metric/ws/DeleteActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/metric/ws/DeleteActionTest.java
@@ -83,9 +83,9 @@ public class DeleteActionTest {
newRequest().setParam("keys", "key-1, key-3").execute();
dbSession.commit();
- List<MetricDto> disabledMetrics = metricDao.selectByKeys(dbSession, Arrays.asList("key-1", "key-3"));
+ List<MetricDto> disabledMetrics = metricDao.selectNullableByKeys(dbSession, Arrays.asList("key-1", "key-3"));
assertThat(disabledMetrics).extracting("enabled").containsOnly(false);
- assertThat(metricDao.selectByKey(dbSession, "key-2").isEnabled()).isTrue();
+ assertThat(metricDao.selectNullableByKey(dbSession, "key-2").isEnabled()).isTrue();
}
@Test
@@ -109,7 +109,7 @@ public class DeleteActionTest {
newRequest().setParam("keys", "key-1").execute();
dbSession.commit();
- MetricDto metric = metricDao.selectByKey(dbSession, "key-1");
+ MetricDto metric = metricDao.selectNullableByKey(dbSession, "key-1");
assertThat(metric.isEnabled()).isTrue();
}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/metric/ws/CreateActionTest/metric.json b/server/sonar-server/src/test/resources/org/sonar/server/metric/ws/CreateActionTest/metric.json
new file mode 100644
index 00000000000..ac8905bea70
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/metric/ws/CreateActionTest/metric.json
@@ -0,0 +1,7 @@
+{
+ "key": "custom-metric-key",
+ "name": "custom-metric-name",
+ "type": "INT",
+ "domain": "custom-metric-domain",
+ "description": "custom-metric-description"
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/metric/db/MetricMapper.java b/sonar-core/src/main/java/org/sonar/core/metric/db/MetricMapper.java
index dc85301383a..360c5c40ded 100644
--- a/sonar-core/src/main/java/org/sonar/core/metric/db/MetricMapper.java
+++ b/sonar-core/src/main/java/org/sonar/core/metric/db/MetricMapper.java
@@ -42,4 +42,6 @@ public interface MetricMapper {
void disable(@Param("ids") List<Integer> ids);
int countCustom();
+
+ void update(MetricDto metric);
}
diff --git a/sonar-core/src/main/resources/org/sonar/core/metric/db/MetricMapper.xml b/sonar-core/src/main/resources/org/sonar/core/metric/db/MetricMapper.xml
index e8a121e6d9f..c95ddd0e931 100644
--- a/sonar-core/src/main/resources/org/sonar/core/metric/db/MetricMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/metric/db/MetricMapper.xml
@@ -71,6 +71,17 @@
)
</insert>
+ <update id="update" parameterType="org.sonar.core.metric.db.MetricDto">
+ update metrics
+ set
+ enabled=#{enabled, jdbcType=BOOLEAN},
+ short_name=#{shortName, jdbcType=VARCHAR},
+ val_type=#{valueType, jdbcType=VARCHAR},
+ domain=#{domain, jdbcType=VARCHAR},
+ description=#{description, jdbcType=VARCHAR}
+ where id=#{id}
+ </update>
+
<select id="selectDomains" resultType="String">
select distinct domain
from metrics m
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
index 6c98862765d..33e87d13232 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/Metric.java
@@ -19,13 +19,7 @@
*/
package org.sonar.api.measures;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.batch.InstantiationStrategy;
-import org.sonar.api.server.ServerSide;
-
+import java.io.Serializable;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.persistence.Column;
@@ -36,8 +30,12 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
-
-import java.io.Serializable;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.batch.InstantiationStrategy;
+import org.sonar.api.server.ServerSide;
/**
* This class represents the definition of a metric in Sonar.
@@ -93,6 +91,16 @@ public class Metric<G extends Serializable> implements Serializable, org.sonar.a
return description;
}
+ public static String[] names() {
+ ValueType[] values = values();
+ String[] names = new String[values.length];
+ for (int i = 0; i < values.length; i += 1) {
+ names[i] = values[i].name();
+ }
+
+ return names;
+ }
+
public static String descriptionOf(String key) {
for (ValueType valueType : values()) {
if (valueType.name().equals(key)) {