@@ -52,16 +52,16 @@ | |||
end | |||
else | |||
# New Test API | |||
test_plan = controller.java_facade.getTestPlan(@snapshot.id) | |||
test_plan = controller.java_facade.testPlan(@snapshot.id) | |||
if test_plan | |||
test_plan.testCases().each do |test| | |||
test_case = {} | |||
test_case[:name] = test.name() | |||
test_case[:status] = test.status() | |||
test_case[:status] = test.status().to_s | |||
test_case[:time] = test.durationInMs() | |||
has_covered_lines = test.doesCover() | |||
test_case[:covered_lines] = test.countCoveredLines() if has_covered_lines | |||
if test.status() != 'ok' | |||
if test.status().to_s != 'ok' | |||
test_case[:message] = '' | |||
test_case[:message] = test.message() if test.message() | |||
test_case[:stack_trace] = html_escape(test.stackTrace()) |
@@ -210,7 +210,7 @@ | |||
<configuration> | |||
<rules> | |||
<requireFilesSize> | |||
<maxsize>54000000</maxsize> | |||
<maxsize>55000000</maxsize> | |||
<minsize>52000000</minsize> | |||
<files> | |||
<file>${project.build.directory}/sonar-${project.version}.zip</file> |
@@ -50,24 +50,12 @@ public class DefaultTestCase extends BeanVertex implements MutableTestCase { | |||
return this; | |||
} | |||
public String status() { | |||
return (String) getProperty("status"); | |||
public Status status() { | |||
return Status.of((String)getProperty("status")); | |||
} | |||
public MutableTestCase setStatus(@Nullable String s) { | |||
setProperty("status", s); | |||
return this; | |||
} | |||
/** | |||
* The key is not blank and unique among the test plan. | |||
*/ | |||
public String key() { | |||
return (String) getProperty("key"); | |||
} | |||
public MutableTestCase setKey(String s) { | |||
setProperty("key", s); | |||
public MutableTestCase setStatus(@Nullable Status s) { | |||
setProperty("status", s == null ? null : s.toString()); | |||
return this; | |||
} | |||
@@ -19,10 +19,10 @@ | |||
*/ | |||
package org.sonar.core.test; | |||
import com.google.common.collect.Lists; | |||
import com.tinkerpop.blueprints.Direction; | |||
import com.tinkerpop.blueprints.Vertex; | |||
import org.sonar.api.component.Component; | |||
import org.sonar.api.test.exception.TestCaseAlreadyExistsException; | |||
import org.sonar.api.test.MutableTestCase; | |||
import org.sonar.api.test.MutableTestPlan; | |||
import org.sonar.core.component.ComponentVertex; | |||
@@ -31,6 +31,8 @@ import org.sonar.core.graph.GraphUtil; | |||
import javax.annotation.CheckForNull; | |||
import java.util.List; | |||
public class DefaultTestPlan extends BeanVertex implements MutableTestPlan { | |||
public Component component() { | |||
Vertex component = GraphUtil.singleAdjacent(element(), Direction.IN, "testplan"); | |||
@@ -47,21 +49,19 @@ public class DefaultTestPlan extends BeanVertex implements MutableTestPlan { | |||
} | |||
@CheckForNull | |||
public MutableTestCase testCaseByKey(String key) { | |||
public Iterable<MutableTestCase> testCasesByName(String name) { | |||
List<MutableTestCase> result = Lists.newArrayList(); | |||
for (MutableTestCase testCase : testCases()) { | |||
if (key.equals(testCase.key())) { | |||
return testCase; | |||
if (name.equals(testCase.name())) { | |||
result.add(testCase); | |||
} | |||
} | |||
return null; | |||
return result; | |||
} | |||
public MutableTestCase addTestCase(String key) { | |||
if (testCaseByKey(key)!=null) { | |||
throw new TestCaseAlreadyExistsException(component().key(), key); | |||
} | |||
public MutableTestCase addTestCase(String name) { | |||
DefaultTestCase testCase = beanGraph().createAdjacentVertex(this, DefaultTestCase.class, "testcase"); | |||
testCase.setKey(key); | |||
testCase.setName(name); | |||
return testCase; | |||
} | |||
@@ -53,10 +53,10 @@ public class DefaultTestable extends BeanVertex implements MutableTestable { | |||
return cases.build(); | |||
} | |||
public TestCase testCaseByKey(final String key) { | |||
public TestCase testCaseByName(final String name) { | |||
return Iterables.find(testCases(), new Predicate<TestCase>() { | |||
public boolean apply(TestCase input) { | |||
return input.key().equals(key); | |||
return input.name().equals(name); | |||
} | |||
}, null); | |||
} | |||
@@ -94,7 +94,7 @@ public class DefaultTestable extends BeanVertex implements MutableTestable { | |||
public Cover coverOfTestCase(final TestCase testCase) { | |||
return Iterables.find(getEdges(DefaultCover.class, Direction.IN, "covers"), new Predicate<Cover>() { | |||
public boolean apply(Cover input) { | |||
return input.testCase().key().equals(testCase.key()); | |||
return input.testCase().name().equals(testCase.name()); | |||
} | |||
}, null); | |||
} |
@@ -83,7 +83,7 @@ public class DefaultTestCaseTest { | |||
} | |||
@Test | |||
public void should_return_cover_of_testable(){ | |||
public void should_return_cover_of_testable() { | |||
BeanGraph beanGraph = BeanGraph.createInMemory(); | |||
ScanGraph graph = ScanGraph.create(); | |||
@@ -106,19 +106,17 @@ public class DefaultTestCaseTest { | |||
BeanGraph beanGraph = BeanGraph.createInMemory(); | |||
DefaultTestCase testCase = beanGraph.createVertex(DefaultTestCase.class); | |||
testCase.setKey("T1") | |||
.setName("Test one") | |||
testCase.setName("T1") | |||
.setDurationInMs(1234L) | |||
.setMessage("Error msg") | |||
.setStackTrace("xxx") | |||
.setStatus(TestCase.STATUS_FAIL); | |||
.setStatus(TestCase.Status.ERROR); | |||
assertThat(testCase.key()).isEqualTo("T1"); | |||
assertThat(testCase.name()).isEqualTo("Test one"); | |||
assertThat(testCase.name()).isEqualTo("T1"); | |||
assertThat(testCase.message()).isEqualTo("Error msg"); | |||
assertThat(testCase.stackTrace()).isEqualTo("xxx"); | |||
assertThat(testCase.durationInMs()).isEqualTo(1234L); | |||
assertThat(testCase.status()).isEqualTo(TestCase.STATUS_FAIL); | |||
assertThat(testCase.status()).isEqualTo(TestCase.Status.ERROR); | |||
} | |||
@Test |
@@ -23,10 +23,8 @@ import com.google.common.collect.Iterables; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.test.exception.TestCaseAlreadyExistsException; | |||
import org.sonar.api.test.MutableTestCase; | |||
import org.sonar.api.test.TestPlan; | |||
import org.sonar.core.component.ComponentVertex; | |||
import org.sonar.core.graph.BeanGraph; | |||
import static org.fest.assertions.Assertions.assertThat; | |||
@@ -53,46 +51,46 @@ public class DefaultTestPlanTest { | |||
assertThat(plan.testCases()).hasSize(2); | |||
MutableTestCase firstTestCase = Iterables.get(plan.testCases(), 0); | |||
assertThat(firstTestCase.key()).isEqualTo("T1"); | |||
assertThat(firstTestCase.name()).isEqualTo("T1"); | |||
assertThat(firstTestCase.testPlan()).isSameAs(plan); | |||
MutableTestCase secondTestCase = Iterables.get(plan.testCases(), 1); | |||
assertThat(secondTestCase.key()).isEqualTo("T2"); | |||
assertThat(secondTestCase.name()).isEqualTo("T2"); | |||
assertThat(secondTestCase.testPlan()).isSameAs(plan); | |||
} | |||
@Test | |||
public void should_find_test_case_by_key() { | |||
public void should_find_test_case_by_name() { | |||
BeanGraph beanGraph = BeanGraph.createInMemory(); | |||
DefaultTestPlan plan = beanGraph.createVertex(DefaultTestPlan.class); | |||
plan.addTestCase("T1"); | |||
plan.addTestCase("T2"); | |||
assertThat(plan.testCaseByKey("T1").key()).isEqualTo("T1"); | |||
assertThat(plan.testCaseByKey("T3")).isNull(); | |||
assertThat(plan.testCasesByName("T1")).hasSize(1); | |||
assertThat(Iterables.get(plan.testCasesByName("T1"), 0).name()).isEqualTo("T1"); | |||
assertThat(plan.testCasesByName("T3")).isEmpty(); | |||
} | |||
@Test | |||
public void should_set_type() { | |||
public void should_find_multiple_test_cases_by_name() { | |||
BeanGraph beanGraph = BeanGraph.createInMemory(); | |||
DefaultTestPlan plan = beanGraph.createVertex(DefaultTestPlan.class); | |||
assertThat(plan.type()).isNull(); | |||
plan.addTestCase("T1"); | |||
plan.addTestCase("T1"); | |||
plan.setType(TestPlan.TYPE_UNIT); | |||
assertThat(plan.type()).isEqualTo(TestPlan.TYPE_UNIT); | |||
assertThat(plan.testCasesByName("T1")).hasSize(2); | |||
} | |||
@Test | |||
public void keys_of_test_cases_should_be_unique() { | |||
thrown.expect(TestCaseAlreadyExistsException.class); | |||
public void should_set_type() { | |||
BeanGraph beanGraph = BeanGraph.createInMemory(); | |||
ComponentVertex component = beanGraph.createVertex(ComponentVertex.class); | |||
DefaultTestPlan plan = beanGraph.createAdjacentVertex(component, DefaultTestPlan.class, "testplan"); | |||
plan.addTestCase("T1"); | |||
plan.addTestCase("T1"); | |||
DefaultTestPlan plan = beanGraph.createVertex(DefaultTestPlan.class); | |||
assertThat(plan.type()).isNull(); | |||
plan.setType(TestPlan.TYPE_UNIT); | |||
assertThat(plan.type()).isEqualTo(TestPlan.TYPE_UNIT); | |||
} | |||
} |
@@ -86,9 +86,9 @@ public class DefaultTestableTest { | |||
MutableTestCase testCase2 = Iterables.get(plan.testCases(), 1); | |||
testCase2.setCover(testable, Arrays.asList(12, 48, 49)); | |||
assertThat(testable.testCaseByKey("T1")).isEqualTo(testCase1); | |||
assertThat(testable.testCaseByKey("T2")).isEqualTo(testCase2); | |||
assertThat(testable.testCaseByKey("Unknown")).isNull(); | |||
assertThat(testable.testCaseByName("T1")).isEqualTo(testCase1); | |||
assertThat(testable.testCaseByName("T2")).isEqualTo(testCase2); | |||
assertThat(testable.testCaseByName("Unknown")).isNull(); | |||
} | |||
@Test |
@@ -24,12 +24,10 @@ import javax.annotation.Nullable; | |||
import java.util.List; | |||
public interface MutableTestCase extends TestCase { | |||
MutableTestCase setStatus(String s); | |||
MutableTestCase setStatus(Status s); | |||
MutableTestCase setDurationInMs(@Nullable Long l); | |||
MutableTestCase setName(String s); | |||
MutableTestCase setMessage(String s); | |||
MutableTestCase setStackTrace(String s); |
@@ -19,22 +19,23 @@ | |||
*/ | |||
package org.sonar.api.test; | |||
import javax.annotation.Nullable; | |||
public interface TestCase { | |||
String STATUS_PASS = "pass"; | |||
String STATUS_FAIL = "fail"; | |||
enum Status { | |||
OK, FAILURE, ERROR, SKIPPED; | |||
public static Status of(@Nullable String s) { | |||
return s == null ? null : valueOf(s.toUpperCase()); | |||
} | |||
} | |||
/** | |||
* Duration in milliseconds | |||
*/ | |||
Long durationInMs(); | |||
// pass/fail/... | |||
String status(); | |||
/** | |||
* The key is not null and unique among the test plan. | |||
*/ | |||
String key(); | |||
Status status(); | |||
String name(); | |||
@@ -32,5 +32,5 @@ public interface TestPlan<T extends TestCase> extends Perspective { | |||
Iterable<T> testCases(); | |||
T testCaseByKey(String key); | |||
Iterable<T> testCasesByName(String name); | |||
} |
@@ -28,7 +28,7 @@ public interface Testable extends Perspective { | |||
List<TestCase> testCases(); | |||
TestCase testCaseByKey(String key); | |||
TestCase testCaseByName(String key); | |||
int countTestCasesOfLine(Integer line); | |||
@@ -1,26 +0,0 @@ | |||
/* | |||
* Sonar, open source software quality management tool. | |||
* Copyright (C) 2008-2012 SonarSource | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* Sonar 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. | |||
* | |||
* Sonar 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 Sonar; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
*/ | |||
package org.sonar.api.test.exception; | |||
public class TestCaseAlreadyExistsException extends TestException { | |||
public TestCaseAlreadyExistsException(String componentKey, String testCaseKey) { | |||
super(String.format("Test case already exists for %s: %s", componentKey, testCaseKey)); | |||
} | |||
} |
@@ -325,7 +325,7 @@ public final class JRubyFacade { | |||
public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) { | |||
getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId], | |||
RulePriority.values()[newSeverityId], userName); | |||
RulePriority.values()[newSeverityId], userName); | |||
} | |||
public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) { | |||
@@ -521,10 +521,10 @@ public final class JRubyFacade { | |||
// notifier is null when creating the administrator in the migration script 011. | |||
if (notifier != null) { | |||
notifier.onNewUser(NewUserHandler.Context.builder() | |||
.setLogin(fields.get("login")) | |||
.setName(fields.get("name")) | |||
.setEmail(fields.get("email")) | |||
.build()); | |||
.setLogin(fields.get("login")) | |||
.setName(fields.get("name")) | |||
.setEmail(fields.get("email")) | |||
.build()); | |||
} | |||
} | |||
@@ -544,11 +544,15 @@ public final class JRubyFacade { | |||
return get(Periods.class).abbreviation(periodIndex); | |||
} | |||
public TestPlan getTestPlan(long snapshotId) { | |||
public TestPlan testPlan(long snapshotId) { | |||
return get(SnapshotPerspectives.class).as(MutableTestPlan.class, snapshotId); | |||
} | |||
public Testable getTestable(long snapshotId) { | |||
public TestPlan testPlan(String componentKey) { | |||
return get(SnapshotPerspectives.class).as(MutableTestPlan.class, componentKey); | |||
} | |||
public Testable testable(long snapshotId) { | |||
return get(SnapshotPerspectives.class).as(MutableTestable.class, snapshotId); | |||
} | |||
@@ -0,0 +1,71 @@ | |||
# | |||
# Sonar, entreprise quality control tool. | |||
# Copyright (C) 2008-2012 SonarSource | |||
# mailto:contact AT sonarsource DOT com | |||
# | |||
# Sonar 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. | |||
# | |||
# Sonar 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 Sonar; if not, write to the Free Software | |||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 | |||
# | |||
class Api::TestsController < Api::ApiController | |||
# GET /api/tests/plan?resource=<test file id or key> | |||
# | |||
# Get the details of a given test plan : | |||
# - test cases | |||
# - resources covered by test cases | |||
# | |||
# Since v.3.5 | |||
# | |||
# ==== Examples | |||
# - get the test plan defined by the file com/mycompany/FooTest.c of my_project : GET /api/tests/plan?resource=my_project:com/mycompany/FooTest.c | |||
# | |||
def plan | |||
require_parameters :resource | |||
resource=Project.by_key(params[:resource]) | |||
not_found("Not found: #{params[:resource]}") unless resource | |||
access_denied unless has_role?(:user, resource) | |||
plan = java_facade.testPlan(resource.key) | |||
json = {} | |||
if plan | |||
json[:type] = plan.type | |||
json[:test_cases] = plan.testCases.map do |test_case| | |||
test_case_json = {:name => test_case.name} | |||
test_case_json[:message] = test_case.message if test_case.message | |||
test_case_json[:durationInMs] = test_case.durationInMs if test_case.durationInMs | |||
test_case_json[:status] = test_case.status.to_s if test_case.status | |||
test_case_json[:stackTrace] = test_case.stackTrace if test_case.stackTrace | |||
if test_case.doesCover() | |||
test_case_json[:covers] = test_case.covers.map do |cover| | |||
cover_json = {} | |||
resource = cover.testable.component | |||
cover_json[:resourceKey] = resource.key | |||
cover_json[:resourceName] = resource.name | |||
cover_json[:resourceQualifier] = resource.qualifier | |||
cover_json[:lines] = cover.lines | |||
cover_json | |||
end | |||
end | |||
test_case_json | |||
end | |||
respond_to do |format| | |||
format.json { render :json => jsonp(json) } | |||
format.xml { render :xml => xml_not_supported } | |||
format.text { render :text => text_not_supported } | |||
end | |||
end | |||
end | |||
end |
@@ -205,7 +205,7 @@ class ResourceController < ApplicationController | |||
@conditions_by_line = load_distribution("#{it_prefix}conditions_by_line") | |||
@covered_conditions_by_line = load_distribution("#{it_prefix}covered_conditions_by_line") | |||
@testable = java_facade.getTestable(@snapshot.id) | |||
@testable = java_facade.testable(@snapshot.id) | |||
@hits_by_line.each_pair do |line_id, hits| | |||
line = @lines[line_id-1] | |||
if line |
@@ -25,7 +25,7 @@ class TestController < ApplicationController | |||
snapshot_id = params[:sid].to_i | |||
@test = params[:test].to_s | |||
@test_plan = java_facade.getTestPlan(snapshot_id) | |||
@test_plan = java_facade.testPlan(snapshot_id) | |||
@test_case = @test_plan.testCaseByKey(@test) | |||
render :partial => 'test/testcase_working_view' | |||
end | |||
@@ -36,7 +36,7 @@ class TestController < ApplicationController | |||
snapshot_id = params[:sid].to_i | |||
@line = params[:line].to_i | |||
@testable = java_facade.getTestable(snapshot_id) | |||
@testable = java_facade.testable(snapshot_id) | |||
@test_case_by_test_plan = {} | |||
@testable.testCasesOfLine(@line).each do |test_case| | |||
test_plan = test_case.testPlan |