diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-06-01 18:16:21 +0200 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-06-02 14:15:01 +0200 |
commit | 0638cd03da8e0bbb88f670a103a661d0c18540a6 (patch) | |
tree | 8644220aab84aa65acab2e37515c2723ad4a0675 | |
parent | c0f8ed1eca7185bcb63454ba8757a0290721e1dc (diff) | |
download | sonarqube-0638cd03da8e0bbb88f670a103a661d0c18540a6.tar.gz sonarqube-0638cd03da8e0bbb88f670a103a661d0c18540a6.zip |
SONAR-6571 WS api/metrics/create create or reactivate a custom metric
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)) { |