From 08ac15573ac5fdbcf071f598dd24c3cd0b2e238b Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Thu, 22 May 2014 19:36:09 +0200 Subject: [PATCH] SONAR-5338 Create s WS /api/tests/plan returning list of files covered by a test case --- .../server/platform/ServerComponents.java | 8 +- .../sonar/server/test/ws/TestsPlanAction.java | 95 +++++++++++++++++++ .../server/test/ws/TestsTestableAction.java | 6 +- .../org/sonar/server/test/ws/TestsWs.java | 29 ++---- .../sonar/server/test/ws/package-info.java | 24 +++++ .../server/test/ws/tests-example-plan.json | 45 ++------- .../server/test/ws/TestsPlanActionTest.java | 87 +++++++++++++++++ .../test/ws/TestsTestableActionTest.java | 4 +- .../org/sonar/server/test/ws/TestsWsTest.java | 8 +- .../test/ws/TestsPlanActionTest/plan.json | 14 +++ 10 files changed, 247 insertions(+), 73 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/test/ws/TestsPlanAction.java create mode 100644 sonar-server/src/main/java/org/sonar/server/test/ws/package-info.java create mode 100644 sonar-server/src/test/java/org/sonar/server/test/ws/TestsPlanActionTest.java create mode 100644 sonar-server/src/test/resources/org/sonar/server/test/ws/TestsPlanActionTest/plan.json diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index db5db86223d..8c30773f1b7 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -143,10 +143,7 @@ import org.sonar.server.source.ws.ShowAction; import org.sonar.server.source.ws.SourcesWs; 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.test.ws.*; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.text.RubyTextService; import org.sonar.server.ui.JRubyI18n; @@ -484,11 +481,12 @@ class ServerComponents { pico.addSingleton(DefaultNotificationManager.class); // Tests - pico.addSingleton(TestsWs.class); pico.addSingleton(CoverageService.class); pico.addSingleton(CoverageWs.class); pico.addSingleton(CoverageShowAction.class); + pico.addSingleton(TestsWs.class); pico.addSingleton(TestsTestableAction.class); + pico.addSingleton(TestsPlanAction.class); // graphs and perspective related classes pico.addSingleton(TestablePerspectiveLoader.class); diff --git a/sonar-server/src/main/java/org/sonar/server/test/ws/TestsPlanAction.java b/sonar-server/src/main/java/org/sonar/server/test/ws/TestsPlanAction.java new file mode 100644 index 00000000000..33d6cfaaf1b --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/test/ws/TestsPlanAction.java @@ -0,0 +1,95 @@ +/* + * 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.*; +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; + +public class TestsPlanAction implements RequestHandler { + + private static final String KEY = "key"; + private static final String TEST = "test"; + + private final SnapshotPerspectives snapshotPerspectives; + + public TestsPlanAction(SnapshotPerspectives snapshotPerspectives) { + this.snapshotPerspectives = snapshotPerspectives; + } + + void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction("plan") + .setDescription("Get the list of files covered by a test plan. Require Browse permission on file's project") + .setSince("4.4") + .setResponseExample(Resources.getResource(getClass(), "tests-example-plan.json")) + .setHandler(this); + + action + .createParam(KEY) + .setRequired(true) + .setDescription("Test plan key") + .setExampleValue("my_project:/src/test/BarTest.java"); + + action + .createParam(TEST) + .setRequired(true) + .setDescription("Test case used to list files covered by the test plan") + .setExampleValue("my_test"); + } + + @Override + public void handle(Request request, Response response) { + String fileKey = request.mandatoryParam(KEY); + UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey); + String test = request.mandatoryParam(TEST); + + MutableTestPlan testPlan = snapshotPerspectives.as(MutableTestPlan.class, fileKey); + JsonWriter json = response.newJsonWriter().beginObject(); + if (testPlan != null) { + writeTests(testPlan, test, json); + } + json.endObject().close(); + } + + private void writeTests(TestPlan testPlan, String test, JsonWriter json) { + json.name("files").beginArray(); + for (TestCase testCase : testPlan.testCasesByName(test)) { + for (CoverageBlock coverageBlock : testCase.coverageBlocks()) { + json.beginObject(); + Component file = coverageBlock.testable().component(); + json.prop("key", file.key()); + json.prop("longName", file.longName()); + json.prop("coveredLines", coverageBlock.lines().size()); + json.endObject(); + } + } + json.endArray(); + } + +} 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 index c403bc763fc..3b919b7ec89 100644 --- 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 @@ -76,16 +76,14 @@ public class TestsTestableAction implements RequestHandler { int line = request.mandatoryParamAsInt(LINE); Testable testable = snapshotPerspectives.as(MutableTestable.class, fileKey); + JsonWriter json = response.newJsonWriter().beginObject(); if (testable != null) { - JsonWriter json = response.newJsonWriter().beginObject(); - Map refByTestPlan = newHashMap(); Map componentsByKey = newHashMap(); writeTests(testable, line, refByTestPlan, componentsByKey, json); writeFiles(refByTestPlan, componentsByKey, json); - - json.endObject().close(); } + json.endObject().close(); } private void writeTests(Testable testable, Integer line, Map refByTestPlan, Map componentsByKey, JsonWriter json) { diff --git a/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java b/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java index 396aaf362a5..8d3ba1d215f 100644 --- a/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java +++ b/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java @@ -20,16 +20,16 @@ package org.sonar.server.test.ws; -import com.google.common.io.Resources; -import org.sonar.api.server.ws.RailsHandler; import org.sonar.api.server.ws.WebService; public class TestsWs implements WebService { - private final TestsTestableAction testsTestableAction; + private final TestsTestableAction testableAction; + private final TestsPlanAction planAction; - public TestsWs(TestsTestableAction testsTestableAction) { - this.testsTestableAction = testsTestableAction; + public TestsWs(TestsTestableAction testableAction, TestsPlanAction planAction) { + this.testableAction = testableAction; + this.planAction = planAction; } @Override @@ -38,25 +38,10 @@ public class TestsWs implements WebService { .setSince("4.4") .setDescription("Tests management"); - definePlanAction(controller); - testsTestableAction.define(controller); + testableAction.define(controller); + planAction.define(controller); controller.done(); } - private void definePlanAction(NewController controller) { - NewAction action = controller.createAction("plan") - .setDescription("Get the details of a given test plan : test cases, resources covered by test cases. Requires Browse permission on resource") - .setSince("3.5") - .setInternal(true) - .setHandler(RailsHandler.INSTANCE) - .setResponseExample(Resources.getResource(this.getClass(), "tests-example-plan.json")); - - action.createParam("resource") - .setRequired(true) - .setDescription("id or key of the test resource") - .setExampleValue("org.codehaus.sonar.plugins:sonar-cpd-plugin:src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java"); - RailsHandler.addJsonOnlyFormatParam(action); - } - } diff --git a/sonar-server/src/main/java/org/sonar/server/test/ws/package-info.java b/sonar-server/src/main/java/org/sonar/server/test/ws/package-info.java new file mode 100644 index 00000000000..cee704a3d7d --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/test/ws/package-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +@ParametersAreNonnullByDefault +package org.sonar.server.test.ws; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json b/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json index 5cc43b76e56..ce75518aefa 100644 --- a/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json +++ b/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json @@ -1,41 +1,14 @@ { - "key": "org.codehaus.sonar.plugins:sonar-cpd-plugin:src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java", - "name": "SonarBridgeEngineTest.java", - "longName": "src/test/java/org/sonar/plugins/cpd/SonarBridgeEngineTest.java", - "testCases": [ + "files": [ { - "name": "shouldReturnDefaultBlockSize", - "type": "UNIT", - "durationInMs": 2, - "status": "OK", - "coverages": [ - { - "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", - "lines": [ - 68, - 69, - 70, - 71, - 72, - 73, - 155, - 156, - 157, - 158, - 160 - ] - }, - { - "key": "org.codehaus.sonar.plugins:sonar-cpd-plugin:src/main/java/org/sonar/plugins/cpd/CpdEngine.java", - "name": "CpdEngine.java", - "longName": "src/main/java/org/sonar/plugins/cpd/CpdEngine.java", - "lines": [ - 27 - ] - } - ] + "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/paging/PagedResult.java", + "longName": "src/main/java/org/sonar/server/paging/PagedResult.java", + "coveredLines": 5 + }, + { + "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/rule/RuleDocumentParser.java", + "longName": "src/main/java/org/sonar/server/rule/RuleDocumentParser.java", + "coveredLines": 38 } ] } diff --git a/sonar-server/src/test/java/org/sonar/server/test/ws/TestsPlanActionTest.java b/sonar-server/src/test/java/org/sonar/server/test/ws/TestsPlanActionTest.java new file mode 100644 index 00000000000..2f623a77071 --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/test/ws/TestsPlanActionTest.java @@ -0,0 +1,87 @@ +/* + * 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.CoverageBlock; +import org.sonar.api.test.MutableTestCase; +import org.sonar.api.test.MutableTestPlan; +import org.sonar.api.test.Testable; +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 java.util.Arrays; + +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 TestsPlanActionTest { + + static final String FILE_KEY = "src/test/java/org/foo/BarTest.java"; + + @Mock + MutableTestPlan testPlan; + + WsTester tester; + + @Before + public void setUp() throws Exception { + SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class); + when(snapshotPerspectives.as(MutableTestPlan.class, FILE_KEY)).thenReturn(testPlan); + tester = new WsTester(new TestsWs(mock(TestsTestableAction.class), new TestsPlanAction(snapshotPerspectives))); + } + + @Test + public void plan() throws Exception { + MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", FILE_KEY); + + MutableTestCase testCase1 = testCase("org.foo.Bar.java", "src/main/java/org/foo/Bar.java", 10); + MutableTestCase testCase2 = testCase("org.foo.File.java", "src/main/java/org/foo/File.java", 3); + when(testPlan.testCasesByName("my_test")).thenReturn(newArrayList(testCase1, testCase2)); + + WsTester.TestRequest request = tester.newGetRequest("api/tests", "plan").setParam("key", FILE_KEY).setParam("test", "my_test"); + + request.execute().assertJson(getClass(), "plan.json"); + } + + private MutableTestCase testCase(String fileKey, String fileLongName, int coveredLines) { + Testable testable = mock(Testable.class); + when(testable.component()).thenReturn(new ComponentDto().setKey(fileKey).setLongName(fileLongName)); + + CoverageBlock block = mock(CoverageBlock.class); + when(block.testable()).thenReturn(testable); + when(block.lines()).thenReturn(Arrays.asList(new Integer[coveredLines])); + + MutableTestCase testCase = mock(MutableTestCase.class); + when(testCase.coverageBlocks()).thenReturn(newArrayList(block)); + return testCase; + } + +} 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 index 9c32a328b8e..e34f9ad6d38 100644 --- 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 @@ -41,7 +41,7 @@ import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class TestsTestableActionTest { - static final String FILE_KEY = "src/Foo.java"; + static final String FILE_KEY = "src/main/java/org/foo/Foo.java"; @Mock MutableTestable testable; @@ -52,7 +52,7 @@ public class TestsTestableActionTest { 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))); + tester = new WsTester(new TestsWs(new TestsTestableAction(snapshotPerspectives), mock(TestsPlanAction.class))); } @Test diff --git a/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java b/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java index 2cbed21b1cb..173d6741733 100644 --- a/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java @@ -22,7 +22,6 @@ package org.sonar.server.test.ws; 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; @@ -36,7 +35,8 @@ public class TestsWsTest { @Before public void setUp() throws Exception { - WsTester tester = new WsTester(new TestsWs(new TestsTestableAction(mock(SnapshotPerspectives.class)))); + SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class); + WsTester tester = new WsTester(new TestsWs(new TestsTestableAction(snapshotPerspectives), new TestsPlanAction(snapshotPerspectives))); controller = tester.controller("api/tests"); } @@ -52,9 +52,9 @@ public class TestsWsTest { public void define_plan_action() throws Exception { WebService.Action action = controller.action("plan"); 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/TestsPlanActionTest/plan.json b/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsPlanActionTest/plan.json new file mode 100644 index 00000000000..be452f5e1b7 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsPlanActionTest/plan.json @@ -0,0 +1,14 @@ +{ + "files": [ + { + "key": "org.foo.Bar.java", + "longName": "src/main/java/org/foo/Bar.java", + "coveredLines" : 10 + }, + { + "key": "org.foo.File.java", + "longName": "src/main/java/org/foo/File.java", + "coveredLines" : 3 + } + ] +} -- 2.39.5