]> source.dussan.org Git - sonarqube.git/commitdiff
Revert "SONAR-5218 Once a module has been turned into a project, its issues are no...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 18 Apr 2014 12:07:18 +0000 (14:07 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 18 Apr 2014 12:07:18 +0000 (14:07 +0200)
This reverts commit 6334cb7d7397e1455099611b3b1259ad050706e6.

26 files changed:
plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTrackingDecorator.java
plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingDecoratorTest.java
sonar-batch/src/main/java/org/sonar/batch/issue/DefaultIssuable.java
sonar-batch/src/main/java/org/sonar/batch/issue/IssuableFactory.java
sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
sonar-batch/src/main/java/org/sonar/batch/issue/ScanIssueStorage.java
sonar-batch/src/test/java/org/sonar/batch/issue/DefaultIssuableTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssuableFactoryTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
sonar-batch/src/test/java/org/sonar/batch/issue/ScanIssueStorageTest.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-core/src/main/java/org/sonar/core/issue/IssueUpdater.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueMapper.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java
sonar-core/src/main/java/org/sonar/core/issue/db/UpdateConflictResolver.java
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueMapper.xml
sonar-core/src/test/java/org/sonar/core/issue/DefaultIssueBuilderTest.java
sonar-core/src/test/java/org/sonar/core/issue/IssueUpdaterTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueDaoTest.java
sonar-core/src/test/java/org/sonar/core/issue/db/IssueMapperTest.java
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/issue/db/IssueMapperTest/testUpdate-result.xml
sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java

index 1838dc5311edd340903ab0d6ae67b669960e39d0..65b2a5a31a67ae63f4a9e2e7a45e25f5419f1364 100644 (file)
@@ -157,7 +157,6 @@ public class IssueTrackingDecorator implements Decorator {
       issue.setStatus(ref.getStatus());
       issue.setAssignee(ref.getAssignee());
       issue.setAuthorLogin(ref.getAuthorLogin());
-
       if (ref.getIssueAttributes() != null) {
         issue.setAttributes(KeyValueFormat.parse(ref.getIssueAttributes()));
       }
@@ -181,7 +180,6 @@ public class IssueTrackingDecorator implements Decorator {
       Long debtInMinutes = ref.getDebt();
       Duration previousTechnicalDebt = debtInMinutes != null ? Duration.create(debtInMinutes) : null;
       updater.setPastTechnicalDebt(issue, previousTechnicalDebt, changeContext);
-      updater.setPastProject(issue, ref.getRootComponentKey(), changeContext);
     }
   }
 
index 121b473d2d88d127d190e66b850bcb1d1df8a9e5..05aa5bdb2d7e23bbe930ee8deaa1de835a6191d9 100644 (file)
@@ -508,7 +508,7 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
   @Test
   public void merge_matched_issue() throws Exception {
     IssueDto previousIssue = new IssueDto().setKee("ABCDE").setResolution(null).setStatus("OPEN").setRuleKey_unit_test_only("squid", "AvoidCycle")
-      .setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L).setRootComponentKey_unit_test_only("sample");
+      .setLine(10).setSeverity("MAJOR").setMessage("Message").setEffortToFix(1.5).setDebt(1L);
     DefaultIssue issue = new DefaultIssue();
 
     IssueTrackingResult trackingResult = mock(IssueTrackingResult.class);
@@ -521,7 +521,6 @@ public class IssueTrackingDecoratorTest extends AbstractDaoTestCase {
     verify(updater).setPastMessage(eq(issue), eq("Message"), any(IssueChangeContext.class));
     verify(updater).setPastEffortToFix(eq(issue), eq(1.5), any(IssueChangeContext.class));
     verify(updater).setPastTechnicalDebt(eq(issue), eq(Duration.create(1L)), any(IssueChangeContext.class));
-    verify(updater).setPastProject(eq(issue), eq("sample"), any(IssueChangeContext.class));
   }
 
   @Test
index 578bb2bb49ef97af435c0b7ee2985ae9f47d534f..62b44e7d69e3f92888db81e474a4b0f91f6aba0d 100644 (file)
@@ -24,7 +24,6 @@ import org.sonar.api.component.Component;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.resources.Project;
 import org.sonar.core.issue.DefaultIssueBuilder;
 
 import java.util.List;
@@ -37,18 +36,16 @@ public class DefaultIssuable implements Issuable {
   private final ModuleIssues moduleIssues;
   private final IssueCache cache;
   private final Component component;
-  private final Project project;
 
-  DefaultIssuable(Component component, Project project, ModuleIssues moduleIssues, IssueCache cache) {
+  DefaultIssuable(Component component, ModuleIssues moduleIssues, IssueCache cache) {
     this.component = component;
-    this.project = project;
     this.moduleIssues = moduleIssues;
     this.cache = cache;
   }
 
   @Override
   public IssueBuilder newIssueBuilder() {
-    return new DefaultIssueBuilder().componentKey(component.key()).projectKey(project.getKey());
+    return new DefaultIssueBuilder().componentKey(component.key());
   }
 
   @Override
index 7491bbb78144e523232b3ae4923da67cf8ad08b4..147ab7c7c155e66503d93912618aa82b3ef4f8f4 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.batch.issue;
 import org.sonar.api.component.Component;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.resources.Scopes;
-import org.sonar.batch.ProjectTree;
 import org.sonar.core.component.PerspectiveBuilder;
 import org.sonar.core.component.ResourceComponent;
 
@@ -36,13 +35,11 @@ public class IssuableFactory extends PerspectiveBuilder<Issuable> {
 
   private final ModuleIssues moduleIssues;
   private final IssueCache cache;
-  private final ProjectTree projectTree;
 
-  public IssuableFactory(ModuleIssues moduleIssues, IssueCache cache, ProjectTree projectTree) {
+  public IssuableFactory(ModuleIssues moduleIssues, IssueCache cache) {
     super(Issuable.class);
     this.moduleIssues = moduleIssues;
     this.cache = cache;
-    this.projectTree = projectTree;
   }
 
   @CheckForNull
@@ -52,6 +49,6 @@ public class IssuableFactory extends PerspectiveBuilder<Issuable> {
     if (component instanceof ResourceComponent) {
       supported = Scopes.isHigherThanOrEquals(((ResourceComponent) component).scope(), Scopes.FILE);
     }
-    return supported ? new DefaultIssuable(component, projectTree.getRootProject(), moduleIssues, cache) : null;
+    return supported ? new DefaultIssuable(component, moduleIssues, cache) : null;
   }
 }
index 6f46e2cc7a9bcda27cc86d06ecbebc87d3c02f0e..c0a49d68671e6e43b617a40d3aa4dd5dbb8c14ec 100644 (file)
@@ -67,7 +67,6 @@ public class ModuleIssues {
   private DefaultIssue newIssue(Violation violation) {
     return (DefaultIssue) new DefaultIssueBuilder()
       .componentKey(violation.getResource().getEffectiveKey())
-      .projectKey(project.getRoot().getEffectiveKey())
       .ruleKey(RuleKey.of(violation.getRule().getRepositoryKey(), violation.getRule().getKey()))
       .effortToFix(violation.getCost())
       .line(violation.getLineId())
index 723082eb3355e6e99fa089b72dc5a9ce7181096b..23dab80cde165b3d4b8de2da77eb7fd06b3fed52 100644 (file)
@@ -23,7 +23,6 @@ import org.sonar.api.BatchComponent;
 import org.sonar.api.database.model.Snapshot;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rules.RuleFinder;
-import org.sonar.batch.ProjectTree;
 import org.sonar.batch.index.SnapshotCache;
 import org.sonar.core.issue.db.IssueStorage;
 import org.sonar.core.persistence.MyBatis;
@@ -35,18 +34,16 @@ public class ScanIssueStorage extends IssueStorage implements BatchComponent {
 
   private final SnapshotCache snapshotCache;
   private final ResourceDao resourceDao;
-  private final ProjectTree projectTree;
 
-  public ScanIssueStorage(MyBatis mybatis, RuleFinder ruleFinder, SnapshotCache snapshotCache, ResourceDao resourceDao, ProjectTree projectTree) {
+  public ScanIssueStorage(MyBatis mybatis, RuleFinder ruleFinder, SnapshotCache snapshotCache, ResourceDao resourceDao) {
     super(mybatis, ruleFinder);
     this.snapshotCache = snapshotCache;
     this.resourceDao = resourceDao;
-    this.projectTree = projectTree;
   }
 
   @Override
   protected long componentId(DefaultIssue issue) {
-    Snapshot snapshot = snapshotCache.get(issue.componentKey());
+    Snapshot snapshot = getSnapshot(issue);
     if (snapshot != null) {
       return snapshot.getResourceId();
     }
@@ -61,7 +58,19 @@ public class ScanIssueStorage extends IssueStorage implements BatchComponent {
 
   @Override
   protected long projectId(DefaultIssue issue) {
-    return projectTree.getRootProject().getId();
+    Snapshot snapshot = getSnapshot(issue);
+    if (snapshot != null) {
+      return snapshot.getRootProjectId();
+    }
+    throw new IllegalStateException("Project id not found for: " + issue.componentKey());
+  }
+
+  private Snapshot getSnapshot(DefaultIssue issue) {
+    Snapshot snapshot = snapshotCache.get(issue.componentKey());
+    if (snapshot != null) {
+      return snapshot;
+    }
+    return null;
   }
 
 }
index 90721058222c99a0aa063002cb9f876b4b186376..1f557c64ad12c732be718d08c3c1c74e091555b2 100644 (file)
@@ -23,7 +23,6 @@ import org.junit.Test;
 import org.sonar.api.component.Component;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.resources.Project;
 
 import java.util.Arrays;
 import java.util.List;
@@ -36,7 +35,6 @@ public class DefaultIssuableTest {
 
   ModuleIssues moduleIssues = mock(ModuleIssues.class);
   IssueCache cache = mock(IssueCache.class);
-  Project project = mock(Project.class);
   Component component = mock(Component.class);
 
   @Test
@@ -46,7 +44,7 @@ public class DefaultIssuableTest {
     DefaultIssue unresolved = new DefaultIssue();
     when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved));
 
-    DefaultIssuable perspective = new DefaultIssuable(component, project, moduleIssues, cache);
+    DefaultIssuable perspective = new DefaultIssuable(component, moduleIssues, cache);
 
     List<Issue> issues = perspective.issues();
     assertThat(issues).containsOnly(unresolved);
@@ -59,7 +57,7 @@ public class DefaultIssuableTest {
     DefaultIssue unresolved = new DefaultIssue();
     when(cache.byComponent("struts:org.apache.Action")).thenReturn(Arrays.asList(resolved, unresolved));
 
-    DefaultIssuable perspective = new DefaultIssuable(component, project, moduleIssues, cache);
+    DefaultIssuable perspective = new DefaultIssuable(component, moduleIssues, cache);
 
     List<Issue> issues = perspective.resolvedIssues();
     assertThat(issues).containsOnly(resolved);
index 4753023ccbc64702cb541b1d2884ddac76ac59bc..d11d0a7211160ed6fb020aff10802e7b9d01e6d5 100644 (file)
@@ -25,7 +25,6 @@ import org.sonar.api.component.Component;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.resources.File;
 import org.sonar.api.resources.Project;
-import org.sonar.batch.ProjectTree;
 import org.sonar.core.component.ResourceComponent;
 
 import static org.fest.assertions.Assertions.assertThat;
@@ -35,11 +34,10 @@ public class IssuableFactoryTest {
 
   ModuleIssues moduleIssues = mock(ModuleIssues.class);
   IssueCache cache = mock(IssueCache.class, Mockito.RETURNS_MOCKS);
-  ProjectTree projectTree = mock(ProjectTree.class);
 
   @Test
   public void file_should_be_issuable() throws Exception {
-    IssuableFactory factory = new IssuableFactory(moduleIssues, cache, projectTree);
+    IssuableFactory factory = new IssuableFactory(moduleIssues, cache);
     Component component = new ResourceComponent(new File("foo/bar.c").setEffectiveKey("foo/bar.c"));
     Issuable issuable = factory.loadPerspective(Issuable.class, component);
 
@@ -50,7 +48,7 @@ public class IssuableFactoryTest {
 
   @Test
   public void project_should_be_issuable() throws Exception {
-    IssuableFactory factory = new IssuableFactory(moduleIssues, cache, projectTree);
+    IssuableFactory factory = new IssuableFactory(moduleIssues, cache);
     Component component = new ResourceComponent(new Project("Foo").setEffectiveKey("foo"));
     Issuable issuable = factory.loadPerspective(Issuable.class, component);
 
index bacfe55be16fb3f0945700cf93f467cd403df25a..3df87485b74fe1ff80d6eaa3b6c716a10d792c19 100644 (file)
@@ -73,7 +73,6 @@ public class ModuleIssuesTest {
   public void setUp() {
     when(project.getAnalysisDate()).thenReturn(new Date());
     when(project.getEffectiveKey()).thenReturn("org.apache:struts-core");
-    when(project.getRoot()).thenReturn(project);
   }
 
   @Test
@@ -226,7 +225,6 @@ public class ModuleIssuesTest {
     assertThat(issue.key()).isNotEmpty();
     assertThat(issue.ruleKey().toString()).isEqualTo("squid:AvoidCycle");
     assertThat(issue.componentKey()).isEqualTo("struts:src/org/struts/Action.java");
-    assertThat(issue.projectKey()).isEqualTo("org.apache:struts-core");
   }
 
   @Test
index 8866851b3da2cea818fa6678ca53cd53b9ffc0b0..7875ae97f25bdddd194308a35fccbfcba85ed235 100644 (file)
  */
 package org.sonar.batch.issue;
 
-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.database.model.Snapshot;
 import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.RuleQuery;
-import org.sonar.batch.ProjectTree;
 import org.sonar.batch.index.SnapshotCache;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.resource.ResourceDao;
@@ -40,28 +34,16 @@ import java.util.Collection;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-@RunWith(MockitoJUnitRunner.class)
 public class ScanIssueStorageTest extends AbstractDaoTestCase {
-
-  @Mock
-  SnapshotCache snapshotCache;
-
-  @Mock
-  ProjectTree projectTree;
-
-  ScanIssueStorage storage;
-
-  @Before
-  public void setUp() throws Exception {
-    storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()), projectTree);
-  }
-
   @Test
   public void should_load_component_id_from_cache() throws Exception {
+    SnapshotCache snapshotCache = mock(SnapshotCache.class);
     when(snapshotCache.get("struts:Action.java")).thenReturn(new Snapshot().setResourceId(123));
 
+    ScanIssueStorage storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()));
     long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
 
     assertThat(componentId).isEqualTo(123);
@@ -70,8 +52,10 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
   @Test
   public void should_load_component_id_from_db() throws Exception {
     setupData("should_load_component_id_from_db");
+    SnapshotCache snapshotCache = mock(SnapshotCache.class);
     when(snapshotCache.get("struts:Action.java")).thenReturn(null);
 
+    ScanIssueStorage storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()));
     long componentId = storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
 
     assertThat(componentId).isEqualTo(123);
@@ -80,8 +64,10 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
   @Test
   public void should_fail_to_load_component_id_if_unknown_component() throws Exception {
     setupData("should_fail_to_load_component_id_if_unknown_component");
+    SnapshotCache snapshotCache = mock(SnapshotCache.class);
     when(snapshotCache.get("struts:Action.java")).thenReturn(null);
 
+    ScanIssueStorage storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()));
     try {
       storage.componentId(new DefaultIssue().setComponentKey("struts:Action.java"));
       fail();
@@ -92,13 +78,29 @@ public class ScanIssueStorageTest extends AbstractDaoTestCase {
 
   @Test
   public void should_load_project_id() throws Exception {
-    when(projectTree.getRootProject()).thenReturn((Project) new Project("struts").setId(100));
+    SnapshotCache snapshotCache = mock(SnapshotCache.class);
+    when(snapshotCache.get("struts:Action.java")).thenReturn(new Snapshot().setResourceId(123).setRootProjectId(100));
 
+    ScanIssueStorage storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()));
     long projectId = storage.projectId(new DefaultIssue().setComponentKey("struts:Action.java"));
 
     assertThat(projectId).isEqualTo(100);
   }
 
+  @Test
+  public void should_fail_to_load_project_id_if_unknown_component() throws Exception {
+    SnapshotCache snapshotCache = mock(SnapshotCache.class);
+    when(snapshotCache.get("struts:Action.java")).thenReturn(null);
+
+    ScanIssueStorage storage = new ScanIssueStorage(getMyBatis(), new FakeRuleFinder(), snapshotCache, new ResourceDao(getMyBatis()));
+    try {
+      storage.projectId(new DefaultIssue().setComponentKey("struts:Action.java"));
+      fail();
+    } catch (Exception e) {
+      assertThat(e).hasMessage("Project id not found for: struts:Action.java");
+    }
+  }
+
   static class FakeRuleFinder implements RuleFinder {
 
     @Override
index 859ad804ad234819b5ade20c97e8dd7bc4f360fe..68284cb07ce190b744a0eba8496d8656a2ce3ba7 100644 (file)
@@ -35,7 +35,6 @@ import java.util.UUID;
 public class DefaultIssueBuilder implements Issuable.IssueBuilder {
 
   private String componentKey;
-  private String projectKey;
   private RuleKey ruleKey;
   private Integer line;
   private String message;
@@ -53,12 +52,6 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     return this;
   }
 
-
-  public DefaultIssueBuilder projectKey(String projectKey) {
-    this.projectKey = projectKey;
-    return this;
-  }
-
   @Override
   public Issuable.IssueBuilder ruleKey(RuleKey ruleKey) {
     this.ruleKey = ruleKey;
@@ -106,7 +99,6 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
 
   @Override
   public DefaultIssue build() {
-    Preconditions.checkNotNull(projectKey, "Project key must be set");
     Preconditions.checkNotNull(componentKey, "Component key must be set");
     Preconditions.checkNotNull(ruleKey, "Rule key must be set");
 
@@ -115,7 +107,6 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
     issue.setKey(key);
     issue.setComponentKey(componentKey);
-    issue.setProjectKey(projectKey);
     issue.setRuleKey(ruleKey);
     issue.setMessage(message);
     issue.setSeverity(severity);
index 9ac381eeffddf25601252f106aa0e7082f7609a2..cdd3717f699aa91bbc0a19ed97e7643d88a88d11 100644 (file)
@@ -247,20 +247,4 @@ public class IssueUpdater implements BatchComponent, ServerComponent {
     return false;
   }
 
-  public boolean setProject(DefaultIssue issue, String key, IssueChangeContext context) {
-    if (!Objects.equal(key, issue.projectKey())) {
-      issue.setProjectKey(key);
-      issue.setUpdateDate(context.date());
-      issue.setChanged(true);
-      return true;
-    }
-    return false;
-  }
-
-  public boolean setPastProject(DefaultIssue issue, String previousKey, IssueChangeContext context) {
-    String currentProjectKey = issue.projectKey();
-    issue.setProjectKey(previousKey);
-    return setProject(issue, currentProjectKey, context);
-  }
-
 }
index be0d275f1cd00981152ce2df66a6f9ed737514a4..3b7aa30ccc490e61c45eee61180b85e24c120141 100644 (file)
@@ -390,7 +390,7 @@ public final class IssueDto implements Serializable {
       .setUpdatedAt(now);
   }
 
-  public static IssueDto toDtoForUpdate(DefaultIssue issue, Long rootComponentId, Date now) {
+  public static IssueDto toDtoForUpdate(DefaultIssue issue, Date now) {
     // Invariant fields, like key and rule, can't be updated
     return new IssueDto()
       .setKee(issue.key())
@@ -408,7 +408,6 @@ public final class IssueDto implements Serializable {
       .setActionPlanKey(issue.actionPlanKey())
       .setIssueAttributes(KeyValueFormat.format(issue.attributes()))
       .setAuthorLogin(issue.authorLogin())
-      .setRootComponentId(rootComponentId)
       .setIssueCreationDate(issue.creationDate())
       .setIssueCloseDate(issue.closeDate())
       .setIssueUpdateDate(issue.updateDate())
index 600b5e4f8c2e0dab00d605a4df6b2c01944e2e32..3c3a878489130381d9daa4d0bc08a2cd68b5ab96 100644 (file)
@@ -31,6 +31,8 @@ public interface IssueMapper {
 
   IssueDto selectByKey(String key);
 
+  List<IssueDto> selectNonClosedIssuesByModule(int rootComponentId);
+
   /**
    * Return a paginated list of authorized issue ids for a user.
    * If the role is null, then the authorisation check is disabled.
index a52f728a5dfc0154ff23df1144cf42a8f80cd01b..fad9862d7bec7519f05fde6e0a6add1992576584 100644 (file)
@@ -119,7 +119,7 @@ public abstract class IssueStorage {
   }
 
   private void update(IssueMapper issueMapper, Date now, DefaultIssue issue) {
-    IssueDto dto = IssueDto.toDtoForUpdate(issue, projectId(issue), now);
+    IssueDto dto = IssueDto.toDtoForUpdate(issue, now);
     if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) {
       // Issue is closed by scan or changed by end-user
       issueMapper.update(dto);
index 73370a7face4a717d06ab85d52ad44c0be1799c0..536667cae3f8d00c998c1825d026b719b6f443e7 100644 (file)
@@ -41,7 +41,7 @@ class UpdateConflictResolver {
     IssueDto dbIssue = mapper.selectByKey(issue.key());
     if (dbIssue != null) {
       mergeFields(dbIssue, issue);
-      mapper.update(IssueDto.toDtoForUpdate(issue, dbIssue.getRootComponentId(), new Date()));
+      mapper.update(IssueDto.toDtoForUpdate(issue, new Date()));
     }
   }
 
index bd85afc93136c9d4ea01fa75a6cf60de827277ca..a3e153780414aef4d968e6158a0407995db82a4e 100644 (file)
@@ -89,7 +89,6 @@
     reporter=#{reporter},
     assignee=#{assignee},
     author_login=#{authorLogin},
-    root_component_id=#{rootComponentId},
     issue_attributes=#{issueAttributes},
     issue_creation_date=#{issueCreationDate},
     issue_update_date=#{issueUpdateDate},
     reporter=#{reporter},
     assignee=#{assignee},
     author_login=#{authorLogin},
-    root_component_id=#{rootComponentId},
     issue_attributes=#{issueAttributes},
     issue_creation_date=#{issueCreationDate},
     issue_update_date=#{issueUpdateDate},
       i.updated_at as updatedAt,
       r.plugin_rule_key as ruleKey,
       r.plugin_name as ruleRepo,
-      p.kee as componentKey,
-      root.kee as rootComponentKey
+      p.kee as componentKey
     from issues i
-    inner join (select p.id,p.kee from projects p where (p.root_id=#{id} and p.qualifier &lt;&gt; 'BRC') or (p.id=#{id})) p on p.id=i.component_id
     inner join rules r on r.id=i.rule_id
-    left outer join projects root on root.id=i.root_component_id
+    inner join (select p.id,p.kee from projects p where (p.root_id=#{id} and p.qualifier &lt;&gt; 'BRC') or (p.id=#{id})) p on p.id=i.component_id
     <where>
       and i.status &lt;&gt; 'CLOSED'
     </where>
index 30b34609c003a3e0c7d1a71f0937f6aaf0507493..916be3ea6e1dde892fd6dd66dca910655296941e 100644 (file)
@@ -32,10 +32,8 @@ public class DefaultIssueBuilderTest {
   @Test
   public void build_new_issue() throws Exception {
     String componentKey = "org.apache.struts:struts-core:Action.java";
-    String projectKey = "org.apache.struts";
     DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
       .componentKey(componentKey)
-      .projectKey(projectKey)
       .message("the message")
       .line(123)
       .effortToFix(10000.0)
@@ -49,7 +47,6 @@ public class DefaultIssueBuilderTest {
     assertThat(issue.key()).isNotNull();
     assertThat(issue.effortToFix()).isEqualTo(10000.0);
     assertThat(issue.componentKey()).isEqualTo(componentKey);
-    assertThat(issue.projectKey()).isEqualTo(projectKey);
     assertThat(issue.message()).isEqualTo("the message");
     assertThat(issue.line()).isEqualTo(123);
     assertThat(issue.ruleKey().repository()).isEqualTo("squid");
@@ -68,7 +65,6 @@ public class DefaultIssueBuilderTest {
   public void not_set_default_severity() {
     DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
       .componentKey("Action.java")
-      .projectKey("org.apache.struts")
       .ruleKey(RuleKey.of("squid", "NullDereference"))
       .build();
 
index 5373ebef6ebc138970039bd6c04a4a99f1659d24..c0dfa62ec32703d8790cd70b1fe2d5f7deb08127 100644 (file)
@@ -447,35 +447,4 @@ public class IssueUpdaterTest {
     assertThat(issue.mustSendNotifications()).isFalse();
   }
 
-  @Test
-  public void set_project() throws Exception {
-    boolean updated = updater.setProject(issue, "sample", context);
-    assertThat(updated).isTrue();
-    assertThat(issue.projectKey()).isEqualTo("sample");
-
-    // do not save change
-    assertThat(issue.currentChange()).isNull();
-    assertThat(issue.mustSendNotifications()).isFalse();
-  }
-
-  @Test
-  public void set_past_project() throws Exception {
-    issue.setProjectKey("new project key");
-    boolean updated = updater.setPastProject(issue, "past project key", context);
-    assertThat(updated).isTrue();
-    assertThat(issue.projectKey()).isEqualTo("new project key");
-
-    // do not save change
-    assertThat(issue.currentChange()).isNull();
-    assertThat(issue.mustSendNotifications()).isFalse();
-  }
-
-  @Test
-  public void not_set_past_project_if_no_change() throws Exception {
-    issue.setProjectKey("key");
-    boolean updated = updater.setPastProject(issue, "key", context);
-    assertThat(updated).isFalse();
-    assertThat(issue.projectKey()).isEqualTo("key");
-  }
-
 }
index 45790762a26466bd376eed3cad04b9b8d9b5cd39..a8087a3d4d8bbeff6cfe3ad4e7de328fb54a8fc1 100644 (file)
@@ -310,7 +310,7 @@ public class IssueDaoTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void select_non_closed_issues_by_module() {
+  public void should_select_non_closed_issues_by_module() {
     setupData("shared", "should_select_non_closed_issues_by_module");
 
     // 400 is a non-root module, we should find 2 issues from classes and one on itself
@@ -322,37 +322,11 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     assertThat(issue.getRuleRepo()).isNotNull();
     assertThat(issue.getRule()).isNotNull();
     assertThat(issue.getComponentKey()).isNotNull();
-    assertThat(issue.getRootComponentKey()).isEqualTo("struts");
 
     // 399 is the root module, we should only find 1 issue on itself
     handler = new DefaultResultHandler();
     dao.selectNonClosedIssuesByModule(399, handler);
     assertThat(handler.getResultList()).hasSize(1);
-
-    issue = (IssueDto) handler.getResultList().get(0);
-    assertThat(issue.getComponentKey()).isEqualTo("struts");
-    assertThat(issue.getRootComponentKey()).isEqualTo("struts");
-  }
-
-  /**
-   * SONAR-5218
-   */
-  @Test
-  public void select_non_closed_issues_by_module_on_removed_project() {
-    // All issues are linked on a project that is not existing anymore
-
-    setupData("shared", "should_select_non_closed_issues_by_module_on_removed_project");
-
-    // 400 is a non-root module, we should find 2 issues from classes and one on itself
-    DefaultResultHandler handler = new DefaultResultHandler();
-    dao.selectNonClosedIssuesByModule(400, handler);
-    assertThat(handler.getResultList()).hasSize(3);
-
-    IssueDto issue = (IssueDto) handler.getResultList().get(0);
-    assertThat(issue.getRuleRepo()).isNotNull();
-    assertThat(issue.getRule()).isNotNull();
-    assertThat(issue.getComponentKey()).isNotNull();
-    assertThat(issue.getRootComponentKey()).isNull();
   }
 
   @Test
index 705c5358ea81df4912d448a591fcb729a9414d09..e3e074562ee2ac98fc2529cb54e8bbe0781a966c 100644 (file)
@@ -84,7 +84,7 @@ public class IssueMapperTest extends AbstractDaoTestCase {
 
     IssueDto dto = new IssueDto();
     dto.setComponentId(123l);
-    dto.setRootComponentId(101l);
+    dto.setRootComponentId(100l);
     dto.setRuleId(200);
     dto.setKee("ABCDE");
     dto.setLine(500);
@@ -119,7 +119,7 @@ public class IssueMapperTest extends AbstractDaoTestCase {
 
     IssueDto dto = new IssueDto();
     dto.setComponentId(123l);
-    dto.setRootComponentId(101l);
+    dto.setRootComponentId(100l);
     dto.setRuleId(200);
     dto.setKee("ABCDE");
     dto.setLine(500);
@@ -157,7 +157,7 @@ public class IssueMapperTest extends AbstractDaoTestCase {
 
     IssueDto dto = new IssueDto();
     dto.setComponentId(123l);
-    dto.setRootComponentId(101l);
+    dto.setRootComponentId(100l);
     dto.setRuleId(200);
     dto.setKee("ABCDE");
     dto.setLine(500);
diff --git a/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml b/sonar-core/src/test/resources/org/sonar/core/issue/db/IssueDaoTest/should_select_non_closed_issues_by_module_on_removed_project.xml
deleted file mode 100644 (file)
index bb4aaf5..0000000
+++ /dev/null
@@ -1,127 +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
-  -->
-
-<dataset>
-
-  <!-- Open Issue on a file -->
-  <issues
-      id="100"
-      kee="100"
-      component_id="401"
-      root_component_id="111"
-      rule_id="500"
-      severity="BLOCKER"
-      manual_severity="[false]"
-      message="[null]"
-      line="200"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="user"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="2013-04-16"
-      issue_update_date="2013-04-16"
-      issue_close_date="2013-04-16"
-      created_at="2013-04-16"
-      updated_at="[null]"
-      />
-
-  <!-- Open Issue on a file -->
-  <issues
-      id="101"
-      kee="101"
-      component_id="402"
-      root_component_id="111"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="120"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="2013-04-16"
-      issue_update_date="2013-04-16"
-      issue_close_date="2013-04-16"
-      created_at="2013-04-10"
-      updated_at="[null]"
-      />
-
-  <!-- Closed Issue on a file -->
-  <issues
-      id="102"
-      kee="102"
-      component_id="402"
-      root_component_id="111"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="120"
-      effort_to_fix="[null]"
-      status="CLOSED"
-      resolution="FIXED"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="2013-04-16"
-      issue_update_date="2013-04-16"
-      issue_close_date="2013-04-16"
-      created_at="2013-04-10"
-      updated_at="[null]"
-      />
-
-  <!-- Open Issue on a sub module -->
-  <issues
-      id="103"
-      kee="103"
-      component_id="400"
-      root_component_id="111"
-      rule_id="501"
-      severity="MAJOR"
-      manual_severity="[false]"
-      message="[null]"
-      line="[null]"
-      effort_to_fix="[null]"
-      status="OPEN"
-      resolution="[null]"
-      checksum="[null]"
-      reporter="[null]"
-      assignee="user"
-      author_login="[null]"
-      issue_attributes="[null]"
-      issue_creation_date="2013-04-16"
-      issue_update_date="2013-04-16"
-      issue_close_date="2013-04-16"
-      created_at="2013-04-10"
-      updated_at="[null]"
-      />
-
-</dataset>
index a923dfa54e0de4c9b31ae68d516c7e54dc089ee5..8016cfac576d926ec1f9b962ca6c63570ec43fc4 100644 (file)
@@ -3,7 +3,7 @@
       id="100"
       kee="ABCDE"
       component_id="123"
-      root_component_id="101"
+      root_component_id="100"
       rule_id="200"
       severity="BLOCKER"
       manual_severity="[false]"
index d0362da17d0746f85517b555c516ee62875567db..bef324ee95fc35f17b3869b158cb7fe5a5d54ca7 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.issue;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
+import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
@@ -35,9 +36,11 @@ import org.sonar.api.issue.action.Action;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.issue.internal.FieldDiffs;
 import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.Severity;
 import org.sonar.api.utils.SonarException;
 import org.sonar.core.issue.ActionPlanStats;
 import org.sonar.core.issue.DefaultActionPlan;
+import org.sonar.core.issue.DefaultIssueBuilder;
 import org.sonar.core.issue.DefaultIssueFilter;
 import org.sonar.core.issue.workflow.Transition;
 import org.sonar.core.resource.ResourceDao;
@@ -233,8 +236,16 @@ public class InternalRubyIssueService implements ServerComponent {
       }
 
       if (result.ok()) {
-        DefaultIssue issue = issueService.createManualIssue(componentKey, ruleKey, RubyUtils.toInteger(params.get("line")), params.get("message"), params.get("severity"),
-          RubyUtils.toDouble(params.get("effortToFix")), UserSession.get());
+        DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
+          .componentKey(componentKey)
+          .line(RubyUtils.toInteger(params.get("line")))
+          .message(params.get("message"))
+          .severity(Objects.firstNonNull(params.get("severity"), Severity.MAJOR))
+          .effortToFix(RubyUtils.toDouble(params.get("effortToFix")))
+          .ruleKey(ruleKey)
+          .reporter(UserSession.get().login())
+          .build();
+        issue = issueService.createManualIssue(issue, UserSession.get());
         result.set(issue);
       }
 
index 7db9d49daca97da01dfc3ee4922b9088ab0abb4a..db1664a919caf2c697f3438a76851423e7b85de2 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.issue;
 
-import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import org.apache.commons.lang.StringUtils;
 import org.sonar.api.ServerComponent;
@@ -29,14 +28,11 @@ import org.sonar.api.issue.IssueQuery;
 import org.sonar.api.issue.IssueQueryResult;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.user.User;
 import org.sonar.api.user.UserFinder;
 import org.sonar.api.web.UserRole;
-import org.sonar.core.issue.DefaultIssueBuilder;
 import org.sonar.core.issue.IssueNotifications;
 import org.sonar.core.issue.IssueUpdater;
 import org.sonar.core.issue.db.IssueStorage;
@@ -206,26 +202,15 @@ public class IssueService implements ServerComponent {
     return issue;
   }
 
-  public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity,
-                                        @Nullable Double effortToFix, UserSession userSession) {
+  public DefaultIssue createManualIssue(DefaultIssue issue, UserSession userSession) {
     verifyLoggedIn(userSession);
-    ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(componentKey));
-    ResourceDto project = resourceDao.getRootProjectByComponentKey(componentKey);
-    if (resourceDto == null || project == null) {
-      throw new IllegalArgumentException("Unknown component: " + componentKey);
+    ResourceDto resourceDto = resourceDao.getResource(ResourceQuery.create().setKey(issue.componentKey()));
+    if (resourceDto == null) {
+      throw new IllegalArgumentException("Unknown component: " + issue.componentKey());
     }
-
-    DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
-      .componentKey(resourceDto.getKey())
-      .projectKey(project.getKey())
-      .line(line)
-      .message(message)
-      .severity(Objects.firstNonNull(severity, Severity.MAJOR))
-      .effortToFix(effortToFix)
-      .ruleKey(ruleKey)
-      .reporter(UserSession.get().login())
-      .build();
-
+    // Force use of correct key in case deprecated key is used
+    issue.setComponentKey(resourceDto.getKey());
+    issue.setComponentId(resourceDto.getId());
     if (!authorizationDao.isAuthorizedComponentKey(resourceDto.getKey(), userSession.userId(), UserRole.USER)) {
       // TODO throw unauthorized
       throw new IllegalStateException("User does not have the required role");
index 3f842e788f4788f5e82a0c9d4583f2109fc4612c..7d27a4bb842c2d6c4816a1488bd69e54f6a0fed0 100644 (file)
@@ -22,10 +22,7 @@ package org.sonar.server.issue;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
 import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueQuery;
@@ -64,56 +61,23 @@ import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.*;
 
-@RunWith(MockitoJUnitRunner.class)
 public class IssueServiceTest {
 
-  @Mock
-  DefaultIssueFinder finder;
-
-  @Mock
-  IssueWorkflow workflow;
-
-  @Mock
-  IssueUpdater issueUpdater;
-
-  @Mock
-  IssueStorage issueStorage;
-
-  @Mock
-  IssueNotifications issueNotifications;
-
-  @Mock
-  ActionPlanService actionPlanService;
-
-  @Mock
-  RuleFinder ruleFinder;
-
-  @Mock
-  ResourceDao resourceDao;
-
-  @Mock
-  AuthorizationDao authorizationDao;
-
-  @Mock
-  UserFinder userFinder;
-
-  @Mock
-  UserSession userSession;
-
-  @Mock
-  IssueQueryResult issueQueryResult;
-
-  @Mock
-  ResourceDto resource;
-
-  @Mock
-  ResourceDto project;
-
-  Transition transition = Transition.create("reopen", Issue.STATUS_RESOLVED, Issue.STATUS_REOPENED);
-
-  DefaultIssue issue = new DefaultIssue().setKey("ABCD");
-
-  IssueService issueService;
+  private DefaultIssueFinder finder = mock(DefaultIssueFinder.class);
+  private IssueWorkflow workflow = mock(IssueWorkflow.class);
+  private IssueUpdater issueUpdater = mock(IssueUpdater.class);
+  private IssueStorage issueStorage = mock(IssueStorage.class);
+  private IssueNotifications issueNotifications = mock(IssueNotifications.class);
+  private ActionPlanService actionPlanService = mock(ActionPlanService.class);
+  private RuleFinder ruleFinder = mock(RuleFinder.class);
+  private ResourceDao resourceDao = mock(ResourceDao.class);
+  private AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
+  private UserFinder userFinder = mock(UserFinder.class);
+  private UserSession userSession = mock(UserSession.class);
+  private Transition transition = Transition.create("reopen", Issue.STATUS_RESOLVED, Issue.STATUS_REOPENED);
+  private IssueQueryResult issueQueryResult = mock(IssueQueryResult.class);
+  private DefaultIssue issue = new DefaultIssue().setKey("ABCD");
+  private IssueService issueService;
 
   @Before
   public void before() {
@@ -126,21 +90,18 @@ public class IssueServiceTest {
     when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) issue));
     when(issueQueryResult.first()).thenReturn(issue);
 
-    when(resource.getKey()).thenReturn("org.sonar.Sample");
-    when(project.getKey()).thenReturn("Sample");
-
     issueService = new IssueService(finder, workflow, issueStorage, issueUpdater, issueNotifications, actionPlanService, ruleFinder, resourceDao, authorizationDao, userFinder,
       mock(PreviewCache.class));
   }
 
   @Test
-  public void load_issue() {
+  public void should_load_issue() {
     IssueQueryResult result = issueService.loadIssue("ABCD");
     assertThat(result).isEqualTo(issueQueryResult);
   }
 
   @Test
-  public void fail_to_load_issue() {
+  public void should_fail_to_load_issue() {
     when(issueQueryResult.issues()).thenReturn(Collections.<Issue>emptyList());
     when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult);
 
@@ -153,13 +114,13 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void list_status() {
+  public void should_list_status() {
     issueService.listStatus();
     verify(workflow).statusKeys();
   }
 
   @Test
-  public void list_transitions() {
+  public void should_list_transitions() {
     List<Transition> transitions = newArrayList(transition);
     when(workflow.outTransitions(issue)).thenReturn(transitions);
 
@@ -169,7 +130,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void return_no_transition() {
+  public void should_return_no_transition() {
     when(issueQueryResult.first()).thenReturn(null);
     when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) new DefaultIssue()));
 
@@ -178,7 +139,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void do_transition() {
+  public void should_do_transition() {
     when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(true);
 
     Issue result = issueService.doTransition("ABCD", transition.key(), userSession);
@@ -196,7 +157,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void not_do_transition() {
+  public void should_not_do_transition() {
     when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(false);
 
     Issue result = issueService.doTransition("ABCD", transition.key(), userSession);
@@ -207,7 +168,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_do_transition_if_not_logged() {
+  public void should_fail_do_transition_if_not_logged() {
     when(userSession.isLoggedIn()).thenReturn(false);
     try {
       issueService.doTransition("ABCD", transition.key(), userSession);
@@ -219,7 +180,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void assign() {
+  public void should_assign() {
     String assignee = "perceval";
     User user = new DefaultUser();
 
@@ -241,7 +202,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void unassign() {
+  public void should_unassign() {
     when(issueUpdater.assign(eq(issue), eq((User) null), any(IssueChangeContext.class))).thenReturn(true);
 
     Issue result = issueService.assign("ABCD", null, userSession);
@@ -260,7 +221,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void not_assign() {
+  public void should_not_assign() {
     String assignee = "perceval";
     User user = new DefaultUser();
 
@@ -276,7 +237,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_assign_if_assignee_not_found() {
+  public void should_fail_assign_if_assignee_not_found() {
     String assignee = "perceval";
 
     when(userFinder.findByLogin(assignee)).thenReturn(null);
@@ -294,7 +255,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void plan() {
+  public void should_plan() {
     String actionPlanKey = "EFGH";
 
     ActionPlan actionPlan = new DefaultActionPlan();
@@ -317,7 +278,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void unplan() {
+  public void should_unplan() {
     when(issueUpdater.plan(eq(issue), eq((ActionPlan) null), any(IssueChangeContext.class))).thenReturn(true);
 
     Issue result = issueService.plan("ABCD", null, userSession);
@@ -336,7 +297,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void not_plan() {
+  public void should_not_plan() {
     String actionPlanKey = "EFGH";
 
     ActionPlan actionPlan = new DefaultActionPlan();
@@ -352,7 +313,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_plan_if_action_plan_not_found() {
+  public void should_fail_plan_if_action_plan_not_found() {
     String actionPlanKey = "EFGH";
 
     when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(null);
@@ -369,7 +330,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void set_severity() {
+  public void should_set_severity() {
     String severity = "MINOR";
     when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(true);
 
@@ -388,7 +349,7 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void not_set_severity() {
+  public void should_not_set_severity() {
     String severity = "MINOR";
     when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(false);
 
@@ -402,47 +363,47 @@ public class IssueServiceTest {
   @Test
   public void create_manual_issue() {
     RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(RuleKey.of("manual", "manualRuleKey")).setComponentKey("org.sonar.Sample").setMessage("Fix it");
     when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class));
 
-    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "Fix it", null, null, userSession);
+    Issue result = issueService.createManualIssue(manualIssue, userSession);
     assertThat(result).isNotNull();
     assertThat(result.message()).isEqualTo("Fix it");
     assertThat(result.creationDate()).isNotNull();
     assertThat(result.updateDate()).isNotNull();
 
-    verify(issueStorage).save(any(DefaultIssue.class));
+    verify(issueStorage).save(manualIssue);
     verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER));
   }
 
   @Test
   public void create_manual_issue_use_rule_name_if_no_message() {
     RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(RuleKey.of("manual", "manualRuleKey")).setComponentKey("org.sonar.Sample").setMessage("");
     when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey").setName("Manual Rule"));
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class));
 
-    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "", null, null, userSession);
+    Issue result = issueService.createManualIssue(manualIssue, userSession);
     assertThat(result).isNotNull();
     assertThat(result.message()).isEqualTo("Manual Rule");
     assertThat(result.creationDate()).isNotNull();
     assertThat(result.updateDate()).isNotNull();
 
-    verify(issueStorage).save(any(DefaultIssue.class));
+    verify(issueStorage).save(manualIssue);
     verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER));
   }
 
   @Test
-  public void fail_create_manual_issue_if_not_having_required_role() {
+  public void should_fail_create_manual_issue_if_not_having_required_role() {
     RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class));
     when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
     when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false);
 
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(ruleKey).setComponentKey("org.sonar.Sample");
     try {
-      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null, userSession);
+      issueService.createManualIssue(manualIssue, userSession);
       fail();
     } catch (Exception e) {
       assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User does not have the required role");
@@ -450,13 +411,13 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_create_manual_issue_if_not_manual_rule() {
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+  public void should_fail_create_manual_issue_if_not_manual_rule() {
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class));
 
     RuleKey ruleKey = RuleKey.of("squid", "s100");
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(ruleKey).setComponentKey("org.sonar.Sample");
     try {
-      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null, userSession);
+      issueService.createManualIssue(manualIssue, userSession);
       fail();
     } catch (Exception e) {
       assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues can be created only on rules marked as 'manual': squid:s100");
@@ -465,14 +426,14 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_create_manual_issue_if_rule_not_found() {
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+  public void should_fail_create_manual_issue_if_rule_not_found() {
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(mock(ResourceDto.class));
 
     RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(RuleKey.of("manual", "manualRuleKey")).setComponentKey("org.sonar.Sample");
     when(ruleFinder.findByKey(ruleKey)).thenReturn(null);
     try {
-      issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, null, null, null, userSession);
+      issueService.createManualIssue(manualIssue, userSession);
       fail();
     } catch (Exception e) {
       assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown rule: manual:manualRuleKey");
@@ -481,12 +442,13 @@ public class IssueServiceTest {
   }
 
   @Test
-  public void fail_create_manual_issue_if_component_not_found() {
+  public void should_fail_create_manual_issue_if_component_not_found() {
     RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    DefaultIssue manualIssue = new DefaultIssue().setKey("GHIJ").setRuleKey(RuleKey.of("manual", "manualRuleKey")).setComponentKey("org.sonar.Sample");
     when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
     when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null);
     try {
-      issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, null, null, null, userSession);
+      issueService.createManualIssue(manualIssue, userSession);
       fail();
     } catch (Exception e) {
       assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown component: org.sonar.Sample");