]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6620 MetricRepository now loads all metrics at startup
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 11 Jun 2015 12:26:49 +0000 (14:26 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 15 Jun 2015 11:07:53 +0000 (13:07 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricRepositoryImpl.java
server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricDtoToMetricTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricRepositoryImplTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/metric/MetricRepositoryImplTest/shared.xml [new file with mode: 0644]

diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java b/server/sonar-server/src/main/java/org/sonar/server/computation/metric/MetricDtoToMetric.java
new file mode 100644 (file)
index 0000000..39c2860
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.computation.metric;
+
+import com.google.common.base.Function;
+import javax.annotation.Nonnull;
+import org.sonar.core.metric.db.MetricDto;
+
+enum MetricDtoToMetric implements Function<MetricDto, Metric> {
+  INSTANCE;
+
+  @Override
+  @Nonnull
+  public Metric apply(@Nonnull MetricDto metricDto) {
+    return new MetricImpl(
+      metricDto.getId(), metricDto.getKey(), metricDto.getShortName(),
+      Metric.MetricType.valueOf(metricDto.getValueType()));
+  }
+}
index 4e04de2b2afaed550795ff24f013ffa2cd4ae48e..3307bc40cb90cfc946c037a7d578f1d69a4b29f2 100644 (file)
  */
 package org.sonar.server.computation.metric;
 
+import com.google.common.base.Function;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.picocontainer.Startable;
 import org.sonar.core.metric.db.MetricDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.DbClient;
 
+import static com.google.common.collect.FluentIterable.from;
 import static java.util.Objects.requireNonNull;
 
-public class MetricRepositoryImpl implements MetricRepository {
+public class MetricRepositoryImpl implements MetricRepository, Startable {
   private final DbClient dbClient;
+  @CheckForNull
+  private Map<String, Metric> metricsByKey;
+  @CheckForNull
+  private Map<Long, Metric> metricsById;
 
   public MetricRepositoryImpl(DbClient dbClient) {
     this.dbClient = dbClient;
   }
 
+  @Override
+  public void start() {
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      List<MetricDto> metricList = dbClient.metricDao().selectEnabled(dbSession);
+      this.metricsByKey = from(metricList).transform(MetricDtoToMetric.INSTANCE).uniqueIndex(MetricToKey.INSTANCE);
+      this.metricsById = from(metricList).transform(MetricDtoToMetric.INSTANCE).uniqueIndex(MetricToId.INSTANCE);
+    }
+  }
+
+  @Override
+  public void stop() {
+    // nothing to do when stopping
+  }
+
   @Override
   public Metric getByKey(String key) {
     requireNonNull(key);
+    verifyMetricsInitialized();
 
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      MetricDto metricDto = dbClient.metricDao().selectNullableByKey(dbSession, key);
-      if (metricDto == null) {
-        throw new IllegalStateException(String.format("Metric with key '%s' does not exist", key));
-      }
-
-      return toMetric(metricDto);
+    Metric res = this.metricsByKey.get(key);
+    if (res == null) {
+      throw new IllegalStateException(String.format("Metric with key '%s' does not exist", key));
     }
+    return res;
   }
 
   @Override
   public Metric getById(long id) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      MetricDto metricDto = dbClient.metricDao().selectNullableById(dbSession, id);
-      if (metricDto == null) {
-        throw new IllegalStateException(String.format("Metric with id '%s' does not exist", id));
-      }
+    verifyMetricsInitialized();
+
+    Metric res = this.metricsById.get(id);
+    if (res == null) {
+      throw new IllegalStateException(String.format("Metric with id '%s' does not exist", id));
+    }
+    return res;
+  }
+
+  private void verifyMetricsInitialized() {
+    if (this.metricsByKey == null) {
+      throw new IllegalStateException("Metric cache has not been initialized");
+    }
+  }
+
+  private enum MetricToKey implements Function<Metric, String> {
+    INSTANCE;
 
-      return toMetric(metricDto);
+    @Override
+    @Nonnull
+    public String apply(@Nonnull Metric metric) {
+      return metric.getKey();
     }
   }
 
-  private static Metric toMetric(MetricDto metricDto) {
-    return new MetricImpl(metricDto.getId(), metricDto.getKey(), metricDto.getShortName(), Metric.MetricType.valueOf(metricDto.getValueType()));
+  private enum MetricToId implements Function<Metric, Long> {
+    INSTANCE;
+
+    @Override
+    @Nonnull
+    public Long apply(@Nonnull Metric metric) {
+      return (long) metric.getId();
+    }
   }
 
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricDtoToMetricTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/metric/MetricDtoToMetricTest.java
new file mode 100644 (file)
index 0000000..9bca629
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.computation.metric;
+
+import org.junit.Test;
+import org.sonar.core.metric.db.MetricDto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MetricDtoToMetricTest {
+
+  private MetricDtoToMetric underTest = MetricDtoToMetric.INSTANCE;
+
+  @Test(expected = NullPointerException.class)
+  public void apply_throws_NPE_if_arg_is_null() {
+    underTest.apply(null);
+  }
+
+  @Test
+  public void verify_mapping_from_dto() {
+
+    for (Metric.MetricType metricType : Metric.MetricType.values()) {
+      MetricDto metricDto = createMetricDto(metricType);
+      Metric metric = underTest.apply(metricDto);
+
+      assertThat(metric.getId()).isEqualTo(metricDto.getId());
+      assertThat(metric.getKey()).isEqualTo(metricDto.getKey());
+      assertThat(metric.getName()).isEqualTo(metricDto.getShortName());
+      assertThat(metric.getType()).isEqualTo(metricType);
+    }
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void apply_throws_IAE_if_valueType_can_not_be_parsed() {
+    underTest.apply(new MetricDto().setId(1).setKey("key").setValueType("trololo"));
+  }
+
+  private static MetricDto createMetricDto(Metric.MetricType metricType) {
+    return new MetricDto()
+        .setId(metricType.name().hashCode())
+        .setKey(metricType.name() + "_key")
+        .setShortName(metricType.name() + "_name")
+        .setValueType(metricType.name())
+        .setEnabled(true);
+  }
+}
index e47c5adc2d441f60d2f2885f6beb99f1523f8be8..e37b02cae191973ece7bfe3c2c79549798c75366 100644 (file)
  */
 package org.sonar.server.computation.metric;
 
-import javax.annotation.CheckForNull;
-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.sonar.core.metric.db.MetricDto;
-import org.sonar.core.persistence.DbSession;
+import org.junit.rules.ExpectedException;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.metric.persistence.MetricDao;
@@ -36,71 +34,99 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 @Category(DbTests.class)
 public class MetricRepositoryImplTest {
-  private static final String SOME_KEY = "some key";
-  private static final String SOME_NAME = "the short name";
+  private static final String SOME_KEY = "some_key";
+  private static final long SOME_ID = 156;
 
   @ClassRule
   public static final DbTester dbTester = new DbTester();
+  @Rule
+  public final ExpectedException expectedException = ExpectedException.none();
 
   private DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MetricDao());
-  private MetricRepository underTest = new MetricRepositoryImpl(dbClient);
-
-  @CheckForNull
-  private DbSession dbSession;
+  private MetricRepositoryImpl underTest = new MetricRepositoryImpl(dbClient);
 
   @Before
   public void setUp() throws Exception {
     dbTester.truncateTables();
   }
 
-  @After
-  public void tearDown() throws Exception {
-    if (dbSession != null) {
-      dbSession.close();
-    }
-  }
-
   @Test(expected = NullPointerException.class)
-  public void findByKey_throws_NPE_if_arg_is_null() {
+  public void getByKey_throws_NPE_if_arg_is_null() {
     underTest.getByKey(null);
   }
 
-  @Test(expected = IllegalStateException.class)
-  public void findByKey_throws_ISE_of_Metric_does_not_exist() {
+  @Test
+  public void getByKey_throws_ISE_if_start_has_not_been_called() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Metric cache has not been initialized");
+
     underTest.getByKey(SOME_KEY);
   }
 
   @Test
-  public void verify_mapping_and_valueType_conversion_from_DB() {
-    dbSession = dbClient.openSession(false);
+  public void getByKey_throws_ISE_of_Metric_does_not_exist() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(String.format("Metric with key '%s' does not exist", SOME_KEY));
 
-    for (Metric.MetricType metricType : Metric.MetricType.values()) {
-      verify_mapping_and_valueType_conversion_from_DB_impl(metricType.name(), metricType);
-    }
+    underTest.start();
+    underTest.getByKey(SOME_KEY);
   }
 
-  private void verify_mapping_and_valueType_conversion_from_DB_impl(String valueType, Metric.MetricType expected) {
-    MetricDto metricDto = new MetricDto().setId(SOME_KEY.hashCode()).setKey(SOME_KEY + valueType).setShortName(SOME_NAME).setValueType(valueType);
+  @Test
+  public void getByKey_throws_ISE_of_Metric_is_disabled() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(String.format("Metric with key '%s' does not exist", "complexity"));
 
-    dbClient.metricDao().insert(dbSession, metricDto);
-    dbSession.commit();
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
 
-    Metric metric = underTest.getByKey(metricDto.getKey());
+    underTest.start();
+    underTest.getByKey("complexity");
+  }
+
+  @Test
+  public void getByKey_find_enabled_Metrics() {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
 
-    assertThat(metric.getId()).isEqualTo(metricDto.getId());
-    assertThat(metric.getKey()).isEqualTo(metricDto.getKey());
-    assertThat(metric.getName()).isEqualTo(metricDto.getShortName());
-    assertThat(metric.getType()).isEqualTo(expected);
+    underTest.start();
+    assertThat(underTest.getByKey("ncloc").getId()).isEqualTo(1);
+    assertThat(underTest.getByKey("coverage").getId()).isEqualTo(2);
   }
 
-  @Test(expected = IllegalArgumentException.class)
-  public void findByKey_throws_IAE_if_valueType_can_not_be_parsed() {
-    MetricDto metricDto = new MetricDto().setKey(SOME_KEY).setShortName(SOME_NAME).setValueType("trololo");
+  @Test
+  public void getById_throws_ISE_if_start_has_not_been_called() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage("Metric cache has not been initialized");
 
-    dbSession = dbClient.openSession(false);
-    dbClient.metricDao().insert(dbSession, metricDto);
-    dbSession.commit();
+    underTest.getById(SOME_ID);
+  }
 
-    underTest.getByKey(SOME_KEY);
+  @Test
+  public void getById_throws_ISE_of_Metric_does_not_exist() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(String.format("Metric with id '%s' does not exist", SOME_ID));
+
+    underTest.start();
+    underTest.getById(SOME_ID);
+  }
+
+  @Test
+  public void getById_throws_ISE_of_Metric_is_disabled() {
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(String.format("Metric with id '%s' does not exist", 3));
+
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    underTest.start();
+    underTest.getById(3);
+  }
+
+  @Test
+  public void getById_find_enabled_Metrics() {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    underTest.start();
+    assertThat(underTest.getById(1).getKey()).isEqualTo("ncloc");
+    assertThat(underTest.getById(2).getKey()).isEqualTo("coverage");
   }
+
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/metric/MetricRepositoryImplTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/metric/MetricRepositoryImplTest/shared.xml
new file mode 100644 (file)
index 0000000..49bb459
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+    <!-- enabled metrics -->
+    <metrics id="1" name="ncloc" VAL_TYPE="INT" short_name="ncloc_name" enabled="[true]" />
+    <metrics id="2" name="coverage" VAL_TYPE="INT" short_name="coverage_name" enabled="[true]" />
+    <!-- disabled metric -->
+    <metrics id="3" name="complexity" VAL_TYPE="INT" short_name="complexity_name" enabled="[false]" />
+</dataset>