]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5338 Read test info from the test_data measure
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 16 Jul 2014 10:10:13 +0000 (12:10 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 16 Jul 2014 10:10:27 +0000 (12:10 +0200)
server/sonar-server/src/main/java/org/sonar/server/measure/persistence/MeasureDao.java
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsShowAction.java
server/sonar-server/src/test/java/org/sonar/server/measure/persistence/MeasureDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsShowActionTest.java
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java
server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsShowActionTest/show_from_test_data.json [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/measure/db/MeasureMapper.java
sonar-core/src/main/resources/org/sonar/core/measure/db/MeasureMapper.xml

index 7fbed57dc0fadc3e3031e73c9b98bebfe149b7d2..80b279ec1cbb9f1ecba03749d05313a30c37aca8 100644 (file)
@@ -69,6 +69,10 @@ public class MeasureDao extends BaseDao<MeasureMapper, MeasureDto, MeasureKey> i
     return dtos;
   }
 
+  public MeasureDto findByComponentKeyAndMetricKey(String componentKey, String metricKey, DbSession session) {
+    return session.getMapper(MeasureMapper.class).selectByComponentAndMetric(componentKey, metricKey);
+  }
+
   @Override
   protected MeasureDto doInsert(DbSession session, MeasureDto item) {
     throw notImplemented();
index 581dad7a90bea67651be792b6a629c2a2ea45b73..117a3b25c54588db6147861a3bde7c59bfd62738 100644 (file)
 package org.sonar.server.test.ws;
 
 import com.google.common.io.Resources;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
@@ -30,15 +34,27 @@ import org.sonar.api.test.TestCase;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
 import org.sonar.server.user.UserSession;
 
+import javax.annotation.CheckForNull;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.StringReader;
+
 public class TestsShowAction implements RequestHandler {
 
   private static final String KEY = "key";
 
+  private final DbClient dbClient;
   private final SnapshotPerspectives snapshotPerspectives;
 
-  public TestsShowAction(SnapshotPerspectives snapshotPerspectives) {
+  public TestsShowAction(DbClient dbClient, SnapshotPerspectives snapshotPerspectives) {
+    this.dbClient = dbClient;
     this.snapshotPerspectives = snapshotPerspectives;
   }
 
@@ -61,15 +77,20 @@ public class TestsShowAction implements RequestHandler {
     String fileKey = request.mandatoryParam(KEY);
     UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
 
-    MutableTestPlan testPlan = snapshotPerspectives.as(MutableTestPlan.class, fileKey);
+    String testData = findTestData(fileKey);
     JsonWriter json = response.newJsonWriter().beginObject();
-    if (testPlan != null) {
-      writeTests(testPlan, json);
+    if (testData != null) {
+      writeFromTestData(testData, json);
+    } else {
+      MutableTestPlan testPlan = snapshotPerspectives.as(MutableTestPlan.class, fileKey);
+      if (testPlan != null) {
+        writeFromTestable(testPlan, json);
+      }
     }
     json.endObject().close();
   }
 
-  private void writeTests(MutableTestPlan testPlan, JsonWriter json) {
+  private void writeFromTestable(MutableTestPlan testPlan, JsonWriter json) {
     json.name("tests").beginArray();
     for (TestCase testCase : testPlan.testCases()) {
       json.beginObject();
@@ -84,4 +105,60 @@ public class TestsShowAction implements RequestHandler {
     json.endArray();
   }
 
+  private void writeFromTestData(String data, JsonWriter json) {
+    SMInputFactory inputFactory = initStax();
+    try {
+      SMHierarchicCursor root = inputFactory.rootElementCursor(new StringReader(data));
+      root.advance(); // tests-details
+      SMInputCursor cursor = root.childElementCursor();
+      json.name("tests").beginArray();
+      while (cursor.getNext() != null) {
+        json.beginObject();
+
+        json.prop("name", cursor.getAttrValue("name"));
+        json.prop("status", cursor.getAttrValue("status").toUpperCase());
+        json.prop("durationInMs", cursor.getAttrValue("time"));
+
+        SMInputCursor errorCursor = cursor.childElementCursor();
+        if (errorCursor.getNext() != null) {
+          json.prop("message", errorCursor.getAttrValue("message"));
+
+          SMInputCursor stackTraceCursor = cursor.childElementCursor();
+          if (stackTraceCursor.getNext() != null) {
+//            json.prop("stackTrace", stackTraceCursor.getAttrValue(""));
+          }
+        }
+
+        json.endObject();
+      }
+      json.endArray();
+    } catch (XMLStreamException e) {
+      throw new IllegalStateException("XML is not valid: " + e.getMessage(), e);
+    }
+  }
+
+  @CheckForNull
+  private String findTestData(String fileKey) {
+    DbSession session = dbClient.openSession(false);
+    try {
+      MeasureDto testData = dbClient.measureDao().findByComponentKeyAndMetricKey(fileKey, CoreMetrics.TEST_DATA_KEY, session);
+      if (testData != null) {
+        return testData.getData();
+      }
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+    return null;
+  }
+
+  private SMInputFactory initStax() {
+    XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
+    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+    // just so it won't try to load DTD in if there's DOCTYPE
+    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+    return new SMInputFactory(xmlFactory);
+  }
+
 }
index 15afbb3bdadd5e06bdde80bdb6e2489f47aee7f1..a93f066059d181eb03d427f1330c4be2c064f87c 100644 (file)
@@ -100,6 +100,23 @@ public class MeasureDaoTest extends AbstractDaoTestCase {
     assertThat(result.getVariation(5)).isEqualTo(-5d);
   }
 
+  @Test
+  public void find_by_component_key_and_metric() throws Exception {
+    setupData("shared");
+
+    MeasureDto result = dao.findByComponentKeyAndMetricKey("org.struts:struts-core:src/org/struts/RequestContext.java", "ncloc", session);
+    assertThat(result.getId()).isEqualTo(22);
+    assertThat(result.getValue()).isEqualTo(10d);
+    assertThat(result.getKey()).isEqualTo(MeasureKey.of("org.struts:struts-core:src/org/struts/RequestContext.java", "ncloc"));
+    assertThat(result.getVariation(1)).isEqualTo(1d);
+    assertThat(result.getVariation(2)).isEqualTo(2d);
+    assertThat(result.getVariation(3)).isEqualTo(3d);
+    assertThat(result.getVariation(4)).isEqualTo(4d);
+    assertThat(result.getVariation(5)).isEqualTo(-5d);
+
+    assertThat(dao.findByComponentKeyAndMetricKey("org.struts:struts-core:src/org/struts/RequestContext.java", "unknown", session)).isNull();
+  }
+
   @Test
   public void exists_by_key() throws Exception {
     setupData("shared");
index 80e9617d6ca66fcfd1ddf656bc5663af84d799f8..07f9be4ab61c69eefd3c496a462c2232191170b3 100644 (file)
@@ -21,6 +21,7 @@
 package org.sonar.server.test.ws;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -30,6 +31,11 @@ import org.sonar.api.test.MutableTestPlan;
 import org.sonar.api.test.TestCase;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.core.measure.db.MeasureDto;
+import org.sonar.core.measure.db.MeasureKey;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.measure.persistence.MeasureDao;
 import org.sonar.server.user.MockUserSession;
 import org.sonar.server.ws.WsTester;
 
@@ -44,29 +50,42 @@ public class TestsShowActionTest {
 
   static final String TEST_PLAN_KEY = "src/test/java/org/foo/BarTest.java";
 
+  @Mock
+  DbSession session;
+
+  @Mock
+  MeasureDao measureDao;
+
   @Mock
   MutableTestPlan testPlan;
 
+  @Mock
+  SnapshotPerspectives snapshotPerspectives;
+
   WsTester tester;
 
   @Before
   public void setUp() throws Exception {
-    SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
-    when(snapshotPerspectives.as(MutableTestPlan.class, TEST_PLAN_KEY)).thenReturn(testPlan);
-    tester = new WsTester(new TestsWs(new TestsShowAction(snapshotPerspectives), mock(TestsTestCasesAction.class), mock(TestsCoveredFilesAction.class)));
+    DbClient dbClient = mock(DbClient.class);
+    when(dbClient.openSession(false)).thenReturn(session);
+    when(dbClient.measureDao()).thenReturn(measureDao);
+
+    tester = new WsTester(new TestsWs(new TestsShowAction(dbClient, snapshotPerspectives), mock(TestsTestCasesAction.class), mock(TestsCoveredFilesAction.class)));
   }
 
   @Test
   public void show() throws Exception {
     MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
 
+    when(snapshotPerspectives.as(MutableTestPlan.class, TEST_PLAN_KEY)).thenReturn(testPlan);
+
     MutableTestCase testCase1 = testCase("test1", TestCase.Status.OK, 10L, 32, null, null);
     MutableTestCase testCase2 = testCase("test2", TestCase.Status.ERROR, 97L, 21, "expected:<true> but was:<false>",
       "java.lang.AssertionError: expected:<true> but was:<false>\n\t" +
-      "at org.junit.Assert.fail(Assert.java:91)\n\t" +
-      "at org.junit.Assert.failNotEquals(Assert.java:645)\n\t" +
-      "at org.junit.Assert.assertEquals(Assert.java:126)\n\t" +
-      "at org.junit.Assert.assertEquals(Assert.java:145)\n");
+        "at org.junit.Assert.fail(Assert.java:91)\n\t" +
+        "at org.junit.Assert.failNotEquals(Assert.java:645)\n\t" +
+        "at org.junit.Assert.assertEquals(Assert.java:126)\n\t" +
+        "at org.junit.Assert.assertEquals(Assert.java:145)\n");
     when(testPlan.testCases()).thenReturn(newArrayList(testCase1, testCase2));
 
     WsTester.TestRequest request = tester.newGetRequest("api/tests", "show").setParam("key", TEST_PLAN_KEY);
@@ -74,6 +93,34 @@ public class TestsShowActionTest {
     request.execute().assertJson(getClass(), "show.json");
   }
 
+  @Test
+  @Ignore
+  public void show_from_test_data() throws Exception {
+    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
+
+    when(measureDao.findByComponentKeyAndMetricKey(TEST_PLAN_KEY, "test_data", session)).thenReturn(MeasureDto.createFor(MeasureKey.of(TEST_PLAN_KEY, "test_data"))
+      .setTextValue("<tests-details>" +
+        "<testcase status=\"ok\" time=\"10\" name=\"test1\"/>" +
+        "<testcase status=\"error\" time=\"97\" name=\"test2\">" +
+        "<error message=\"expected:<true> but was:<false>\">" +
+        "<![CDATA[" +
+        "java.lang.AssertionError: expected:<true> but was:<false>\n\t" +
+        "at org.junit.Assert.fail(Assert.java:91)\n\t" +
+        "at org.junit.Assert.failNotEquals(Assert.java:645)\n\t" +
+        "at org.junit.Assert.assertEquals(Assert.java:126)\n\t" +
+        "at org.junit.Assert.assertEquals(Assert.java:145)\n" +
+        "]]>" +
+        "</error>" +
+        "</testcase>" +
+        "</tests-details>"));
+
+    // TODO failure
+
+    WsTester.TestRequest request = tester.newGetRequest("api/tests", "show").setParam("key", TEST_PLAN_KEY);
+
+    request.execute().assertJson(getClass(), "show_from_test_data.json");
+  }
+
   private MutableTestCase testCase(String name, TestCase.Status status, Long durationInMs, int coveredLines, @Nullable String message, @Nullable String stackTrace) {
     MutableTestCase testCase = mock(MutableTestCase.class);
     when(testCase.name()).thenReturn(name);
index 5dd2c4f185f7e4b0b83c5840725f5e7b94214d3f..50290be7023e9835ccd04024c32b36d42edf092a 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.server.db.DbClient;
 import org.sonar.server.ws.WsTester;
 
 import static org.fest.assertions.Assertions.assertThat;
@@ -36,7 +37,7 @@ public class TestsWsTest {
   @Before
   public void setUp() throws Exception {
     SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
-    WsTester tester = new WsTester(new TestsWs(new TestsShowAction(snapshotPerspectives), new TestsTestCasesAction(snapshotPerspectives), new TestsCoveredFilesAction(snapshotPerspectives)));
+    WsTester tester = new WsTester(new TestsWs(new TestsShowAction(mock(DbClient.class), snapshotPerspectives), new TestsTestCasesAction(snapshotPerspectives), new TestsCoveredFilesAction(snapshotPerspectives)));
     controller = tester.controller("api/tests");
   }
 
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsShowActionTest/show_from_test_data.json b/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsShowActionTest/show_from_test_data.json
new file mode 100644 (file)
index 0000000..f8832a0
--- /dev/null
@@ -0,0 +1,18 @@
+{
+"tests": [
+    {
+      "name": "test1",
+      "status": "OK",
+      "durationInMs": 10,
+      "coveredLines": 32
+    },
+    {
+      "name": "test2",
+      "status": "ERROR",
+      "durationInMs": 97,
+      "coveredLines": 21,
+      "message": "expected:<true> but was:<false>",
+      "stackTrace" : "java.lang.AssertionError: expected:<true> but was:<false>\n\tat org.junit.Assert.fail(Assert.java:91)\n\tat org.junit.Assert.failNotEquals(Assert.java:645)\n\tat org.junit.Assert.assertEquals(Assert.java:126)\n\tat org.junit.Assert.assertEquals(Assert.java:145)\n"
+    }
+  ]
+}
index 6752fe6f6b3dee4fff4ab117a917219740f322d8..572d70715cd8f79abf8017b945b30eb152115359 100644 (file)
@@ -22,6 +22,8 @@ package org.sonar.core.measure.db;
 
 import org.apache.ibatis.annotations.Param;
 
+import javax.annotation.CheckForNull;
+
 import java.util.List;
 
 public interface MeasureMapper {
@@ -30,6 +32,9 @@ public interface MeasureMapper {
 
   List<MeasureDto> selectByComponentAndMetrics(@Param("componentKey") String componentKey, @Param("metricKeys") List<String> metricKeys);
 
+  @CheckForNull
+  MeasureDto selectByComponentAndMetric(@Param("componentKey") String componentKey, @Param("metricKey") String metricKey);
+
   long countByKey(@Param("key") MeasureKey key);
 
 }
index cde157e101f3176d53db87e228d8838a71c006b5..0964ff196f108777f36a070006dceea7925e3ef4 100644 (file)
     </where>
   </select>
 
+  <select id="selectByComponentAndMetric" parameterType="map" resultType="Measure">
+    SELECT metric.name as metric_name,
+    <include refid="measureColumns"/>
+    FROM project_measures pm
+    INNER JOIN snapshots s ON s.id=pm.snapshot_id AND s.islast=${_true}
+    INNER JOIN projects p ON p.id=s.project_id AND p.enabled=${_true}
+    INNER JOIN metrics metric ON metric.id=pm.metric_id
+    <where>
+      AND p.kee = #{componentKey}
+      AND metric.name=#{metricKey}
+      AND pm.rule_id IS NULL
+      AND pm.characteristic_id IS NULL
+      AND pm.person_id IS NULL
+    </where>
+  </select>
+
   <select id="countByKey" parameterType="map" resultType="long">
     SELECT count(pm.id)
     FROM project_measures pm