Browse Source

SONAR-2501 a test plan can have multiple test cases with the same name (see TestNG)

tags/3.5
Simon Brandhof 11 years ago
parent
commit
b58601cce7

+ 3
- 3
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/web/tests_viewer.html.erb View File

@@ -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())

+ 1
- 1
sonar-application/pom.xml View File

@@ -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>

+ 4
- 16
sonar-core/src/main/java/org/sonar/core/test/DefaultTestCase.java View 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;
}


+ 10
- 10
sonar-core/src/main/java/org/sonar/core/test/DefaultTestPlan.java View File

@@ -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;
}


+ 3
- 3
sonar-core/src/main/java/org/sonar/core/test/DefaultTestable.java View File

@@ -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);
}

+ 5
- 7
sonar-core/src/test/java/org/sonar/core/test/DefaultTestCaseTest.java View File

@@ -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

+ 16
- 18
sonar-core/src/test/java/org/sonar/core/test/DefaultTestPlanTest.java View File

@@ -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);
}
}

+ 3
- 3
sonar-core/src/test/java/org/sonar/core/test/DefaultTestableTest.java View File

@@ -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

+ 1
- 3
sonar-plugin-api/src/main/java/org/sonar/api/test/MutableTestCase.java View File

@@ -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);

+ 10
- 9
sonar-plugin-api/src/main/java/org/sonar/api/test/TestCase.java View File

@@ -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();


+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/test/TestPlan.java View File

@@ -32,5 +32,5 @@ public interface TestPlan<T extends TestCase> extends Perspective {

Iterable<T> testCases();

T testCaseByKey(String key);
Iterable<T> testCasesByName(String name);
}

+ 1
- 1
sonar-plugin-api/src/main/java/org/sonar/api/test/Testable.java View File

@@ -28,7 +28,7 @@ public interface Testable extends Perspective {

List<TestCase> testCases();

TestCase testCaseByKey(String key);
TestCase testCaseByName(String key);

int countTestCasesOfLine(Integer line);


+ 0
- 26
sonar-plugin-api/src/main/java/org/sonar/api/test/exception/TestCaseAlreadyExistsException.java View File

@@ -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));
}
}

+ 11
- 7
sonar-server/src/main/java/org/sonar/server/ui/JRubyFacade.java View File

@@ -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);
}


+ 71
- 0
sonar-server/src/main/webapp/WEB-INF/app/controllers/api/tests_controller.rb View File

@@ -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

+ 1
- 1
sonar-server/src/main/webapp/WEB-INF/app/controllers/resource_controller.rb View File

@@ -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

+ 2
- 2
sonar-server/src/main/webapp/WEB-INF/app/controllers/test_controller.rb View File

@@ -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

Loading…
Cancel
Save