]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5338 Create s WS /api/tests/testable returning list of test cases from a file...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 22 May 2014 17:36:09 +0000 (19:36 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 23 May 2014 14:07:01 +0000 (16:07 +0200)
sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsWriter.java
sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestableAction.java [new file with mode: 0644]
sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java
sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-testable.json
sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestableActionTest.java [new file with mode: 0644]
sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java
sonar-server/src/test/resources/org/sonar/server/test/ws/TestsTestableActionTest/testable.json [new file with mode: 0644]

index 28e8e6330682f91a81e1e54525d739fb3d065f71..663afccc3c3c9d9c2a1fa2fa117fa56a08dc6ed2 100644 (file)
@@ -89,7 +89,7 @@ public class DuplicationsWriter implements ServerComponent {
     String ref = refByComponentKey.get(componentKey);
     if (ref == null) {
       ref = Integer.toString(refByComponentKey.size() + 1);
-      refByComponentKey.put(componentKey, Integer.toString(refByComponentKey.size() + 1));
+      refByComponentKey.put(componentKey, ref);
     }
 
     json.beginObject();
index 4bd0d16d9b9dd6fd62e262547237f2bb8a4884bb..db5db86223de83b3115397773d91c3528fdfac65 100644 (file)
@@ -145,6 +145,7 @@ import org.sonar.server.startup.*;
 import org.sonar.server.test.CoverageService;
 import org.sonar.server.test.ws.CoverageShowAction;
 import org.sonar.server.test.ws.CoverageWs;
+import org.sonar.server.test.ws.TestsTestableAction;
 import org.sonar.server.test.ws.TestsWs;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.text.RubyTextService;
@@ -487,6 +488,7 @@ class ServerComponents {
     pico.addSingleton(CoverageService.class);
     pico.addSingleton(CoverageWs.class);
     pico.addSingleton(CoverageShowAction.class);
+    pico.addSingleton(TestsTestableAction.class);
 
     // graphs and perspective related classes
     pico.addSingleton(TestablePerspectiveLoader.class);
diff --git a/sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestableAction.java b/sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestableAction.java
new file mode 100644 (file)
index 0000000..c403bc7
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * 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.test.ws;
+
+import com.google.common.io.Resources;
+import org.sonar.api.component.Component;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.RequestHandler;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.test.MutableTestable;
+import org.sonar.api.test.TestCase;
+import org.sonar.api.test.Testable;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.server.user.UserSession;
+
+import java.util.Map;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+public class TestsTestableAction implements RequestHandler {
+
+  private static final String KEY = "key";
+  private static final String LINE = "line";
+
+  private final SnapshotPerspectives snapshotPerspectives;
+
+  public TestsTestableAction(SnapshotPerspectives snapshotPerspectives) {
+    this.snapshotPerspectives = snapshotPerspectives;
+  }
+
+  void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("testable")
+      .setDescription("Get the list of test cases covering a given file and line. Require Browse permission on file's project")
+      .setSince("4.4")
+      .setResponseExample(Resources.getResource(getClass(), "tests-example-testable.json"))
+      .setHandler(this);
+
+    action
+      .createParam(KEY)
+      .setRequired(true)
+      .setDescription("File key")
+      .setExampleValue("my_project:/src/foo/Bar.php");
+
+    action
+      .createParam(LINE)
+      .setRequired(true)
+      .setDescription("Line of the file used to get test cases")
+      .setExampleValue("10");
+  }
+
+  @Override
+  public void handle(Request request, Response response) {
+    String fileKey = request.mandatoryParam(KEY);
+    UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
+    int line = request.mandatoryParamAsInt(LINE);
+
+    Testable testable = snapshotPerspectives.as(MutableTestable.class, fileKey);
+    if (testable != null) {
+      JsonWriter json = response.newJsonWriter().beginObject();
+
+      Map<String, Integer> refByTestPlan = newHashMap();
+      Map<String, Component> componentsByKey = newHashMap();
+      writeTests(testable, line, refByTestPlan, componentsByKey, json);
+      writeFiles(refByTestPlan, componentsByKey, json);
+
+      json.endObject().close();
+    }
+  }
+
+  private void writeTests(Testable testable, Integer line, Map<String, Integer> refByTestPlan, Map<String, Component> componentsByKey, JsonWriter json) {
+    json.name("tests").beginArray();
+    for (TestCase testCase : testable.testCasesOfLine(line)) {
+      json.beginObject();
+      json.prop("name", testCase.name());
+      json.prop("status", testCase.status().name());
+      json.prop("durationInMs", testCase.durationInMs());
+
+      Component testPlan = testCase.testPlan().component();
+      Integer ref = refByTestPlan.get(testPlan.key());
+      if (ref == null) {
+        ref = refByTestPlan.size() + 1;
+        refByTestPlan.put(testPlan.key(), ref);
+        componentsByKey.put(testPlan.key(), testPlan);
+      }
+      json.prop("_ref", Integer.toString(ref));
+      json.endObject();
+    }
+    json.endArray();
+  }
+
+  private void writeFiles(Map<String, Integer> refByTestPlan, Map<String, Component> componentsByKey, JsonWriter json) {
+    json.name("files").beginObject();
+    for (Map.Entry<String, Integer> entry : refByTestPlan.entrySet()) {
+      String componentKey = entry.getKey();
+      Integer ref = entry.getValue();
+      Component file = componentsByKey.get(componentKey);
+      json.name(Integer.toString(ref)).beginObject();
+      json.prop("key", file.key());
+      json.prop("longName", file.longName());
+      json.endObject();
+    }
+    json.endObject();
+  }
+}
index c5b02ef3a5cd3d296a8c0e61e26917da5aab656e..396aaf362a5ea10bff3c356fd8caf03532fad08c 100644 (file)
@@ -26,14 +26,20 @@ import org.sonar.api.server.ws.WebService;
 
 public class TestsWs implements WebService {
 
+  private final TestsTestableAction testsTestableAction;
+
+  public TestsWs(TestsTestableAction testsTestableAction) {
+    this.testsTestableAction = testsTestableAction;
+  }
+
   @Override
   public void define(Context context) {
     NewController controller = context.createController("api/tests")
-      .setSince("3.5")
+      .setSince("4.4")
       .setDescription("Tests management");
 
     definePlanAction(controller);
-    defineTestableAction(controller);
+    testsTestableAction.define(controller);
 
     controller.done();
   }
@@ -53,19 +59,4 @@ public class TestsWs implements WebService {
     RailsHandler.addJsonOnlyFormatParam(action);
   }
 
-  private void defineTestableAction(NewController controller) {
-    NewAction action = controller.createAction("testable")
-      .setDescription("Get the details of a given resource : test plan, test cases covering lines. Requires Browse permission on resource")
-      .setSince("3.5")
-      .setInternal(true)
-      .setHandler(RailsHandler.INSTANCE)
-      .setResponseExample(Resources.getResource(this.getClass(), "tests-example-testable.json"));
-
-    action.createParam("resource")
-      .setRequired(true)
-      .setDescription("id or key of the resource")
-      .setExampleValue("org.codehaus.sonar.plugins:sonar-cpd-plugin:src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java");
-    RailsHandler.addJsonOnlyFormatParam(action);
-  }
-
 }
index 9a146d89a7f943fa85299921fc6ee8b43358d0b2..92e038af28c18f04824a5123326ddfdf4e78871e 100644 (file)
@@ -1,33 +1,26 @@
 {
-  "key": "org.codehaus.sonar.plugins:sonar-cpd-plugin:src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java",
-  "name": "SonarBridgeEngine.java",
-  "longName": "src/main/java/org/sonar/plugins/cpd/SonarBridgeEngine.java",
-  "coveredLines": [
-    68,
-    69,
-    70,
-    71,
-    72,
-    73,
-    76,
-    77
-  ],
-  "coverages": [
+  "tests": [
     {
-      "lines": [
-        68,
-        69,
-        70,
-        71,
-        72,
-        73,
-        76,
-        77
-      ],
-      "name": "test_engine",
+      "_ref": "1",
+      "name": "find_by_params",
       "status": "OK",
-      "durationInMs": 2,
-      "testPlan": "org.codehaus.sonar.plugins:sonar-cpd-plugin:src/test/java/org/sonar/plugins/cpd/CpdSensorTest.java"
+      "durationInMs": 10
+    },
+    {
+      "_ref": "2",
+      "name": "find_rules_by_characteristics",
+      "status": "ERROR",
+      "durationInMs": 97
+    }
+  ],
+  "files": {
+    "1": {
+      "key": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
+      "longName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java"
+    },
+    "2": {
+      "key": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RuleRegistryTest.java",
+      "longName": "src/test/java/org/sonar/server/rule/RuleRegistryTest.java"
     }
-  ]
+  }
 }
diff --git a/sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestableActionTest.java b/sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestableActionTest.java
new file mode 100644 (file)
index 0000000..9c32a32
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.test.ws;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.test.MutableTestable;
+import org.sonar.api.test.TestCase;
+import org.sonar.api.test.TestPlan;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TestsTestableActionTest {
+
+  static final String FILE_KEY = "src/Foo.java";
+
+  @Mock
+  MutableTestable testable;
+
+  WsTester tester;
+
+  @Before
+  public void setUp() throws Exception {
+    SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
+    when(snapshotPerspectives.as(MutableTestable.class, FILE_KEY)).thenReturn(testable);
+    tester = new WsTester(new TestsWs(new TestsTestableAction(snapshotPerspectives)));
+  }
+
+  @Test
+  public void testable() throws Exception {
+    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", FILE_KEY);
+
+    TestCase testCase1 = testCase("test1", TestCase.Status.OK, 10L, "org.foo.BarTest.java", "src/test/java/org/foo/BarTest.java");
+    TestCase testCase2 = testCase("test2", TestCase.Status.ERROR, 97L, "org.foo.FileTest.java", "src/test/java/org/foo/FileTest.java");
+    when(testable.testCasesOfLine(10)).thenReturn(newArrayList(testCase1, testCase2));
+
+    WsTester.TestRequest request = tester.newGetRequest("api/tests", "testable").setParam("key", FILE_KEY).setParam("line", "10");
+
+    request.execute().assertJson(getClass(), "testable.json");
+  }
+
+  private TestCase testCase(String name, TestCase.Status status, Long durationInMs, String testPlanKey, String testPlanLongName) {
+    TestCase testCase = mock(TestCase.class);
+    when(testCase.name()).thenReturn(name);
+    when(testCase.status()).thenReturn(status);
+    when(testCase.durationInMs()).thenReturn(durationInMs);
+
+    TestPlan testPlan = mock(TestPlan.class);
+    when(testPlan.component()).thenReturn(new ComponentDto().setKey(testPlanKey).setLongName(testPlanLongName));
+    when(testCase.testPlan()).thenReturn(testPlan);
+    return testCase;
+  }
+
+}
index b0475fdec8e3d7c2c223f9e0d2a2e94950ef66bd..2cbed21b1cb75fcf90193acdd9e9543af09b82a9 100644 (file)
@@ -24,9 +24,11 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.server.ws.RailsHandler;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.core.component.SnapshotPerspectives;
 import org.sonar.server.ws.WsTester;
 
 import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
 
 public class TestsWsTest {
 
@@ -34,14 +36,14 @@ public class TestsWsTest {
 
   @Before
   public void setUp() throws Exception {
-    WsTester tester = new WsTester(new TestsWs());
+    WsTester tester = new WsTester(new TestsWs(new TestsTestableAction(mock(SnapshotPerspectives.class))));
     controller = tester.controller("api/tests");
   }
 
   @Test
   public void define_controller() throws Exception {
     assertThat(controller).isNotNull();
-    assertThat(controller.since()).isEqualTo("3.5");
+    assertThat(controller.since()).isEqualTo("4.4");
     assertThat(controller.description()).isNotEmpty();
     assertThat(controller.actions()).hasSize(2);
   }
@@ -61,9 +63,9 @@ public class TestsWsTest {
   public void define_testable_action() throws Exception {
     WebService.Action action = controller.action("testable");
     assertThat(action).isNotNull();
-    assertThat(action.isInternal()).isTrue();
+    assertThat(action.isInternal()).isFalse();
     assertThat(action.isPost()).isFalse();
-    assertThat(action.handler()).isInstanceOf(RailsHandler.class);
+    assertThat(action.handler()).isNotNull();
     assertThat(action.responseExampleAsString()).isNotEmpty();
     assertThat(action.params()).hasSize(2);
   }
diff --git a/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsTestableActionTest/testable.json b/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsTestableActionTest/testable.json
new file mode 100644 (file)
index 0000000..c2ed0ff
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "tests": [
+    {
+      "name": "test1",
+      "status": "OK",
+      "durationInMs": 10,
+      "_ref": "1"
+    },
+    {
+      "name": "test2",
+      "status": "ERROR",
+      "durationInMs": 97,
+      "_ref": "2"
+    }
+  ],
+  "files": {
+    "1": {
+      "key": "org.foo.BarTest.java",
+      "longName": "src/test/java/org/foo/BarTest.java"
+    },
+    "2": {
+      "key": "org.foo.FileTest.java",
+      "longName": "src/test/java/org/foo/FileTest.java"
+    }
+  }
+}