]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5531 Provide an implementation based on ES of all "issues relating" web services
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 17 Sep 2014 09:24:27 +0000 (11:24 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 17 Sep 2014 09:24:27 +0000 (11:24 +0200)
36 files changed:
server/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueService.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java
server/sonar-server/src/main/java/org/sonar/server/issue/OldIssueService.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueActionsWriter.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentAppActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueServiceMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyDefaultIssueServiceTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/issue/OldDefaultIssueServiceTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyDefaultIssueServiceTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueDaoTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueAuthorizationIndexMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueActionsWriterTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueSearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowActionTest.java
server/sonar-server/src/test/java/org/sonar/server/rule/RuleTesting.java
server/sonar-server/src/test/java/org/sonar/server/search/IndexSynchronizerMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/get_by_key.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/insert-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/should_select_all.xml [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/some_issues.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update.xml [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/IssueNotifications.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/permission/PermissionFacade.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/IssueQueryResult.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueService.java
new file mode 100644 (file)
index 0000000..c19387a
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * 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.issue;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueQuery;
+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.component.ComponentDto;
+import org.sonar.core.issue.DefaultIssueBuilder;
+import org.sonar.core.issue.IssueNotifications;
+import org.sonar.core.issue.IssueUpdater;
+import org.sonar.core.issue.db.IssueDao;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.preview.PreviewCache;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.issue.actionplan.ActionPlanService;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.QueryContext;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+public class DefaultIssueService implements IssueService {
+
+  private final DbClient dbClient;
+  private final IndexClient indexClient;
+
+  private final IssueWorkflow workflow;
+  private final IssueUpdater issueUpdater;
+  private final IssueStorage issueStorage;
+  private final IssueNotifications issueNotifications;
+  private final ActionPlanService actionPlanService;
+  private final RuleFinder ruleFinder;
+  private final IssueDao issueDao;
+  private final UserFinder userFinder;
+  private final PreviewCache dryRunCache;
+
+  public DefaultIssueService(DbClient dbClient, IndexClient indexClient,
+                             IssueWorkflow workflow,
+                             IssueStorage issueStorage,
+                             IssueUpdater issueUpdater,
+                             IssueNotifications issueNotifications,
+                             ActionPlanService actionPlanService,
+                             RuleFinder ruleFinder,
+                             IssueDao issueDao,
+                             UserFinder userFinder,
+                             PreviewCache dryRunCache) {
+    this.dbClient = dbClient;
+    this.indexClient = indexClient;
+    this.workflow = workflow;
+    this.issueStorage = issueStorage;
+    this.issueUpdater = issueUpdater;
+    this.actionPlanService = actionPlanService;
+    this.ruleFinder = ruleFinder;
+    this.issueNotifications = issueNotifications;
+    this.issueDao = issueDao;
+    this.userFinder = userFinder;
+    this.dryRunCache = dryRunCache;
+  }
+
+  @Override
+  public List<String> listStatus() {
+    return workflow.statusKeys();
+  }
+
+  /**
+   * List of available transitions.
+   * <p/>
+   * Never return null, but return an empty list if the issue does not exist.
+   */
+  @Override
+  public List<Transition> listTransitions(String issueKey) {
+    DbSession session = dbClient.openSession(false);
+    try {
+      IssueDto issueDto = getByKey(session, issueKey);
+      return listTransitions(issueDto.toDefaultIssue());
+    } finally {
+      session.close();
+    }
+  }
+
+  /**
+   * Never return null, but an empty list if the issue does not exist.
+   * No security check is done since it should already have been done to get the issue
+   */
+  @Override
+  public List<Transition> listTransitions(@Nullable Issue issue) {
+    if (issue == null) {
+      return Collections.emptyList();
+    }
+    List<Transition> outTransitions = workflow.outTransitions(issue);
+    List<Transition> allowedTransitions = new ArrayList<Transition>();
+    for (Transition transition : outTransitions) {
+      DefaultIssue defaultIssue = (DefaultIssue) issue;
+      String projectKey = defaultIssue.projectKey();
+      if (StringUtils.isBlank(transition.requiredProjectPermission()) ||
+        (projectKey != null && UserSession.get().hasProjectPermission(transition.requiredProjectPermission(), projectKey))) {
+        allowedTransitions.add(transition);
+      }
+    }
+    return allowedTransitions;
+  }
+
+  @Override
+  public Issue doTransition(String issueKey, String transitionKey) {
+    verifyLoggedIn();
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      IssueDto issueDto = getByKey(session, issueKey);
+      DefaultIssue defaultIssue = issueDto.toDefaultIssue();
+      IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+      checkTransitionPermission(transitionKey, UserSession.get(), defaultIssue);
+      if (workflow.doTransition(defaultIssue, transitionKey, context)) {
+        saveIssue(session, defaultIssue, context);
+      }
+      return defaultIssue;
+
+    } finally {
+      session.close();
+    }
+  }
+
+  private void checkTransitionPermission(String transitionKey, UserSession userSession, DefaultIssue defaultIssue) {
+    List<Transition> outTransitions = workflow.outTransitions(defaultIssue);
+    for (Transition transition : outTransitions) {
+      String projectKey = defaultIssue.projectKey();
+      if (transition.key().equals(transitionKey) && StringUtils.isNotBlank(transition.requiredProjectPermission()) && projectKey != null) {
+        userSession.checkProjectPermission(transition.requiredProjectPermission(), projectKey);
+      }
+    }
+  }
+
+  @Override
+  public Issue assign(String issueKey, @Nullable String assignee) {
+    verifyLoggedIn();
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      IssueDto issueDto = getByKey(session, issueKey);
+      DefaultIssue issue = issueDto.toDefaultIssue();
+      User user = null;
+      if (!Strings.isNullOrEmpty(assignee)) {
+        user = userFinder.findByLogin(assignee);
+        if (user == null) {
+          throw new NotFoundException("Unknown user: " + assignee);
+        }
+      }
+      IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+      if (issueUpdater.assign(issue, user, context)) {
+        saveIssue(session, issue, context);
+      }
+      return issue;
+
+    } finally {
+      session.close();
+    }
+  }
+
+  @Override
+  public Issue plan(String issueKey, @Nullable String actionPlanKey) {
+    verifyLoggedIn();
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      ActionPlan actionPlan = null;
+      if (!Strings.isNullOrEmpty(actionPlanKey)) {
+        actionPlan = actionPlanService.findByKey(actionPlanKey, UserSession.get());
+        if (actionPlan == null) {
+          throw new NotFoundException("Unknown action plan: " + actionPlanKey);
+        }
+      }
+      IssueDto issueDto = getByKey(session, issueKey);
+      DefaultIssue issue = issueDto.toDefaultIssue();
+
+      IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+      if (issueUpdater.plan(issue, actionPlan, context)) {
+        saveIssue(session, issue, context);
+      }
+      return issue;
+
+    } finally {
+      session.close();
+    }
+  }
+
+  @Override
+  public Issue setSeverity(String issueKey, String severity) {
+    verifyLoggedIn();
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      IssueDto issueDto = getByKey(session, issueKey);
+      DefaultIssue issue = issueDto.toDefaultIssue();
+      UserSession.get().checkProjectPermission(UserRole.ISSUE_ADMIN, issue.projectKey());
+
+      IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+      if (issueUpdater.setManualSeverity(issue, severity, context)) {
+        saveIssue(session, issue, context);
+      }
+      return issue;
+    } finally {
+      session.close();
+    }
+  }
+
+  @Override
+  public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity,
+                                        @Nullable Double effortToFix) {
+    verifyLoggedIn();
+
+    DbSession session = dbClient.openSession(false);
+    try {
+      ComponentDto component = dbClient.componentDao().getByKey(session, componentKey);
+      ComponentDto project = dbClient.componentDao().getRootProjectByKey(componentKey, session);
+
+      UserSession.get().checkProjectPermission(UserRole.USER, project.getKey());
+      if (!ruleKey.isManual()) {
+        throw new IllegalArgumentException("Issues can be created only on rules marked as 'manual': " + ruleKey);
+      }
+      Rule rule = getRuleByKey(ruleKey);
+
+      DefaultIssue issue = new DefaultIssueBuilder()
+        .componentKey(component.getKey())
+        .projectKey(project.getKey())
+        .line(line)
+        .message(!Strings.isNullOrEmpty(message) ? message : rule.getName())
+        .severity(Objects.firstNonNull(severity, Severity.MAJOR))
+        .effortToFix(effortToFix)
+        .ruleKey(ruleKey)
+        .reporter(UserSession.get().login())
+        .build();
+
+      Date now = new Date();
+      issue.setCreationDate(now);
+      issue.setUpdateDate(now);
+      issueStorage.save(issue);
+      dryRunCache.reportResourceModification(component.getKey());
+      return issue;
+    } finally {
+      session.close();
+    }
+  }
+
+  // TODO result should be replaced by an aggregation object in IssueIndex
+  @Override
+  public RulesAggregation findRulesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
+    RulesAggregation rulesAggregation = new RulesAggregation();
+    for (RuleDto ruleDto : issueDao.findRulesByComponent(componentKey, periodDate, session)) {
+      rulesAggregation.add(ruleDto);
+    }
+    return rulesAggregation;
+  }
+
+  // TODO result should be replaced by an aggregation object in IssueIndex
+  @Override
+  public Multiset<String> findSeveritiesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
+    Multiset<String> aggregation = HashMultiset.create();
+    for (String severity : issueDao.findSeveritiesByComponent(componentKey, periodDate, session)) {
+      aggregation.add(severity);
+    }
+    return aggregation;
+  }
+
+  public IssueDto getByKey(DbSession session, String key) {
+    // Load with index to check permission
+    indexClient.get(IssueIndex.class).getByKey(key);
+    return dbClient.issueDao().getByKey(session, key);
+  }
+
+  private void saveIssue(DbSession session, DefaultIssue issue, IssueChangeContext context) {
+    issueStorage.save(issue);
+    issueNotifications.sendChanges(issue, context,
+      getRuleByKey(issue.ruleKey()),
+      dbClient.componentDao().getByKey(session, issue.projectKey()),
+      dbClient.componentDao().getNullableByKey(session, issue.componentKey()));
+    dryRunCache.reportResourceModification(issue.componentKey());
+  }
+
+  private Rule getRuleByKey(RuleKey ruleKey) {
+    Rule rule = ruleFinder.findByKey(ruleKey);
+    if (rule == null) {
+      throw new IllegalArgumentException("Unknown rule: " + ruleKey);
+    }
+    return rule;
+  }
+
+  public org.sonar.server.search.Result<Issue> search(IssueQuery query, QueryContext options) {
+    IssueIndex issueIndex = indexClient.get(IssueIndex.class);
+    return issueIndex.search(query, options);
+  }
+
+  private void verifyLoggedIn() {
+    UserSession.get().checkLoggedIn();
+  }
+}
index 1fa162a5dd707194605422014dca8849498e6eaf..e919ba8f6dc9abfc14d1ce356e94dec2b47bcf4e 100644 (file)
@@ -110,11 +110,11 @@ public class InternalRubyIssueService implements ServerComponent {
   }
 
   public List<Transition> listTransitions(String issueKey) {
-    return issueService.listTransitions(issueKey, UserSession.get());
+    return issueService.listTransitions(issueKey);
   }
 
   public List<Transition> listTransitions(Issue issue) {
-    return issueService.listTransitions(issue, UserSession.get());
+    return issueService.listTransitions(issue);
   }
 
   public List<String> listStatus() {
@@ -149,7 +149,7 @@ public class InternalRubyIssueService implements ServerComponent {
   public Result<Issue> doTransition(String issueKey, String transitionKey) {
     Result<Issue> result = Result.of();
     try {
-      result.set(issueService.doTransition(issueKey, transitionKey, UserSession.get()));
+      result.set(issueService.doTransition(issueKey, transitionKey));
     } catch (Exception e) {
       result.addError(e.getMessage());
     }
@@ -159,7 +159,7 @@ public class InternalRubyIssueService implements ServerComponent {
   public Result<Issue> assign(String issueKey, @Nullable String assignee) {
     Result<Issue> result = Result.of();
     try {
-      result.set(issueService.assign(issueKey, StringUtils.defaultIfBlank(assignee, null), UserSession.get()));
+      result.set(issueService.assign(issueKey, StringUtils.defaultIfBlank(assignee, null)));
     } catch (Exception e) {
       result.addError(e.getMessage());
     }
@@ -169,7 +169,7 @@ public class InternalRubyIssueService implements ServerComponent {
   public Result<Issue> setSeverity(String issueKey, String severity) {
     Result<Issue> result = Result.of();
     try {
-      result.set(issueService.setSeverity(issueKey, severity, UserSession.get()));
+      result.set(issueService.setSeverity(issueKey, severity));
     } catch (Exception e) {
       result.addError(e.getMessage());
     }
@@ -179,7 +179,7 @@ public class InternalRubyIssueService implements ServerComponent {
   public Result<Issue> plan(String issueKey, @Nullable String actionPlanKey) {
     Result<Issue> result = Result.of();
     try {
-      result.set(issueService.plan(issueKey, actionPlanKey, UserSession.get()));
+      result.set(issueService.plan(issueKey, actionPlanKey));
     } catch (Exception e) {
       result.addError(e.getMessage());
     }
@@ -235,7 +235,7 @@ 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());
+          RubyUtils.toDouble(params.get("effortToFix")));
         result.set(issue);
       }
 
index 6ef2e3b252f73dc40f84f9011e92c185dfa161a4..c60d205fe8a965d5fb5520275a076b0aa92d655d 100644 (file)
  * 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.issue;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Objects;
-import com.google.common.base.Strings;
-import com.google.common.collect.HashMultiset;
 import com.google.common.collect.Multiset;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
-import org.sonar.api.issue.ActionPlan;
 import org.sonar.api.issue.Issue;
-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.IssueDao;
-import org.sonar.core.issue.db.IssueStorage;
-import org.sonar.core.issue.workflow.IssueWorkflow;
 import org.sonar.core.issue.workflow.Transition;
 import org.sonar.core.persistence.DbSession;
-import org.sonar.core.preview.PreviewCache;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.user.AuthorizationDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.issue.actionplan.ActionPlanService;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.user.UserSession;
 
 import javax.annotation.Nullable;
 
-import java.util.*;
-
-/**
- * @since 3.6
- */
-public class IssueService implements ServerComponent {
-
-  private static final Logger LOGGER = LoggerFactory.getLogger(IssueService.class);
-
-  private final DbClient dbClient;
-  private final IndexClient indexClient;
-
-  private final DefaultIssueFinder finder;
-  private final IssueWorkflow workflow;
-  private final IssueUpdater issueUpdater;
-  private final IssueStorage issueStorage;
-  private final IssueNotifications issueNotifications;
-  private final ActionPlanService actionPlanService;
-  private final RuleFinder ruleFinder;
-  private final ResourceDao resourceDao;
-  private final IssueDao issueDao;
-  private final AuthorizationDao authorizationDao;
-  private final UserFinder userFinder;
-  private final PreviewCache dryRunCache;
-
-  @Deprecated
-  @VisibleForTesting
-  public IssueService(DefaultIssueFinder finder,
-    IssueWorkflow workflow,
-    IssueStorage issueStorage,
-    IssueUpdater issueUpdater,
-    IssueNotifications issueNotifications,
-    ActionPlanService actionPlanService,
-    RuleFinder ruleFinder,
-    ResourceDao resourceDao,
-    IssueDao issueDao,
-    AuthorizationDao authorizationDao,
-    UserFinder userFinder,
-    PreviewCache dryRunCache) {
-    this(null, null, finder, workflow, issueStorage, issueUpdater, issueNotifications, actionPlanService,
-      ruleFinder, resourceDao, issueDao, authorizationDao, userFinder, dryRunCache);
-  }
-
-  public IssueService(DbClient dbClient, IndexClient indexClient,
-    DefaultIssueFinder finder,
-    IssueWorkflow workflow,
-    IssueStorage issueStorage,
-    IssueUpdater issueUpdater,
-    IssueNotifications issueNotifications,
-    ActionPlanService actionPlanService,
-    RuleFinder ruleFinder,
-    ResourceDao resourceDao,
-    IssueDao issueDao,
-    AuthorizationDao authorizationDao,
-    UserFinder userFinder,
-    PreviewCache dryRunCache) {
-    this.dbClient = dbClient;
-    this.indexClient = indexClient;
-    this.finder = finder;
-    this.workflow = workflow;
-    this.issueStorage = issueStorage;
-    this.issueUpdater = issueUpdater;
-    this.actionPlanService = actionPlanService;
-    this.ruleFinder = ruleFinder;
-    this.issueNotifications = issueNotifications;
-    this.resourceDao = resourceDao;
-    this.issueDao = issueDao;
-    this.authorizationDao = authorizationDao;
-    this.userFinder = userFinder;
-    this.dryRunCache = dryRunCache;
-  }
-
-  /**
-   * List of available transitions.
-   * <p/>
-   * Never return null, but return an empty list if the issue does not exist.
-   */
-  public List<Transition> listTransitions(String issueKey, UserSession userSession) {
-    Issue issue = loadIssue(issueKey).first();
-    return listTransitions(issue, userSession);
-  }
+import java.util.Date;
+import java.util.List;
 
-  /**
-   * Never return null, but an empty list if the issue does not exist.
-   * No security check is done since it should already have been done to get the issue
-   */
-  public List<Transition> listTransitions(@Nullable Issue issue, UserSession userSession) {
-    if (issue == null) {
-      return Collections.emptyList();
-    }
-    List<Transition> outTransitions = workflow.outTransitions(issue);
-    List<Transition> allowedTransitions = new ArrayList<Transition>();
-    for (Transition transition : outTransitions) {
-      DefaultIssue defaultIssue = (DefaultIssue) issue;
-      String projectKey = defaultIssue.projectKey();
-      if (StringUtils.isBlank(transition.requiredProjectPermission()) ||
-        (projectKey != null && userSession.hasProjectPermission(transition.requiredProjectPermission(), projectKey))) {
-        allowedTransitions.add(transition);
-      }
-    }
-    return allowedTransitions;
-  }
+public interface IssueService extends ServerComponent {
+  List<String> listStatus();
 
-  public Issue doTransition(String issueKey, String transitionKey, UserSession userSession) {
-    verifyLoggedIn(userSession);
-    IssueQueryResult queryResult = loadIssue(issueKey);
-    DefaultIssue defaultIssue = (DefaultIssue) queryResult.first();
-    IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login());
-    checkTransitionPermission(transitionKey, userSession, defaultIssue);
-    if (workflow.doTransition(defaultIssue, transitionKey, context)) {
-      issueStorage.save(defaultIssue);
-      issueNotifications.sendChanges(defaultIssue, context, queryResult);
-      dryRunCache.reportResourceModification(defaultIssue.componentKey());
-    }
-    return defaultIssue;
-  }
+  List<Transition> listTransitions(String issueKey);
 
-  private void checkTransitionPermission(String transitionKey, UserSession userSession, DefaultIssue defaultIssue) {
-    List<Transition> outTransitions = workflow.outTransitions(defaultIssue);
-    for (Transition transition : outTransitions) {
-      String projectKey = defaultIssue.projectKey();
-      if (transition.key().equals(transitionKey) && StringUtils.isNotBlank(transition.requiredProjectPermission()) && projectKey != null) {
-        userSession.checkProjectPermission(transition.requiredProjectPermission(), projectKey);
-      }
-    }
-  }
+  List<Transition> listTransitions(@Nullable Issue issue);
 
-  public Issue assign(String issueKey, @Nullable String assignee, UserSession userSession) {
-    verifyLoggedIn(userSession);
-    IssueQueryResult queryResult = loadIssue(issueKey);
-    DefaultIssue issue = (DefaultIssue) queryResult.first();
-    User user = null;
-    if (!Strings.isNullOrEmpty(assignee)) {
-      user = userFinder.findByLogin(assignee);
-      if (user == null) {
-        throw new IllegalArgumentException("Unknown user: " + assignee);
-      }
-    }
-    IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login());
-    if (issueUpdater.assign(issue, user, context)) {
-      issueStorage.save(issue);
-      issueNotifications.sendChanges(issue, context, queryResult);
-      dryRunCache.reportResourceModification(issue.componentKey());
-    }
-    return issue;
-  }
+  Issue doTransition(String issueKey, String transitionKey);
 
-  public Issue plan(String issueKey, @Nullable String actionPlanKey, UserSession userSession) {
-    verifyLoggedIn(userSession);
-    ActionPlan actionPlan = null;
-    if (!Strings.isNullOrEmpty(actionPlanKey)) {
-      actionPlan = actionPlanService.findByKey(actionPlanKey, userSession);
-      if (actionPlan == null) {
-        throw new IllegalArgumentException("Unknown action plan: " + actionPlanKey);
-      }
-    }
-    IssueQueryResult queryResult = loadIssue(issueKey);
-    DefaultIssue issue = (DefaultIssue) queryResult.first();
+  Issue assign(String issueKey, @Nullable String assignee);
 
-    IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login());
-    if (issueUpdater.plan(issue, actionPlan, context)) {
-      issueStorage.save(issue);
-      issueNotifications.sendChanges(issue, context, queryResult);
-      dryRunCache.reportResourceModification(issue.componentKey());
-    }
-    return issue;
-  }
+  Issue plan(String issueKey, @Nullable String actionPlanKey);
 
-  public Issue setSeverity(String issueKey, String severity, UserSession userSession) {
-    verifyLoggedIn(userSession);
-    IssueQueryResult queryResult = loadIssue(issueKey);
-    DefaultIssue issue = (DefaultIssue) queryResult.first();
-    userSession.checkProjectPermission(UserRole.ISSUE_ADMIN, issue.projectKey());
+  Issue setSeverity(String issueKey, String severity);
 
-    IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.login());
-    if (issueUpdater.setManualSeverity(issue, severity, context)) {
-      issueStorage.save(issue);
-      issueNotifications.sendChanges(issue, context, queryResult);
-      dryRunCache.reportResourceModification(issue.componentKey());
-    }
-    return issue;
-  }
-
-  public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity,
-    @Nullable Double effortToFix, UserSession userSession) {
-    verifyLoggedIn(userSession);
-    ResourceDto component = resourceDao.getResource(ResourceQuery.create().setKey(componentKey));
-    ResourceDto project = resourceDao.getRootProjectByComponentKey(componentKey);
-    if (component == null || project == null) {
-      throw new IllegalArgumentException("Unknown component: " + componentKey);
-    }
-    if (!authorizationDao.isAuthorizedComponentKey(component.getKey(), userSession.userId(), UserRole.USER)) {
-      // TODO throw unauthorized
-      throw new IllegalStateException("User does not have the required role");
-    }
-    if (!ruleKey.isManual()) {
-      throw new IllegalArgumentException("Issues can be created only on rules marked as 'manual': " + ruleKey);
-    }
-    Rule rule = findRule(ruleKey);
-
-    DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
-      .componentKey(component.getKey())
-      .projectKey(project.getKey())
-      .line(line)
-      .message(!Strings.isNullOrEmpty(message) ? message : rule.getName())
-      .severity(Objects.firstNonNull(severity, Severity.MAJOR))
-      .effortToFix(effortToFix)
-      .ruleKey(ruleKey)
-      .reporter(UserSession.get().login())
-      .build();
-
-    Date now = new Date();
-    issue.setCreationDate(now);
-    issue.setUpdateDate(now);
-    issueStorage.save(issue);
-    dryRunCache.reportResourceModification(component.getKey());
-    return issue;
-  }
-
-  private Rule findRule(RuleKey ruleKey) {
-    Rule rule = ruleFinder.findByKey(ruleKey);
-    if (rule == null) {
-      throw new IllegalArgumentException("Unknown rule: " + ruleKey);
-    }
-    return rule;
-  }
-
-  public IssueQueryResult loadIssue(String issueKey) {
-    // TODO use IssueIndex for ACL
-    // TODO load DTO
-    IssueQueryResult result = finder.find(IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).requiredRole(UserRole.USER).build());
-    if (result.issues().size() != 1) {
-      // TODO throw 404
-      throw new IllegalArgumentException("Issue not found: " + issueKey);
-    }
-    return result;
-  }
-
-  public List<String> listStatus() {
-    return workflow.statusKeys();
-  }
-
-  private void verifyLoggedIn(UserSession userSession) {
-    if (!userSession.isLoggedIn()) {
-      // must be logged
-      throw new IllegalStateException("User is not logged in");
-    }
-  }
+  DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity,
+                                 @Nullable Double effortToFix);
 
   // TODO result should be replaced by an aggregation object in IssueIndex
-  public RulesAggregation findRulesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
-    RulesAggregation rulesAggregation = new RulesAggregation();
-    for (RuleDto ruleDto : issueDao.findRulesByComponent(componentKey, periodDate, session)) {
-      rulesAggregation.add(ruleDto);
-    }
-    return rulesAggregation;
-  }
+  RulesAggregation findRulesByComponent(String componentKey, @Nullable Date periodDate, DbSession session);
 
   // TODO result should be replaced by an aggregation object in IssueIndex
-  public Multiset<String> findSeveritiesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
-    Multiset<String> aggregation = HashMultiset.create();
-    for (String severity : issueDao.findSeveritiesByComponent(componentKey, periodDate, session)) {
-      aggregation.add(severity);
-    }
-    return aggregation;
-  }
-
-  public Issue getByKey(String key) {
-    return indexClient.get(IssueIndex.class).getByKey(key);
-  }
+  Multiset<String> findSeveritiesByComponent(String componentKey, @Nullable Date periodDate, DbSession session);
 
-  public org.sonar.server.search.Result<Issue> search(IssueQuery query, QueryContext options) {
-    IssueIndex issueIndex = indexClient.get(IssueIndex.class);
-    return issueIndex.search(query, options);
-  }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/OldIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/OldIssueService.java
new file mode 100644 (file)
index 0000000..107ac34
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * 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.issue;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Strings;
+import com.google.common.collect.HashMultiset;
+import com.google.common.collect.Multiset;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.Issue;
+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.IssueDao;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.preview.PreviewCache;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.ResourceDto;
+import org.sonar.core.resource.ResourceQuery;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.user.AuthorizationDao;
+import org.sonar.server.issue.actionplan.ActionPlanService;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.*;
+
+/**
+ * @since 3.6
+ */
+public class OldIssueService implements IssueService {
+
+  private final DefaultIssueFinder finder;
+  private final IssueWorkflow workflow;
+  private final IssueUpdater issueUpdater;
+  private final IssueStorage issueStorage;
+  private final IssueNotifications issueNotifications;
+  private final ActionPlanService actionPlanService;
+  private final RuleFinder ruleFinder;
+  private final ResourceDao resourceDao;
+  private final IssueDao issueDao;
+  private final AuthorizationDao authorizationDao;
+  private final UserFinder userFinder;
+  private final PreviewCache dryRunCache;
+
+  public OldIssueService(
+    DefaultIssueFinder finder,
+    IssueWorkflow workflow,
+    IssueStorage issueStorage,
+    IssueUpdater issueUpdater,
+    IssueNotifications issueNotifications,
+    ActionPlanService actionPlanService,
+    RuleFinder ruleFinder,
+    ResourceDao resourceDao,
+    IssueDao issueDao,
+    AuthorizationDao authorizationDao,
+    UserFinder userFinder,
+    PreviewCache dryRunCache) {
+    this.finder = finder;
+    this.workflow = workflow;
+    this.issueStorage = issueStorage;
+    this.issueUpdater = issueUpdater;
+    this.actionPlanService = actionPlanService;
+    this.ruleFinder = ruleFinder;
+    this.issueNotifications = issueNotifications;
+    this.resourceDao = resourceDao;
+    this.issueDao = issueDao;
+    this.authorizationDao = authorizationDao;
+    this.userFinder = userFinder;
+    this.dryRunCache = dryRunCache;
+  }
+
+  /**
+   * List of available transitions.
+   * <p/>
+   * Never return null, but return an empty list if the issue does not exist.
+   */
+  public List<Transition> listTransitions(String issueKey) {
+    Issue issue = loadIssue(issueKey).first();
+    return listTransitions(issue);
+  }
+
+  /**
+   * Never return null, but an empty list if the issue does not exist.
+   * No security check is done since it should already have been done to get the issue
+   */
+  public List<Transition> listTransitions(@Nullable Issue issue) {
+    if (issue == null) {
+      return Collections.emptyList();
+    }
+    List<Transition> outTransitions = workflow.outTransitions(issue);
+    List<Transition> allowedTransitions = new ArrayList<Transition>();
+    for (Transition transition : outTransitions) {
+      DefaultIssue defaultIssue = (DefaultIssue) issue;
+      String projectKey = defaultIssue.projectKey();
+      if (StringUtils.isBlank(transition.requiredProjectPermission()) ||
+        (projectKey != null && UserSession.get().hasProjectPermission(transition.requiredProjectPermission(), projectKey))) {
+        allowedTransitions.add(transition);
+      }
+    }
+    return allowedTransitions;
+  }
+
+  public Issue doTransition(String issueKey, String transitionKey) {
+    verifyLoggedIn();
+    IssueQueryResult queryResult = loadIssue(issueKey);
+    DefaultIssue defaultIssue = (DefaultIssue) queryResult.first();
+    IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+    checkTransitionPermission(transitionKey, UserSession.get(), defaultIssue);
+    if (workflow.doTransition(defaultIssue, transitionKey, context)) {
+      issueStorage.save(defaultIssue);
+      issueNotifications.sendChanges(defaultIssue, context, queryResult);
+      dryRunCache.reportResourceModification(defaultIssue.componentKey());
+    }
+    return defaultIssue;
+  }
+
+  private void checkTransitionPermission(String transitionKey, UserSession userSession, DefaultIssue defaultIssue) {
+    List<Transition> outTransitions = workflow.outTransitions(defaultIssue);
+    for (Transition transition : outTransitions) {
+      String projectKey = defaultIssue.projectKey();
+      if (transition.key().equals(transitionKey) && StringUtils.isNotBlank(transition.requiredProjectPermission()) && projectKey != null) {
+        userSession.checkProjectPermission(transition.requiredProjectPermission(), projectKey);
+      }
+    }
+  }
+
+  public Issue assign(String issueKey, @Nullable String assignee) {
+    verifyLoggedIn();
+    IssueQueryResult queryResult = loadIssue(issueKey);
+    DefaultIssue issue = (DefaultIssue) queryResult.first();
+    User user = null;
+    if (!Strings.isNullOrEmpty(assignee)) {
+      user = userFinder.findByLogin(assignee);
+      if (user == null) {
+        throw new IllegalArgumentException("Unknown user: " + assignee);
+      }
+    }
+    IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+    if (issueUpdater.assign(issue, user, context)) {
+      issueStorage.save(issue);
+      issueNotifications.sendChanges(issue, context, queryResult);
+      dryRunCache.reportResourceModification(issue.componentKey());
+    }
+    return issue;
+  }
+
+  public Issue plan(String issueKey, @Nullable String actionPlanKey) {
+    verifyLoggedIn();
+    ActionPlan actionPlan = null;
+    if (!Strings.isNullOrEmpty(actionPlanKey)) {
+      actionPlan = actionPlanService.findByKey(actionPlanKey, UserSession.get());
+      if (actionPlan == null) {
+        throw new IllegalArgumentException("Unknown action plan: " + actionPlanKey);
+      }
+    }
+    IssueQueryResult queryResult = loadIssue(issueKey);
+    DefaultIssue issue = (DefaultIssue) queryResult.first();
+
+    IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+    if (issueUpdater.plan(issue, actionPlan, context)) {
+      issueStorage.save(issue);
+      issueNotifications.sendChanges(issue, context, queryResult);
+      dryRunCache.reportResourceModification(issue.componentKey());
+    }
+    return issue;
+  }
+
+  public Issue setSeverity(String issueKey, String severity) {
+    verifyLoggedIn();
+    IssueQueryResult queryResult = loadIssue(issueKey);
+    DefaultIssue issue = (DefaultIssue) queryResult.first();
+    UserSession.get().checkProjectPermission(UserRole.ISSUE_ADMIN, issue.projectKey());
+
+    IssueChangeContext context = IssueChangeContext.createUser(new Date(), UserSession.get().login());
+    if (issueUpdater.setManualSeverity(issue, severity, context)) {
+      issueStorage.save(issue);
+      issueNotifications.sendChanges(issue, context, queryResult);
+      dryRunCache.reportResourceModification(issue.componentKey());
+    }
+    return issue;
+  }
+
+  public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity,
+    @Nullable Double effortToFix) {
+    verifyLoggedIn();
+    ResourceDto component = resourceDao.getResource(ResourceQuery.create().setKey(componentKey));
+    ResourceDto project = resourceDao.getRootProjectByComponentKey(componentKey);
+    if (component == null || project == null) {
+      throw new IllegalArgumentException("Unknown component: " + componentKey);
+    }
+    if (!authorizationDao.isAuthorizedComponentKey(component.getKey(), UserSession.get().userId(), UserRole.USER)) {
+      // TODO throw unauthorized
+      throw new IllegalStateException("User does not have the required role");
+    }
+    if (!ruleKey.isManual()) {
+      throw new IllegalArgumentException("Issues can be created only on rules marked as 'manual': " + ruleKey);
+    }
+    Rule rule = findRule(ruleKey);
+
+    DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
+      .componentKey(component.getKey())
+      .projectKey(project.getKey())
+      .line(line)
+      .message(!Strings.isNullOrEmpty(message) ? message : rule.getName())
+      .severity(Objects.firstNonNull(severity, Severity.MAJOR))
+      .effortToFix(effortToFix)
+      .ruleKey(ruleKey)
+      .reporter(UserSession.get().login())
+      .build();
+
+    Date now = new Date();
+    issue.setCreationDate(now);
+    issue.setUpdateDate(now);
+    issueStorage.save(issue);
+    dryRunCache.reportResourceModification(component.getKey());
+    return issue;
+  }
+
+  private Rule findRule(RuleKey ruleKey) {
+    Rule rule = ruleFinder.findByKey(ruleKey);
+    if (rule == null) {
+      throw new IllegalArgumentException("Unknown rule: " + ruleKey);
+    }
+    return rule;
+  }
+
+  public IssueQueryResult loadIssue(String issueKey) {
+    // TODO use IssueIndex for ACL
+    // TODO load DTO
+    IssueQueryResult result = finder.find(IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).requiredRole(UserRole.USER).build());
+    if (result.issues().size() != 1) {
+      // TODO throw 404
+      throw new IllegalArgumentException("Issue not found: " + issueKey);
+    }
+    return result;
+  }
+
+  public List<String> listStatus() {
+    return workflow.statusKeys();
+  }
+
+  private void verifyLoggedIn() {
+    if (!UserSession.get().isLoggedIn()) {
+      // must be logged
+      throw new IllegalStateException("User is not logged in");
+    }
+  }
+
+  // TODO result should be replaced by an aggregation object in IssueIndex
+  public RulesAggregation findRulesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
+    RulesAggregation rulesAggregation = new RulesAggregation();
+    for (RuleDto ruleDto : issueDao.findRulesByComponent(componentKey, periodDate, session)) {
+      rulesAggregation.add(ruleDto);
+    }
+    return rulesAggregation;
+  }
+
+  // TODO result should be replaced by an aggregation object in IssueIndex
+  public Multiset<String> findSeveritiesByComponent(String componentKey, @Nullable Date periodDate, DbSession session) {
+    Multiset<String> aggregation = HashMultiset.create();
+    for (String severity : issueDao.findSeveritiesByComponent(componentKey, periodDate, session)) {
+      aggregation.add(severity);
+    }
+    return aggregation;
+  }
+
+}
index e4d7cfa04daeb76287a988d63581d7948a1905ae..4057524f0f86698727ca6516e308eb1d0f611edc 100644 (file)
@@ -48,7 +48,7 @@ public class IssueActionsWriter implements ServerComponent {
   public void writeTransitions(Issue issue, JsonWriter json) {
     json.name("transitions").beginArray();
     if (UserSession.get().isLoggedIn()) {
-      List<Transition> transitions = issueService.listTransitions(issue, UserSession.get());
+      List<Transition> transitions = issueService.listTransitions(issue);
       for (Transition transition : transitions) {
         json.value(transition.key());
       }
index 20ceda385eaac6b6e56dcca15fbe5b826f769821..30fd11a0cc292659170981c60a0963b663502223 100644 (file)
@@ -24,11 +24,7 @@ import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
 import com.google.common.io.Resources;
 import org.sonar.api.i18n.I18n;
-import org.sonar.api.issue.ActionPlan;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueComment;
-import org.sonar.api.issue.IssueQuery;
-import org.sonar.api.issue.IssueQueryResult;
+import org.sonar.api.issue.*;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.server.ws.Request;
@@ -45,6 +41,7 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.markdown.Markdown;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.DefaultIssueService;
 import org.sonar.server.issue.IssueService;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.filter.IssueFilterParameters;
@@ -58,13 +55,7 @@ import org.sonar.server.user.UserSession;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static com.google.common.collect.Lists.newArrayList;
 
@@ -229,7 +220,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
 
   @Override
   protected Result<Issue> doSearch(IssueQuery query, QueryContext context) {
-    return service.search(query, context);
+    return ((DefaultIssueService)service).search(query, context);
   }
 
   @Override
index 9ccca614c62ea47865369e57a9ebc57128e6db6e..4e4caaae9326ee96e7b5eab13fdb581c9fcc4b85 100644 (file)
@@ -51,13 +51,7 @@ import org.sonar.core.measure.db.MeasureFilterDao;
 import org.sonar.core.metric.DefaultMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.DaoUtils;
-import org.sonar.core.persistence.DatabaseVersion;
-import org.sonar.core.persistence.DefaultDatabase;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.persistence.PreviewDatabaseFactory;
-import org.sonar.core.persistence.SemaphoreUpdater;
-import org.sonar.core.persistence.SemaphoresImpl;
+import org.sonar.core.persistence.*;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.purge.PurgeProfiler;
@@ -83,57 +77,27 @@ import org.sonar.server.activity.index.ActivityNormalizer;
 import org.sonar.server.activity.ws.ActivitiesWebService;
 import org.sonar.server.activity.ws.ActivityMapping;
 import org.sonar.server.authentication.ws.AuthenticationWs;
-import org.sonar.server.batch.BatchIndex;
-import org.sonar.server.batch.BatchWs;
-import org.sonar.server.batch.GlobalReferentialsAction;
-import org.sonar.server.batch.ProjectReferentialsAction;
-import org.sonar.server.batch.UploadReportAction;
+import org.sonar.server.batch.*;
 import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.component.db.SnapshotDao;
-import org.sonar.server.component.ws.ComponentAppAction;
-import org.sonar.server.component.ws.ComponentsWs;
-import org.sonar.server.component.ws.EventsWs;
-import org.sonar.server.component.ws.ProjectsWs;
-import org.sonar.server.component.ws.ResourcesWs;
+import org.sonar.server.component.ws.*;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.db.DatabaseChecker;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
 import org.sonar.server.db.migrations.DatabaseMigrations;
 import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
-import org.sonar.server.debt.DebtModelBackup;
-import org.sonar.server.debt.DebtModelLookup;
-import org.sonar.server.debt.DebtModelOperations;
-import org.sonar.server.debt.DebtModelPluginRepository;
-import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.debt.DebtModelXMLExporter;
-import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.debt.*;
 import org.sonar.server.design.FileDesignWidget;
 import org.sonar.server.design.PackageDesignWidget;
 import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
 import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
-import org.sonar.server.issue.ActionService;
-import org.sonar.server.issue.AssignAction;
-import org.sonar.server.issue.CommentAction;
-import org.sonar.server.issue.DefaultIssueFinder;
-import org.sonar.server.issue.InternalRubyIssueService;
-import org.sonar.server.issue.IssueBulkChangeService;
-import org.sonar.server.issue.IssueChangelogFormatter;
-import org.sonar.server.issue.IssueChangelogService;
-import org.sonar.server.issue.IssueCommentService;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.issue.IssueStatsFinder;
-import org.sonar.server.issue.PlanAction;
-import org.sonar.server.issue.PublicRubyIssueService;
-import org.sonar.server.issue.ServerIssueStorage;
-import org.sonar.server.issue.SetSeverityAction;
-import org.sonar.server.issue.TransitionAction;
+import org.sonar.server.issue.*;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.actionplan.ActionPlanWs;
 import org.sonar.server.issue.db.IssueAuthorizationDao;
@@ -167,84 +131,22 @@ import org.sonar.server.platform.ws.L10nWs;
 import org.sonar.server.platform.ws.RestartHandler;
 import org.sonar.server.platform.ws.ServerWs;
 import org.sonar.server.platform.ws.SystemWs;
-import org.sonar.server.plugins.InstalledPluginReferentialFactory;
-import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerExtensionInstaller;
-import org.sonar.server.plugins.ServerPluginJarInstaller;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
-import org.sonar.server.plugins.ServerPluginRepository;
-import org.sonar.server.plugins.UpdateCenterClient;
-import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.plugins.*;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
 import org.sonar.server.qualitygate.RegisterQualityGates;
-import org.sonar.server.qualitygate.ws.QGatesAppAction;
-import org.sonar.server.qualitygate.ws.QGatesCopyAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeselectAction;
-import org.sonar.server.qualitygate.ws.QGatesDestroyAction;
-import org.sonar.server.qualitygate.ws.QGatesListAction;
-import org.sonar.server.qualitygate.ws.QGatesRenameAction;
-import org.sonar.server.qualitygate.ws.QGatesSearchAction;
-import org.sonar.server.qualitygate.ws.QGatesSelectAction;
-import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesShowAction;
-import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesWs;
-import org.sonar.server.qualityprofile.BuiltInProfiles;
-import org.sonar.server.qualityprofile.QProfileBackuper;
-import org.sonar.server.qualityprofile.QProfileCopier;
-import org.sonar.server.qualityprofile.QProfileExporters;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.qualityprofile.QProfileLookup;
-import org.sonar.server.qualityprofile.QProfileProjectLookup;
-import org.sonar.server.qualityprofile.QProfileProjectOperations;
-import org.sonar.server.qualityprofile.QProfileRepositoryExporter;
-import org.sonar.server.qualityprofile.QProfileReset;
-import org.sonar.server.qualityprofile.QProfileService;
-import org.sonar.server.qualityprofile.QProfiles;
-import org.sonar.server.qualityprofile.RegisterQualityProfiles;
-import org.sonar.server.qualityprofile.RuleActivator;
-import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
+import org.sonar.server.qualitygate.ws.*;
+import org.sonar.server.qualityprofile.*;
 import org.sonar.server.qualityprofile.db.ActiveRuleDao;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions;
-import org.sonar.server.qualityprofile.ws.ProfilesWs;
-import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction;
-import org.sonar.server.qualityprofile.ws.QProfilesWs;
-import org.sonar.server.qualityprofile.ws.RuleActivationActions;
-import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.rule.DeprecatedRulesDefinition;
-import org.sonar.server.rule.RegisterRules;
-import org.sonar.server.rule.RubyRuleService;
-import org.sonar.server.rule.RuleCreator;
-import org.sonar.server.rule.RuleDefinitionsLoader;
-import org.sonar.server.rule.RuleDeleter;
-import org.sonar.server.rule.RuleOperations;
-import org.sonar.server.rule.RuleRepositories;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.rule.RuleUpdater;
+import org.sonar.server.qualityprofile.ws.*;
+import org.sonar.server.rule.*;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleNormalizer;
-import org.sonar.server.rule.ws.ActiveRuleCompleter;
-import org.sonar.server.rule.ws.AppAction;
-import org.sonar.server.rule.ws.DeleteAction;
-import org.sonar.server.rule.ws.RuleMapping;
-import org.sonar.server.rule.ws.RulesWebService;
-import org.sonar.server.rule.ws.SearchAction;
-import org.sonar.server.rule.ws.TagsAction;
-import org.sonar.server.rule.ws.UpdateAction;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.IndexQueue;
-import org.sonar.server.search.IndexSynchronizer;
-import org.sonar.server.search.SearchClient;
-import org.sonar.server.search.SearchHealth;
+import org.sonar.server.rule.ws.*;
+import org.sonar.server.search.*;
 import org.sonar.server.source.CodeColorizers;
 import org.sonar.server.source.DeprecatedSourceDecorator;
 import org.sonar.server.source.HtmlSourceDecorator;
@@ -253,27 +155,9 @@ import org.sonar.server.source.ws.ScmAction;
 import org.sonar.server.source.ws.ScmWriter;
 import org.sonar.server.source.ws.ShowAction;
 import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.startup.CleanPreviewAnalysisCache;
-import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules;
-import org.sonar.server.startup.GeneratePluginIndex;
-import org.sonar.server.startup.GwtPublisher;
-import org.sonar.server.startup.JdbcDriverDeployer;
-import org.sonar.server.startup.LogServerId;
-import org.sonar.server.startup.RegisterDashboards;
-import org.sonar.server.startup.RegisterDebtModel;
-import org.sonar.server.startup.RegisterMetrics;
-import org.sonar.server.startup.RegisterNewMeasureFilters;
-import org.sonar.server.startup.RegisterPermissionTemplates;
-import org.sonar.server.startup.RegisterServletFilters;
-import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
-import org.sonar.server.startup.ServerMetadataPersister;
+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.TestsCoveredFilesAction;
-import org.sonar.server.test.ws.TestsShowAction;
-import org.sonar.server.test.ws.TestsTestCasesAction;
-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;
@@ -281,23 +165,12 @@ import org.sonar.server.ui.JRubyProfiling;
 import org.sonar.server.ui.PageDecorations;
 import org.sonar.server.ui.Views;
 import org.sonar.server.updatecenter.ws.UpdateCenterWs;
-import org.sonar.server.user.DefaultUserService;
-import org.sonar.server.user.DoPrivileged;
-import org.sonar.server.user.GroupMembershipFinder;
-import org.sonar.server.user.GroupMembershipService;
-import org.sonar.server.user.NewUserNotifier;
-import org.sonar.server.user.SecurityRealmFactory;
+import org.sonar.server.user.*;
 import org.sonar.server.user.db.GroupDao;
 import org.sonar.server.user.ws.FavoritesWs;
 import org.sonar.server.user.ws.UserPropertiesWs;
 import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.util.BooleanTypeValidation;
-import org.sonar.server.util.FloatTypeValidation;
-import org.sonar.server.util.IntegerTypeValidation;
-import org.sonar.server.util.StringListTypeValidation;
-import org.sonar.server.util.StringTypeValidation;
-import org.sonar.server.util.TextTypeValidation;
-import org.sonar.server.util.TypeValidations;
+import org.sonar.server.util.*;
 import org.sonar.server.ws.ListingWs;
 import org.sonar.server.ws.WebServiceEngine;
 
@@ -595,7 +468,6 @@ class ServerComponents {
     pico.addSingleton(IssueUpdater.class);
     pico.addSingleton(FunctionExecutor.class);
     pico.addSingleton(IssueWorkflow.class);
-    pico.addSingleton(IssueService.class);
     pico.addSingleton(IssueCommentService.class);
     pico.addSingleton(DefaultIssueFinder.class);
     pico.addSingleton(IssueStatsFinder.class);
@@ -613,8 +485,10 @@ class ServerComponents {
     // Switch Issue search
     if (properties.getProperty("sonar.issues.use_es_backend", null) != null) {
       pico.addSingleton(org.sonar.server.issue.ws.SearchAction.class);
+      pico.addSingleton(DefaultIssueService.class);
     } else {
       pico.addSingleton(IssueSearchAction.class);
+      pico.addSingleton(OldIssueService.class);
     }
     pico.addSingleton(IssueActionsWriter.class);
 
index 8a847ef35eadc85735675875698a4195faa797ac..1ffcb84bf468227893895d4c904c0cbb97c5c396 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.search;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.config.Settings;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.activity.index.ActivityIndex;
 import org.sonar.server.db.Dao;
@@ -41,10 +42,12 @@ public class IndexSynchronizer {
 
   private final DbClient db;
   private final IndexClient index;
+  private final Settings settings;
 
-  public IndexSynchronizer(DbClient db, IndexClient index) {
+  public IndexSynchronizer(DbClient db, IndexClient index, Settings settings) {
     this.db = db;
     this.index = index;
+    this.settings = settings;
   }
 
   public void execute() {
@@ -53,8 +56,13 @@ public class IndexSynchronizer {
     LOG.info("Starting DB to Index synchronization");
     long start = System.currentTimeMillis();
     synchronize(session, db.ruleDao(), index.get(RuleIndex.class));
-    synchronize(session, db.issueDao(), index.get(IssueIndex.class));
-    synchronize(session, db.issueAuthorizationDao(), index.get(IssueAuthorizationIndex.class));
+
+    // Switch Issue search
+    if (settings.getString("sonar.issues.use_es_backend") != null) {
+      synchronize(session, db.issueDao(), index.get(IssueIndex.class));
+      synchronize(session, db.issueAuthorizationDao(), index.get(IssueAuthorizationIndex.class));
+    }
+
     synchronize(session, db.activeRuleDao(), index.get(ActiveRuleIndex.class));
     synchronize(session, db.activityDao(), index.get(ActivityIndex.class));
     session.commit();
index 5de5a0bac76325508ca8575a17d689755367f2be..34a0835706e37dd3c7929a6bf03ce1c5262b20a0 100644 (file)
@@ -350,7 +350,6 @@ public class ComponentAppActionTest {
     MockUserSession.set().addComponentPermission(UserRole.USER, SUB_PROJECT_KEY, COMPONENT_KEY);
     addComponent();
 
-
     addMeasure(CoreMetrics.IT_COVERAGE_KEY, 85.2);
 
     WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY);
@@ -365,7 +364,7 @@ public class ComponentAppActionTest {
 
     when(resourceDao.getLastSnapshotByResourceId(eq(1L), eq(session))).thenReturn(
       new SnapshotDto().setPeriodMode(1, "previous_analysis").setPeriodDate(1, DateUtils.parseDate("2014-05-08"))
-    );
+      );
     when(periods.label(anyString(), anyString(), any(Date.class))).thenReturn("since previous analysis (May 08 2014)");
 
     WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY);
@@ -409,7 +408,7 @@ public class ComponentAppActionTest {
     addComponent();
     when(issueService.findRulesByComponent(COMPONENT_KEY, null, session)).thenReturn(
       new RulesAggregation().add(new RuleDto().setRuleKey("AvoidCycle").setRepositoryKey("squid").setName("Avoid Cycle"))
-    );
+      );
 
     WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY);
     request.execute().assertJson(getClass(), "app_with_rules.json");
@@ -424,12 +423,12 @@ public class ComponentAppActionTest {
     Date periodDate = DateUtils.parseDate("2014-05-08");
     when(resourceDao.getLastSnapshotByResourceId(eq(1L), eq(session))).thenReturn(
       new SnapshotDto().setPeriodMode(1, "previous_analysis").setPeriodDate(1, periodDate)
-    );
+      );
     when(periods.label(anyString(), anyString(), any(Date.class))).thenReturn("since previous analysis (May 08 2014)");
 
     when(issueService.findRulesByComponent(COMPONENT_KEY, periodDate, session)).thenReturn(
       new RulesAggregation().add(new RuleDto().setRuleKey("AvoidCycle").setRepositoryKey("squid").setName("Avoid Cycle"))
-    );
+      );
 
     WsTester.TestRequest request = tester.newGetRequest("api/components", "app").setParam("key", COMPONENT_KEY).setParam("period", "1");
     request.execute().assertJson(getClass(), "app_with_rules_when_period_is_set.json");
@@ -485,11 +484,11 @@ public class ComponentAppActionTest {
     when(componentDao.getById(1L, session)).thenReturn(new ComponentDto().setId(1L).setLongName("SonarQube").setKey("org.codehaus.sonar:sonar"));
   }
 
-  private void addPeriod(){
+  private void addPeriod() {
     Date periodDate = DateUtils.parseDate("2014-05-08");
     when(resourceDao.getLastSnapshotByResourceId(eq(1L), eq(session))).thenReturn(
       new SnapshotDto().setPeriodMode(1, "previous_analysis").setPeriodDate(1, periodDate)
-    );
+      );
     when(periods.label(anyString(), anyString(), any(Date.class))).thenReturn("since previous analysis (May 08 2014)");
   }
 
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueServiceMediumTest.java
new file mode 100644 (file)
index 0000000..708b5dc
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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.issue;
+
+import com.google.common.collect.Multiset;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.issue.DefaultTransitions;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.api.rule.Severity;
+import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.ActionPlanDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.permission.PermissionFacade;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.user.UserDto;
+import org.sonar.server.component.SnapshotTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.issue.db.IssueDao;
+import org.sonar.server.issue.index.IssueIndex;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.QueryContext;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+
+public class DefaultIssueServiceMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.issues.use_es_backend", "true");
+
+  DbClient db;
+  IndexClient indexClient;
+  DbSession session;
+  IssueService service;
+
+  RuleDto rule;
+  ComponentDto project;
+  ComponentDto file;
+  UserDto connectedUser;
+
+  @Before
+  public void setUp() throws Exception {
+    tester.clearDbAndIndexes();
+    db = tester.get(DbClient.class);
+    indexClient = tester.get(IndexClient.class);
+    session = db.openSession(false);
+    service = tester.get(IssueService.class);
+
+    rule = RuleTesting.newXooX1();
+    tester.get(RuleDao.class).insert(session, rule);
+
+    project = new ComponentDto()
+      .setKey("MyProject")
+      .setLongName("My Project")
+      .setQualifier(Qualifiers.PROJECT)
+      .setScope(Scopes.PROJECT);
+    tester.get(ComponentDao.class).insert(session, project);
+    tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(project));
+
+    file = new ComponentDto()
+      .setProjectId(project.getId())
+      .setSubProjectId(project.getId())
+      .setKey("MyComponent")
+      .setLongName("My Component");
+    tester.get(ComponentDao.class).insert(session, file);
+    tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file));
+
+    // project can be seen by anyone
+    tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session);
+    db.issueAuthorizationDao().synchronizeAfter(session, new Date(0));
+
+    connectedUser = new UserDto().setLogin("gandalf").setName("Gandalf");
+    db.userDao().insert(session, connectedUser);
+    tester.get(PermissionFacade.class).insertUserPermission(project.getId(), connectedUser.getId(), UserRole.USER, session);
+
+    MockUserSession.set()
+      .setLogin(connectedUser.getLogin())
+      .setUserId(connectedUser.getId().intValue())
+      .setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN)
+      .addProjectPermissions(UserRole.USER, project.key())
+      .addProjectPermissions(UserRole.ISSUE_ADMIN, project.key());
+
+    session.commit();
+  }
+
+  @After
+  public void after() {
+    session.close();
+  }
+
+  @Test
+  public void can_facet() throws Exception {
+    IssueDto issue1 = newIssue().setActionPlanKey("P1");
+    IssueDto issue2 = newIssue().setActionPlanKey("P2").setResolution("NONE");
+    tester.get(IssueDao.class).insert(session, issue1, issue2);
+    session.commit();
+
+    org.sonar.server.search.Result<Issue> result = ((DefaultIssueService) service).search(IssueQuery.builder().build(), new QueryContext());
+    assertThat(result.getHits()).hasSize(2);
+    assertThat(result.getFacets()).isEmpty();
+
+    result = ((DefaultIssueService) service).search(IssueQuery.builder().build(), new QueryContext().setFacet(true));
+    assertThat(result.getFacets().keySet()).hasSize(4);
+    assertThat(result.getFacetKeys("actionPlan")).hasSize(2);
+  }
+
+  @Test
+  public void list_status() {
+    assertThat(service.listStatus()).containsExactly("OPEN", "CONFIRMED", "REOPENED", "RESOLVED", "CLOSED");
+  }
+
+  @Test
+  public void list_transitions() {
+    IssueDto issue = newIssue().setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE);
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    List<Transition> result = service.listTransitions(issue.getKey());
+    assertThat(result).hasSize(1);
+    assertThat(result.get(0).key()).isEqualTo("reopen");
+  }
+
+  @Test
+  public void do_transition() {
+    IssueDto issue = newIssue().setStatus(Issue.STATUS_OPEN);
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    assertThat(db.issueDao().getByKey(session, issue.getKey())).isNotNull();
+    IssueTesting.assertIsEquivalent(issue, indexClient.get(IssueIndex.class).getByKey(issue.getKey()));
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_OPEN);
+
+    service.doTransition(issue.getKey(), DefaultTransitions.CONFIRM);
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).status()).isEqualTo(Issue.STATUS_CONFIRMED);
+  }
+
+  @Test
+  public void assign() {
+    IssueDto issue = newIssue();
+    tester.get(IssueDao.class).insert(session, issue);
+
+    UserDto user = new UserDto().setLogin("perceval").setName("Perceval");
+    db.userDao().insert(session, user);
+    session.commit();
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isNull();
+
+    service.assign(issue.getKey(), user.getLogin());
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
+  }
+
+  @Test
+  public void un_assign() {
+    IssueDto issue = newIssue().setAssignee("perceval");
+    tester.get(IssueDao.class).insert(session, issue);
+
+    UserDto user = new UserDto().setLogin("perceval").setName("Perceval");
+    db.userDao().insert(session, user);
+    session.commit();
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isEqualTo("perceval");
+
+    service.assign(issue.getKey(), "");
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).assignee()).isNull();
+  }
+
+  @Test
+  public void fail_to_assign_on_unknown_user() {
+    IssueDto issue = newIssue();
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    try {
+      service.assign(issue.getKey(), "unknown");
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Unknown user: unknown");
+    }
+  }
+
+  @Test
+  public void plan() {
+    IssueDto issue = newIssue();
+    tester.get(IssueDao.class).insert(session, issue);
+
+    String actionPlanKey = "EFGH";
+    db.actionPlanDao().save(new ActionPlanDto().setKey(actionPlanKey).setProjectId(project.getId()));
+    session.commit();
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isNull();
+
+    service.plan(issue.getKey(), actionPlanKey);
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
+  }
+
+  @Test
+  public void un_plan() {
+    String actionPlanKey = "EFGH";
+    db.actionPlanDao().save(new ActionPlanDto().setKey(actionPlanKey).setProjectId(project.getId()));
+
+    IssueDto issue = newIssue().setActionPlanKey(actionPlanKey);
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isEqualTo(actionPlanKey);
+
+    service.plan(issue.getKey(), null);
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).actionPlanKey()).isNull();
+  }
+
+  @Test
+  public void fail_plan_if_action_plan_not_found() {
+    tester.get(IssueDao.class).insert(session, newIssue());
+    session.commit();
+
+    try {
+      service.plan("ABCD", "unknown");
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Unknown action plan: unknown");
+    }
+  }
+
+  @Test
+  public void set_severity() {
+    IssueDto issue = newIssue().setSeverity(Severity.BLOCKER);
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).severity()).isEqualTo(Severity.BLOCKER);
+
+    service.setSeverity(issue.getKey(), Severity.MINOR);
+
+    assertThat(indexClient.get(IssueIndex.class).getByKey(issue.getKey()).severity()).isEqualTo(Severity.MINOR);
+  }
+
+  @Test
+  public void create_manual_issue() {
+    RuleDto manualRule = RuleTesting.newManualRule("manualRuleKey");
+    tester.get(RuleDao.class).insert(session, manualRule);
+    session.commit();
+
+    Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 10, "Fix it", Severity.MINOR, 2d);
+
+    Issue manualIssue = indexClient.get(IssueIndex.class).getByKey(result.key());
+    assertThat(manualIssue.componentKey()).isEqualTo(file.key());
+    assertThat(manualIssue.projectKey()).isEqualTo(project.key());
+    assertThat(manualIssue.ruleKey()).isEqualTo(manualRule.getKey());
+    assertThat(manualIssue.message()).isEqualTo("Fix it");
+    assertThat(manualIssue.line()).isEqualTo(10);
+    assertThat(manualIssue.severity()).isEqualTo(Severity.MINOR);
+    assertThat(manualIssue.effortToFix()).isEqualTo(2d);
+    assertThat(manualIssue.reporter()).isEqualTo(connectedUser.getLogin());
+  }
+
+  @Test
+  public void create_manual_issue_with_major_severity_when_no_severity() {
+    RuleDto manualRule = RuleTesting.newManualRule("manualRuleKey");
+    tester.get(RuleDao.class).insert(session, manualRule);
+    session.commit();
+
+    Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 10, "Fix it", null, 2d);
+
+    Issue manualIssue = indexClient.get(IssueIndex.class).getByKey(result.key());
+    assertThat(manualIssue.severity()).isEqualTo(Severity.MAJOR);
+  }
+
+  @Test
+  public void create_manual_issue_with_rule_name_when_no_message() {
+    RuleDto manualRule = RuleTesting.newManualRule("manualRuleKey").setName("Manual rule name");
+    tester.get(RuleDao.class).insert(session, manualRule);
+    session.commit();
+
+    Issue result = service.createManualIssue(file.key(), manualRule.getKey(), 10, null, null, 2d);
+
+    Issue manualIssue = indexClient.get(IssueIndex.class).getByKey(result.key());
+    assertThat(manualIssue.message()).isEqualTo("Manual rule name");
+  }
+
+  @Test
+  public void fail_create_manual_issue_on_not_manual_rule() {
+    try {
+      service.createManualIssue(file.key(), rule.getKey(), 10, "Fix it", null, 2d);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues can be created only on rules marked as 'manual': xoo:x1");
+    }
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_create_manual_issue_if_not_having_required_role() {
+    // User has not the 'user' role on the project
+    MockUserSession.set()
+      .setLogin(connectedUser.getLogin())
+      .setUserId(connectedUser.getId().intValue())
+      .setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN)
+      .addProjectPermissions(UserRole.CODEVIEWER, project.key());
+
+    RuleDto manualRule = RuleTesting.newManualRule("manualRuleKey");
+    tester.get(RuleDao.class).insert(session, manualRule);
+    session.commit();
+
+    service.createManualIssue(file.key(), rule.getKey(), 10, "Fix it", null, 2d);
+  }
+
+  @Test
+  public void find_rules_by_component() throws Exception {
+    // 2 issues on the same rule
+    tester.get(IssueDao.class).insert(session, newIssue().setRule(rule));
+    tester.get(IssueDao.class).insert(session, newIssue().setRule(rule));
+    session.commit();
+
+    RulesAggregation result = service.findRulesByComponent(file.key(), null, session);
+    assertThat(result.rules()).hasSize(1);
+  }
+
+  @Test
+  public void find_rules_by_severity() throws Exception {
+    tester.get(IssueDao.class).insert(session, newIssue().setSeverity(Severity.MAJOR));
+    tester.get(IssueDao.class).insert(session, newIssue().setSeverity(Severity.MAJOR));
+    tester.get(IssueDao.class).insert(session, newIssue().setSeverity(Severity.INFO));
+    session.commit();
+
+    Multiset<String> result = service.findSeveritiesByComponent(file.key(), null, session);
+    assertThat(result.count("MAJOR")).isEqualTo(2);
+    assertThat(result.count("INFO")).isEqualTo(1);
+    assertThat(result.count("UNKNOWN")).isEqualTo(0);
+  }
+
+  private IssueDto newIssue() {
+    return new IssueDto()
+      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
+      .setIssueUpdateDate(DateUtils.parseDate("2014-12-04"))
+      .setRule(rule)
+      .setDebt(10L)
+      .setRootComponent(project)
+      .setComponent(file)
+      .setStatus(Issue.STATUS_OPEN)
+      .setResolution(null)
+      .setSeverity(Severity.MAJOR)
+      .setKee(UUID.randomUUID().toString());
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyDefaultIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyDefaultIssueServiceTest.java
new file mode 100644 (file)
index 0000000..b807c0b
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * 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.issue;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+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;
+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.user.User;
+import org.sonar.core.issue.DefaultActionPlan;
+import org.sonar.core.issue.DefaultIssueFilter;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.ResourceDto;
+import org.sonar.core.resource.ResourceQuery;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.Message;
+import org.sonar.server.issue.actionplan.ActionPlanService;
+import org.sonar.server.issue.filter.IssueFilterService;
+import org.sonar.server.user.UserSession;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InternalRubyDefaultIssueServiceTest {
+
+  @Mock
+  IssueService issueService;
+
+  @Mock
+  IssueCommentService commentService;
+
+  @Mock
+  IssueChangelogService changelogService;
+
+  @Mock
+  ActionPlanService actionPlanService;
+
+  @Mock
+  ResourceDao resourceDao;
+
+  @Mock
+  IssueStatsFinder issueStatsFinder;
+
+  @Mock
+  ActionService actionService;
+
+  @Mock
+  IssueFilterService issueFilterService;
+
+  @Mock
+  IssueBulkChangeService issueBulkChangeService;
+
+  InternalRubyIssueService service;
+
+  @Before
+  public void setUp() {
+    ResourceDto project = new ResourceDto().setKey("org.sonar.Sample");
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(project);
+    service = new InternalRubyIssueService(issueService, commentService, changelogService, actionPlanService, issueStatsFinder, resourceDao, actionService,
+      issueFilterService, issueBulkChangeService);
+  }
+
+  @Test
+  public void find_issue_assignees() throws Exception {
+    service.findIssueAssignees(ImmutableMap.<String, Object>of("issues", "ABCD"));
+    verify(issueStatsFinder).findIssueAssignees(any(IssueQuery.class));
+  }
+
+  @Test
+  public void list_transitions_by_issue_key() throws Exception {
+    service.listTransitions("ABCD");
+    verify(issueService).listTransitions(eq("ABCD"));
+  }
+
+  @Test
+  public void list_transitions_by_issue() throws Exception {
+    Issue issue = new DefaultIssue().setKey("ABCD");
+    service.listTransitions(issue);
+    verify(issueService).listTransitions(eq(issue));
+  }
+
+  @Test
+  public void list_status() throws Exception {
+    service.listStatus();
+    verify(issueService).listStatus();
+  }
+
+  @Test
+  public void list_resolutions() throws Exception {
+    assertThat(service.listResolutions()).isEqualTo(Issue.RESOLUTIONS);
+  }
+
+  @Test
+  public void list_plugin_actions() {
+    Action action = mock(Action.class);
+    when(action.key()).thenReturn("link-to-jira");
+
+    when(actionService.listAllActions()).thenReturn(newArrayList(action));
+
+    assertThat(service.listPluginActions()).containsOnly("link-to-jira");
+  }
+
+  @Test
+  public void do_transition() throws Exception {
+    service.doTransition("ABCD", Issue.STATUS_RESOLVED);
+    verify(issueService).doTransition(eq("ABCD"), eq(Issue.STATUS_RESOLVED));
+  }
+
+  @Test
+  public void create_action_plan() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+    parameters.put("deadLine", "2113-05-13");
+
+    Result result = service.createActionPlan(parameters);
+    assertThat(result.ok()).isTrue();
+
+    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
+    verify(actionPlanService).create(actionPlanCaptor.capture(), any(UserSession.class));
+    ActionPlan actionPlan = actionPlanCaptor.getValue();
+
+    assertThat(actionPlan).isNotNull();
+    assertThat(actionPlan.key()).isNotNull();
+    assertThat(actionPlan.name()).isEqualTo("Long term");
+    assertThat(actionPlan.description()).isEqualTo("Long term issues");
+    assertThat(actionPlan.deadLine()).isNotNull();
+  }
+
+  @Test
+  public void update_action_plan() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
+
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "New Long term");
+    parameters.put("description", "New Long term issues");
+    parameters.put("deadLine", "2113-05-13");
+    parameters.put("project", "org.sonar.MultiSample");
+
+    Result result = service.updateActionPlan("ABCD", parameters);
+    assertThat(result.ok()).isTrue();
+
+    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
+    verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
+    ActionPlan actionPlan = actionPlanCaptor.getValue();
+
+    assertThat(actionPlan).isNotNull();
+    assertThat(actionPlan.key()).isNotNull();
+    assertThat(actionPlan.name()).isEqualTo("New Long term");
+    assertThat(actionPlan.description()).isEqualTo("New Long term issues");
+    assertThat(actionPlan.deadLine()).isNotNull();
+  }
+
+  @Test
+  public void update_action_plan_with_new_project() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term").setProjectKey("org.sonar.MultiSample"));
+
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "New Long term");
+    parameters.put("description", "New Long term issues");
+    parameters.put("deadLine", "2113-05-13");
+
+    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
+    Result result = service.updateActionPlan("ABCD", parameters);
+    assertThat(result.ok()).isTrue();
+
+    verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
+    ActionPlan actionPlan = actionPlanCaptor.getValue();
+
+    assertThat(actionPlan).isNotNull();
+    assertThat(actionPlan.key()).isNotNull();
+    assertThat(actionPlan.name()).isEqualTo("New Long term");
+    assertThat(actionPlan.description()).isEqualTo("New Long term issues");
+    assertThat(actionPlan.deadLine()).isNotNull();
+    assertThat(actionPlan.projectKey()).isEqualTo("org.sonar.MultiSample");
+  }
+
+  @Test
+  public void not_update_action_plan_when_action_plan_is_not_found() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
+
+    Result result = service.updateActionPlan("ABCD", null);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.action_plan_does_not_exist", "ABCD"));
+  }
+
+  @Test
+  public void delete_action_plan() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
+
+    Result result = service.deleteActionPlan("ABCD");
+    verify(actionPlanService).delete(eq("ABCD"), any(UserSession.class));
+    assertThat(result.ok()).isTrue();
+  }
+
+  @Test
+  public void not_delete_action_plan_if_action_plan_not_found() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
+
+    Result result = service.deleteActionPlan("ABCD");
+    verify(actionPlanService, never()).delete(eq("ABCD"), any(UserSession.class));
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.action_plan_does_not_exist", "ABCD"));
+  }
+
+  @Test
+  public void close_action_plan() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
+
+    Result result = service.closeActionPlan("ABCD");
+    verify(actionPlanService).setStatus(eq("ABCD"), eq("CLOSED"), any(UserSession.class));
+    assertThat(result.ok()).isTrue();
+  }
+
+  @Test
+  public void open_action_plan() {
+    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
+
+    Result result = service.openActionPlan("ABCD");
+    verify(actionPlanService).setStatus(eq("ABCD"), eq("OPEN"), any(UserSession.class));
+    assertThat(result.ok()).isTrue();
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_no_project() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "project"));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_no_name() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", null);
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "name"));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_name_is_too_long() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", createLongString(201));
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "name", 200));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_description_is_too_long() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", createLongString(1001));
+    parameters.put("project", "org.sonar.Sample");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "description", 1000));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_dead_line_use_wrong_format() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+    parameters.put("deadLine", "18/05/2013");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_not_valid", "date"));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_dead_line_is_in_the_past() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+    parameters.put("deadLine", "2000-01-01");
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.date_cant_be_in_past"));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_name_is_already_used_for_project() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+
+    when(actionPlanService.isNameAlreadyUsedForProject(anyString(), anyString())).thenReturn(true);
+
+    Result result = service.createActionPlanResult(parameters, DefaultActionPlan.create("Short term"));
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.same_name_in_same_project"));
+  }
+
+  @Test
+  public void get_error_on_action_plan_result_when_project_not_found() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("project", "org.sonar.Sample");
+
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null);
+
+    Result result = service.createActionPlanResult(parameters);
+    assertThat(result.ok()).isFalse();
+    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", "org.sonar.Sample"));
+  }
+
+  @Test
+  public void test_changelog_from_issue_key() throws Exception {
+    IssueChangelog changelog = new IssueChangelog(Collections.<FieldDiffs>emptyList(), Collections.<User>emptyList());
+    when(changelogService.changelog(eq("ABCDE"))).thenReturn(changelog);
+
+    IssueChangelog result = service.changelog("ABCDE");
+
+    assertThat(result).isSameAs(changelog);
+  }
+
+  @Test
+  public void test_changelog_from_issue() throws Exception {
+    Issue issue = new DefaultIssue().setKey("ABCDE");
+
+    IssueChangelog changelog = new IssueChangelog(Collections.<FieldDiffs>emptyList(), Collections.<User>emptyList());
+    when(changelogService.changelog(eq(issue))).thenReturn(changelog);
+
+    IssueChangelog result = service.changelog(issue);
+
+    assertThat(result).isSameAs(changelog);
+  }
+
+  @Test
+  public void create_issue_filter() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+
+    service.createIssueFilter(parameters);
+
+    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
+    verify(issueFilterService).save(issueFilterCaptor.capture(), any(UserSession.class));
+    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
+    assertThat(issueFilter.name()).isEqualTo("Long term");
+    assertThat(issueFilter.description()).isEqualTo("Long term issues");
+  }
+
+  @Test
+  public void update_issue_filter() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("id", "10");
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("user", "John");
+
+    service.updateIssueFilter(parameters);
+
+    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
+    verify(issueFilterService).update(issueFilterCaptor.capture(), any(UserSession.class));
+    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
+    assertThat(issueFilter.id()).isEqualTo(10L);
+    assertThat(issueFilter.name()).isEqualTo("Long term");
+    assertThat(issueFilter.description()).isEqualTo("Long term issues");
+  }
+
+  @Test
+  public void update_data() {
+    Map<String, Object> data = newHashMap();
+    service.updateIssueFilterQuery(10L, data);
+    verify(issueFilterService).updateFilterQuery(eq(10L), eq(data), any(UserSession.class));
+  }
+
+  @Test
+  public void delete_issue_filter() {
+    service.deleteIssueFilter(1L);
+    verify(issueFilterService).delete(eq(1L), any(UserSession.class));
+  }
+
+  @Test
+  public void copy_issue_filter() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Copy of Long term");
+    parameters.put("description", "Copy of Long term issues");
+
+    service.copyIssueFilter(1L, parameters);
+
+    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
+    verify(issueFilterService).copy(eq(1L), issueFilterCaptor.capture(), any(UserSession.class));
+    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
+    assertThat(issueFilter.name()).isEqualTo("Copy of Long term");
+    assertThat(issueFilter.description()).isEqualTo("Copy of Long term issues");
+  }
+
+  @Test
+  public void get_error_on_create_issue_filter_result_when_no_name() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "");
+    parameters.put("description", "Long term issues");
+    parameters.put("user", "John");
+
+    try {
+      service.createIssueFilterResultForNew(parameters);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+      checkBadRequestException(e, "errors.cant_be_empty", "name");
+    }
+  }
+
+  @Test
+  public void get_error_on_create_issue_filter_result_when_name_is_too_long() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", createLongString(101));
+    parameters.put("description", "Long term issues");
+    parameters.put("user", "John");
+
+    try {
+      service.createIssueFilterResultForNew(parameters);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+      checkBadRequestException(e, "errors.is_too_long", "name", 100);
+    }
+  }
+
+  @Test
+  public void get_error_on_create_issue_filter_result_when_description_is_too_long() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("name", "Long term");
+    parameters.put("description", createLongString(4001));
+    parameters.put("user", "John");
+
+    try {
+      service.createIssueFilterResultForNew(parameters);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+      checkBadRequestException(e, "errors.is_too_long", "description", 4000);
+    }
+  }
+
+  @Test
+  public void get_error_on_create_issue_filter_result_when_id_is_null_on_update() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("id", null);
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("user", "John");
+
+    try {
+      service.createIssueFilterResultForUpdate(parameters);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+      checkBadRequestException(e, "errors.cant_be_empty", "id");
+    }
+  }
+
+  @Test
+  public void get_error_on_create_issue_filter_result_when_user_is_null_on_update() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("id", "10");
+    parameters.put("name", "All Open Issues");
+    parameters.put("description", "Long term issues");
+    parameters.put("user", null);
+
+    try {
+      service.createIssueFilterResultForUpdate(parameters);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(BadRequestException.class);
+      checkBadRequestException(e, "errors.cant_be_empty", "user");
+    }
+  }
+
+  @Test
+  public void get_no_error_on_issue_filter_result_when_id_and_user_are_null_on_copy() {
+    Map<String, String> parameters = newHashMap();
+    parameters.put("id", null);
+    parameters.put("name", "Long term");
+    parameters.put("description", "Long term issues");
+    parameters.put("user", null);
+
+    DefaultIssueFilter result = service.createIssueFilterResultForCopy(parameters);
+    assertThat(result).isNotNull();
+  }
+
+  @Test
+  public void execute_issue_filter_from_issue_query() {
+    service.execute(Maps.<String, Object>newHashMap());
+    verify(issueFilterService).execute(any(IssueQuery.class));
+  }
+
+  @Test
+  public void execute_issue_filter_from_existing_filter() {
+    Map<String, Object> props = newHashMap();
+    props.put("componentRoots", "struts");
+    props.put("statuses", "OPEN");
+    when(issueFilterService.deserializeIssueFilterQuery(any(DefaultIssueFilter.class))).thenReturn(props);
+
+    Map<String, Object> overrideProps = newHashMap();
+    overrideProps.put("statuses", "CLOSED");
+    overrideProps.put("resolved", true);
+    overrideProps.put("pageSize", 20);
+    overrideProps.put("pageIndex", 2);
+    service.execute(10L, overrideProps);
+    ArgumentCaptor<IssueQuery> captor = ArgumentCaptor.forClass(IssueQuery.class);
+    verify(issueFilterService).execute(captor.capture());
+    verify(issueFilterService).find(eq(10L), any(UserSession.class));
+
+    IssueQuery issueQuery = captor.getValue();
+    assertThat(issueQuery.componentRoots()).contains("struts");
+    assertThat(issueQuery.statuses()).contains("CLOSED");
+    assertThat(issueQuery.resolved()).isTrue();
+    assertThat(issueQuery.pageSize()).isEqualTo(20);
+    assertThat(issueQuery.pageIndex()).isEqualTo(2);
+  }
+
+  @Test
+  public void serialize_filter_query() {
+    Map<String, Object> props = newHashMap();
+    props.put("componentRoots", "struts");
+    service.serializeFilterQuery(props);
+    verify(issueFilterService).serializeFilterQuery(props);
+  }
+
+  @Test
+  public void deserialize_filter_query() {
+    DefaultIssueFilter issueFilter = new DefaultIssueFilter();
+    service.deserializeFilterQuery(issueFilter);
+    verify(issueFilterService).deserializeIssueFilterQuery(issueFilter);
+  }
+
+  @Test
+  public void sanitize_filter_query() {
+    Map<String, Object> query = newHashMap();
+    query.put("statuses", "CLOSED");
+    query.put("resolved", true);
+    query.put("unknown", "john");
+    Map<String, Object> result = service.sanitizeFilterQuery(query);
+    assertThat(result.keySet()).containsOnly("statuses", "resolved");
+  }
+
+  @Test
+  public void find_user_issue_filters() {
+    service.findIssueFiltersForCurrentUser();
+    verify(issueFilterService).findByUser(any(UserSession.class));
+  }
+
+  @Test
+  public void find_shared_issue_filters() {
+    service.findSharedFiltersForCurrentUser();
+    verify(issueFilterService).findSharedFiltersWithoutUserFilters(any(UserSession.class));
+  }
+
+  @Test
+  public void find_favourite_issue_filters() {
+    service.findFavouriteIssueFiltersForCurrentUser();
+    verify(issueFilterService).findFavoriteFilters(any(UserSession.class));
+  }
+
+  @Test
+  public void toggle_favourite_issue_filter() {
+    service.toggleFavouriteIssueFilter(10L);
+    verify(issueFilterService).toggleFavouriteIssueFilter(eq(10L), any(UserSession.class));
+  }
+
+  @Test
+  public void check_if_user_is_authorized_to_see_issue_filter() {
+    DefaultIssueFilter issueFilter = new DefaultIssueFilter();
+    service.isUserAuthorized(issueFilter);
+    verify(issueFilterService).getLoggedLogin(any(UserSession.class));
+    verify(issueFilterService).verifyCurrentUserCanReadFilter(eq(issueFilter), anyString());
+  }
+
+  @Test
+  public void check_if_user_can_share_issue_filter() {
+    service.canUserShareIssueFilter();
+    verify(issueFilterService).canShareFilter(any(UserSession.class));
+  }
+
+  @Test
+  public void execute_bulk_change() {
+    Map<String, Object> params = newHashMap();
+    params.put("issues", newArrayList("ABCD", "EFGH"));
+    params.put("actions", newArrayList("do_transition", "assign", "set_severity", "plan"));
+    params.put("do_transition.transition", "confirm");
+    params.put("assign.assignee", "arthur");
+    params.put("set_severity.severity", "MINOR");
+    params.put("plan.plan", "3.7");
+    service.bulkChange(params, "My comment", true);
+    verify(issueBulkChangeService).execute(any(IssueBulkChangeQuery.class), any(UserSession.class));
+  }
+
+  @Test
+  public void format_changelog() {
+    FieldDiffs fieldDiffs = new FieldDiffs();
+    service.formatChangelog(fieldDiffs);
+    verify(changelogService).formatDiffs(eq(fieldDiffs));
+  }
+
+  private void checkBadRequestException(Exception e, String key, Object... params) {
+    BadRequestException exception = (BadRequestException) e;
+    Message msg = exception.errors().messages().get(0);
+    assertThat(msg.getKey()).isEqualTo(key);
+    assertThat(msg.getParams()).containsOnly(params);
+  }
+
+  private String createLongString(int size) {
+    String result = "";
+    for (int i = 0; i < size; i++) {
+      result += "c";
+    }
+    return result;
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
deleted file mode 100644 (file)
index 508890b..0000000
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * 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.issue;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-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;
-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.user.User;
-import org.sonar.core.issue.DefaultActionPlan;
-import org.sonar.core.issue.DefaultIssueFilter;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.Message;
-import org.sonar.server.issue.actionplan.ActionPlanService;
-import org.sonar.server.issue.filter.IssueFilterService;
-import org.sonar.server.user.UserSession;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class InternalRubyIssueServiceTest {
-
-  @Mock
-  IssueService issueService;
-
-  @Mock
-  IssueCommentService commentService = mock(IssueCommentService.class);
-
-  @Mock
-  IssueChangelogService changelogService = mock(IssueChangelogService.class);
-
-  @Mock
-  ActionPlanService actionPlanService = mock(ActionPlanService.class);
-
-  @Mock
-  ResourceDao resourceDao = mock(ResourceDao.class);
-
-  @Mock
-  IssueStatsFinder issueStatsFinder = mock(IssueStatsFinder.class);
-
-  @Mock
-  ActionService actionService = mock(ActionService.class);
-
-  @Mock
-  IssueFilterService issueFilterService = mock(IssueFilterService.class);
-
-  @Mock
-  IssueBulkChangeService issueBulkChangeService = mock(IssueBulkChangeService.class);
-
-  InternalRubyIssueService service;
-
-  @Before
-  public void setUp() {
-    ResourceDto project = new ResourceDto().setKey("org.sonar.Sample");
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(project);
-    service = new InternalRubyIssueService(issueService, commentService, changelogService, actionPlanService, issueStatsFinder, resourceDao, actionService,
-      issueFilterService, issueBulkChangeService);
-  }
-
-  @Test
-  public void find_issue_assignees() throws Exception {
-    service.findIssueAssignees(ImmutableMap.<String, Object>of("issues", "ABCD"));
-    verify(issueStatsFinder).findIssueAssignees(any(IssueQuery.class));
-  }
-
-  @Test
-  public void list_transitions_by_issue_key() throws Exception {
-    service.listTransitions("ABCD");
-    verify(issueService).listTransitions(eq("ABCD"), any(UserSession.class));
-  }
-
-  @Test
-  public void list_transitions_by_issue() throws Exception {
-    Issue issue = new DefaultIssue().setKey("ABCD");
-    service.listTransitions(issue);
-    verify(issueService).listTransitions(eq(issue), any(UserSession.class));
-  }
-
-  @Test
-  public void list_status() throws Exception {
-    service.listStatus();
-    verify(issueService).listStatus();
-  }
-
-  @Test
-  public void list_resolutions() throws Exception {
-    assertThat(service.listResolutions()).isEqualTo(Issue.RESOLUTIONS);
-  }
-
-  @Test
-  public void list_plugin_actions() {
-    Action action = mock(Action.class);
-    when(action.key()).thenReturn("link-to-jira");
-
-    when(actionService.listAllActions()).thenReturn(newArrayList(action));
-
-    assertThat(service.listPluginActions()).containsOnly("link-to-jira");
-  }
-
-  @Test
-  public void do_transition() throws Exception {
-    service.doTransition("ABCD", Issue.STATUS_RESOLVED);
-    verify(issueService).doTransition(eq("ABCD"), eq(Issue.STATUS_RESOLVED), any(UserSession.class));
-  }
-
-  @Test
-  public void create_action_plan() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-    parameters.put("deadLine", "2113-05-13");
-
-    Result result = service.createActionPlan(parameters);
-    assertThat(result.ok()).isTrue();
-
-    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
-    verify(actionPlanService).create(actionPlanCaptor.capture(), any(UserSession.class));
-    ActionPlan actionPlan = actionPlanCaptor.getValue();
-
-    assertThat(actionPlan).isNotNull();
-    assertThat(actionPlan.key()).isNotNull();
-    assertThat(actionPlan.name()).isEqualTo("Long term");
-    assertThat(actionPlan.description()).isEqualTo("Long term issues");
-    assertThat(actionPlan.deadLine()).isNotNull();
-  }
-
-  @Test
-  public void update_action_plan() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
-
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "New Long term");
-    parameters.put("description", "New Long term issues");
-    parameters.put("deadLine", "2113-05-13");
-    parameters.put("project", "org.sonar.MultiSample");
-
-    Result result = service.updateActionPlan("ABCD", parameters);
-    assertThat(result.ok()).isTrue();
-
-    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
-    verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
-    ActionPlan actionPlan = actionPlanCaptor.getValue();
-
-    assertThat(actionPlan).isNotNull();
-    assertThat(actionPlan.key()).isNotNull();
-    assertThat(actionPlan.name()).isEqualTo("New Long term");
-    assertThat(actionPlan.description()).isEqualTo("New Long term issues");
-    assertThat(actionPlan.deadLine()).isNotNull();
-  }
-
-  @Test
-  public void update_action_plan_with_new_project() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term").setProjectKey("org.sonar.MultiSample"));
-
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "New Long term");
-    parameters.put("description", "New Long term issues");
-    parameters.put("deadLine", "2113-05-13");
-
-    ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
-    Result result = service.updateActionPlan("ABCD", parameters);
-    assertThat(result.ok()).isTrue();
-
-    verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
-    ActionPlan actionPlan = actionPlanCaptor.getValue();
-
-    assertThat(actionPlan).isNotNull();
-    assertThat(actionPlan.key()).isNotNull();
-    assertThat(actionPlan.name()).isEqualTo("New Long term");
-    assertThat(actionPlan.description()).isEqualTo("New Long term issues");
-    assertThat(actionPlan.deadLine()).isNotNull();
-    assertThat(actionPlan.projectKey()).isEqualTo("org.sonar.MultiSample");
-  }
-
-  @Test
-  public void not_update_action_plan_when_action_plan_is_not_found() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
-
-    Result result = service.updateActionPlan("ABCD", null);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.action_plan_does_not_exist", "ABCD"));
-  }
-
-  @Test
-  public void delete_action_plan() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
-
-    Result result = service.deleteActionPlan("ABCD");
-    verify(actionPlanService).delete(eq("ABCD"), any(UserSession.class));
-    assertThat(result.ok()).isTrue();
-  }
-
-  @Test
-  public void not_delete_action_plan_if_action_plan_not_found() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
-
-    Result result = service.deleteActionPlan("ABCD");
-    verify(actionPlanService, never()).delete(eq("ABCD"), any(UserSession.class));
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.action_plan_does_not_exist", "ABCD"));
-  }
-
-  @Test
-  public void close_action_plan() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
-
-    Result result = service.closeActionPlan("ABCD");
-    verify(actionPlanService).setStatus(eq("ABCD"), eq("CLOSED"), any(UserSession.class));
-    assertThat(result.ok()).isTrue();
-  }
-
-  @Test
-  public void open_action_plan() {
-    when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
-
-    Result result = service.openActionPlan("ABCD");
-    verify(actionPlanService).setStatus(eq("ABCD"), eq("OPEN"), any(UserSession.class));
-    assertThat(result.ok()).isTrue();
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_no_project() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "project"));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_no_name() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", null);
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "name"));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_name_is_too_long() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", createLongString(201));
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "name", 200));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_description_is_too_long() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", createLongString(1001));
-    parameters.put("project", "org.sonar.Sample");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "description", 1000));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_dead_line_use_wrong_format() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-    parameters.put("deadLine", "18/05/2013");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_not_valid", "date"));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_dead_line_is_in_the_past() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-    parameters.put("deadLine", "2000-01-01");
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.date_cant_be_in_past"));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_name_is_already_used_for_project() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-
-    when(actionPlanService.isNameAlreadyUsedForProject(anyString(), anyString())).thenReturn(true);
-
-    Result result = service.createActionPlanResult(parameters, DefaultActionPlan.create("Short term"));
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.same_name_in_same_project"));
-  }
-
-  @Test
-  public void get_error_on_action_plan_result_when_project_not_found() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("project", "org.sonar.Sample");
-
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null);
-
-    Result result = service.createActionPlanResult(parameters);
-    assertThat(result.ok()).isFalse();
-    assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.errors.project_does_not_exist", "org.sonar.Sample"));
-  }
-
-  @Test
-  public void test_changelog_from_issue_key() throws Exception {
-    IssueChangelog changelog = new IssueChangelog(Collections.<FieldDiffs>emptyList(), Collections.<User>emptyList());
-    when(changelogService.changelog(eq("ABCDE"))).thenReturn(changelog);
-
-    IssueChangelog result = service.changelog("ABCDE");
-
-    assertThat(result).isSameAs(changelog);
-  }
-
-  @Test
-  public void test_changelog_from_issue() throws Exception {
-    Issue issue = new DefaultIssue().setKey("ABCDE");
-
-    IssueChangelog changelog = new IssueChangelog(Collections.<FieldDiffs>emptyList(), Collections.<User>emptyList());
-    when(changelogService.changelog(eq(issue))).thenReturn(changelog);
-
-    IssueChangelog result = service.changelog(issue);
-
-    assertThat(result).isSameAs(changelog);
-  }
-
-  @Test
-  public void create_issue_filter() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-
-    service.createIssueFilter(parameters);
-
-    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
-    verify(issueFilterService).save(issueFilterCaptor.capture(), any(UserSession.class));
-    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
-    assertThat(issueFilter.name()).isEqualTo("Long term");
-    assertThat(issueFilter.description()).isEqualTo("Long term issues");
-  }
-
-  @Test
-  public void update_issue_filter() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("id", "10");
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("user", "John");
-
-    service.updateIssueFilter(parameters);
-
-    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
-    verify(issueFilterService).update(issueFilterCaptor.capture(), any(UserSession.class));
-    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
-    assertThat(issueFilter.id()).isEqualTo(10L);
-    assertThat(issueFilter.name()).isEqualTo("Long term");
-    assertThat(issueFilter.description()).isEqualTo("Long term issues");
-  }
-
-  @Test
-  public void update_data() {
-    Map<String, Object> data = newHashMap();
-    service.updateIssueFilterQuery(10L, data);
-    verify(issueFilterService).updateFilterQuery(eq(10L), eq(data), any(UserSession.class));
-  }
-
-  @Test
-  public void delete_issue_filter() {
-    service.deleteIssueFilter(1L);
-    verify(issueFilterService).delete(eq(1L), any(UserSession.class));
-  }
-
-  @Test
-  public void copy_issue_filter() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Copy of Long term");
-    parameters.put("description", "Copy of Long term issues");
-
-    service.copyIssueFilter(1L, parameters);
-
-    ArgumentCaptor<DefaultIssueFilter> issueFilterCaptor = ArgumentCaptor.forClass(DefaultIssueFilter.class);
-    verify(issueFilterService).copy(eq(1L), issueFilterCaptor.capture(), any(UserSession.class));
-    DefaultIssueFilter issueFilter = issueFilterCaptor.getValue();
-    assertThat(issueFilter.name()).isEqualTo("Copy of Long term");
-    assertThat(issueFilter.description()).isEqualTo("Copy of Long term issues");
-  }
-
-  @Test
-  public void get_error_on_create_issue_filter_result_when_no_name() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "");
-    parameters.put("description", "Long term issues");
-    parameters.put("user", "John");
-
-    try {
-      service.createIssueFilterResultForNew(parameters);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class);
-      checkBadRequestException(e, "errors.cant_be_empty", "name");
-    }
-  }
-
-  @Test
-  public void get_error_on_create_issue_filter_result_when_name_is_too_long() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", createLongString(101));
-    parameters.put("description", "Long term issues");
-    parameters.put("user", "John");
-
-    try {
-      service.createIssueFilterResultForNew(parameters);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class);
-      checkBadRequestException(e, "errors.is_too_long", "name", 100);
-    }
-  }
-
-  @Test
-  public void get_error_on_create_issue_filter_result_when_description_is_too_long() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("name", "Long term");
-    parameters.put("description", createLongString(4001));
-    parameters.put("user", "John");
-
-    try {
-      service.createIssueFilterResultForNew(parameters);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class);
-      checkBadRequestException(e, "errors.is_too_long", "description", 4000);
-    }
-  }
-
-  @Test
-  public void get_error_on_create_issue_filter_result_when_id_is_null_on_update() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("id", null);
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("user", "John");
-
-    try {
-      service.createIssueFilterResultForUpdate(parameters);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class);
-      checkBadRequestException(e, "errors.cant_be_empty", "id");
-    }
-  }
-
-  @Test
-  public void get_error_on_create_issue_filter_result_when_user_is_null_on_update() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("id", "10");
-    parameters.put("name", "All Open Issues");
-    parameters.put("description", "Long term issues");
-    parameters.put("user", null);
-
-    try {
-      service.createIssueFilterResultForUpdate(parameters);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(BadRequestException.class);
-      checkBadRequestException(e, "errors.cant_be_empty", "user");
-    }
-  }
-
-  @Test
-  public void get_no_error_on_issue_filter_result_when_id_and_user_are_null_on_copy() {
-    Map<String, String> parameters = newHashMap();
-    parameters.put("id", null);
-    parameters.put("name", "Long term");
-    parameters.put("description", "Long term issues");
-    parameters.put("user", null);
-
-    DefaultIssueFilter result = service.createIssueFilterResultForCopy(parameters);
-    assertThat(result).isNotNull();
-  }
-
-  @Test
-  public void execute_issue_filter_from_issue_query() {
-    service.execute(Maps.<String, Object>newHashMap());
-    verify(issueFilterService).execute(any(IssueQuery.class));
-  }
-
-  @Test
-  public void execute_issue_filter_from_existing_filter() {
-    Map<String, Object> props = newHashMap();
-    props.put("componentRoots", "struts");
-    props.put("statuses", "OPEN");
-    when(issueFilterService.deserializeIssueFilterQuery(any(DefaultIssueFilter.class))).thenReturn(props);
-
-    Map<String, Object> overrideProps = newHashMap();
-    overrideProps.put("statuses", "CLOSED");
-    overrideProps.put("resolved", true);
-    overrideProps.put("pageSize", 20);
-    overrideProps.put("pageIndex", 2);
-    service.execute(10L, overrideProps);
-    ArgumentCaptor<IssueQuery> captor = ArgumentCaptor.forClass(IssueQuery.class);
-    verify(issueFilterService).execute(captor.capture());
-    verify(issueFilterService).find(eq(10L), any(UserSession.class));
-
-    IssueQuery issueQuery = captor.getValue();
-    assertThat(issueQuery.componentRoots()).contains("struts");
-    assertThat(issueQuery.statuses()).contains("CLOSED");
-    assertThat(issueQuery.resolved()).isTrue();
-    assertThat(issueQuery.pageSize()).isEqualTo(20);
-    assertThat(issueQuery.pageIndex()).isEqualTo(2);
-  }
-
-  @Test
-  public void serialize_filter_query() {
-    Map<String, Object> props = newHashMap();
-    props.put("componentRoots", "struts");
-    service.serializeFilterQuery(props);
-    verify(issueFilterService).serializeFilterQuery(props);
-  }
-
-  @Test
-  public void deserialize_filter_query() {
-    DefaultIssueFilter issueFilter = new DefaultIssueFilter();
-    service.deserializeFilterQuery(issueFilter);
-    verify(issueFilterService).deserializeIssueFilterQuery(issueFilter);
-  }
-
-  @Test
-  public void sanitize_filter_query() {
-    Map<String, Object> query = newHashMap();
-    query.put("statuses", "CLOSED");
-    query.put("resolved", true);
-    query.put("unknown", "john");
-    Map<String, Object> result = service.sanitizeFilterQuery(query);
-    assertThat(result.keySet()).containsOnly("statuses", "resolved");
-  }
-
-  @Test
-  public void find_user_issue_filters() {
-    service.findIssueFiltersForCurrentUser();
-    verify(issueFilterService).findByUser(any(UserSession.class));
-  }
-
-  @Test
-  public void find_shared_issue_filters() {
-    service.findSharedFiltersForCurrentUser();
-    verify(issueFilterService).findSharedFiltersWithoutUserFilters(any(UserSession.class));
-  }
-
-  @Test
-  public void find_favourite_issue_filters() {
-    service.findFavouriteIssueFiltersForCurrentUser();
-    verify(issueFilterService).findFavoriteFilters(any(UserSession.class));
-  }
-
-  @Test
-  public void toggle_favourite_issue_filter() {
-    service.toggleFavouriteIssueFilter(10L);
-    verify(issueFilterService).toggleFavouriteIssueFilter(eq(10L), any(UserSession.class));
-  }
-
-  @Test
-  public void check_if_user_is_authorized_to_see_issue_filter() {
-    DefaultIssueFilter issueFilter = new DefaultIssueFilter();
-    service.isUserAuthorized(issueFilter);
-    verify(issueFilterService).getLoggedLogin(any(UserSession.class));
-    verify(issueFilterService).verifyCurrentUserCanReadFilter(eq(issueFilter), anyString());
-  }
-
-  @Test
-  public void check_if_user_can_share_issue_filter() {
-    service.canUserShareIssueFilter();
-    verify(issueFilterService).canShareFilter(any(UserSession.class));
-  }
-
-  @Test
-  public void execute_bulk_change() {
-    Map<String, Object> params = newHashMap();
-    params.put("issues", newArrayList("ABCD", "EFGH"));
-    params.put("actions", newArrayList("do_transition", "assign", "set_severity", "plan"));
-    params.put("do_transition.transition", "confirm");
-    params.put("assign.assignee", "arthur");
-    params.put("set_severity.severity", "MINOR");
-    params.put("plan.plan", "3.7");
-    service.bulkChange(params, "My comment", true);
-    verify(issueBulkChangeService).execute(any(IssueBulkChangeQuery.class), any(UserSession.class));
-  }
-
-  @Test
-  public void format_changelog() {
-    FieldDiffs fieldDiffs = new FieldDiffs();
-    service.formatChangelog(fieldDiffs);
-    verify(changelogService).formatDiffs(eq(fieldDiffs));
-  }
-
-  private void checkBadRequestException(Exception e, String key, Object... params) {
-    BadRequestException exception = (BadRequestException) e;
-    Message msg = exception.errors().messages().get(0);
-    assertThat(msg.getKey()).isEqualTo(key);
-    assertThat(msg.getParams()).containsOnly(params);
-  }
-
-  private String createLongString(int size) {
-    String result = "";
-    for (int i = 0; i < size; i++) {
-      result += "c";
-    }
-    return result;
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
deleted file mode 100644 (file)
index ac4e506..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.issue;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.issue.DefaultTransitions;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.IssueQuery;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.security.DefaultGroups;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.user.UserDto;
-import org.sonar.server.component.SnapshotTesting;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.component.db.SnapshotDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.issue.db.IssueDao;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.rule.RuleTesting;
-import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.QueryContext;
-import org.sonar.server.tester.ServerTester;
-import org.sonar.server.user.MockUserSession;
-import org.sonar.server.user.UserSession;
-
-import java.util.Date;
-import java.util.UUID;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class IssueServiceMediumTest {
-
-  @ClassRule
-  public static ServerTester tester = new ServerTester();
-
-  DbClient db;
-  IndexClient indexClient;
-  DbSession session;
-  IssueService service;
-  UserSession userSession;
-
-  RuleDto rule;
-  ComponentDto project;
-  ComponentDto resource;
-
-  @Before
-  public void setUp() throws Exception {
-    tester.clearDbAndIndexes();
-    db = tester.get(DbClient.class);
-    indexClient = tester.get(IndexClient.class);
-    session = db.openSession(false);
-    service = tester.get(IssueService.class);
-
-    rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(session, rule);
-
-    project = new ComponentDto()
-      .setKey("MyProject")
-      .setLongName("My Project")
-      .setQualifier(Qualifiers.PROJECT)
-      .setScope(Scopes.PROJECT);
-    tester.get(ComponentDao.class).insert(session, project);
-    tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(project));
-
-    resource = new ComponentDto()
-      .setProjectId(project.getId())
-      .setKey("MyComponent")
-      .setLongName("My Component");
-    tester.get(ComponentDao.class).insert(session, resource);
-    tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(resource));
-
-    // project can be seen by anyone
-    tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session);
-    db.issueAuthorizationDao().synchronizeAfter(session, new Date(0));
-
-    UserDto user = new UserDto().setLogin("gandalf").setName("Gandalf");
-    db.userDao().insert(session, user);
-    tester.get(PermissionFacade.class).insertUserPermission(project.getId(), user.getId(), UserRole.USER, session);
-
-    userSession = MockUserSession.create().setLogin(user.getLogin()).setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN)
-      .addProjectPermissions(UserRole.USER, project.key());
-
-    session.commit();
-  }
-
-  @After
-  public void after() {
-    session.close();
-  }
-
-  @Test
-  public void can_facet() throws Exception {
-    IssueDto issue1 = getIssue().setActionPlanKey("P1");
-    IssueDto issue2 = getIssue().setActionPlanKey("P2").setResolution("NONE");
-    tester.get(IssueDao.class).insert(session, issue1, issue2);
-    session.commit();
-
-    org.sonar.server.search.Result<Issue> result = service.search(IssueQuery.builder().build(), new QueryContext());
-    assertThat(result.getHits()).hasSize(2);
-    assertThat(result.getFacets()).isEmpty();
-
-    result = service.search(IssueQuery.builder().build(), new QueryContext().setFacet(true));
-    assertThat(result.getFacets().keySet()).hasSize(4);
-    assertThat(result.getFacetKeys("actionPlan")).hasSize(2);
-  }
-
-  @Test
-  public void do_transition() {
-    IssueDto issue = getIssue();
-    tester.get(IssueDao.class).insert(session, issue);
-    session.commit();
-
-    assertThat(db.issueDao().getByKey(session, issue.getKey())).isNotNull();
-
-    IssueTesting.assertIsEquivalent(issue, indexClient.get(IssueIndex.class).getByKey(issue.getKey()));
-
-    service.doTransition(issue.getKey(), DefaultTransitions.CONFIRM, userSession);
-    Issue issueDoc = indexClient.get(IssueIndex.class).getByKey(issue.getKey());
-    assertThat(issueDoc.status()).isEqualTo(Issue.STATUS_CONFIRMED);
-  }
-
-  private IssueDto getIssue() {
-    return new IssueDto()
-      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
-      .setIssueUpdateDate(DateUtils.parseDate("2014-12-04"))
-      .setRule(rule)
-      .setDebt(10L)
-      .setRootComponent(project)
-      .setComponent(resource)
-      .setStatus(Issue.STATUS_OPEN)
-      .setResolution(null)
-      .setSeverity(Severity.MAJOR)
-      .setKee(UUID.randomUUID().toString());
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceTest.java
deleted file mode 100644 (file)
index 4f555e5..0000000
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * 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.issue;
-
-import com.google.common.collect.Multiset;
-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;
-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.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.DefaultActionPlan;
-import org.sonar.core.issue.IssueNotifications;
-import org.sonar.core.issue.IssueUpdater;
-import org.sonar.core.issue.db.IssueDao;
-import org.sonar.core.issue.db.IssueStorage;
-import org.sonar.core.issue.workflow.IssueWorkflow;
-import org.sonar.core.issue.workflow.Transition;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.preview.PreviewCache;
-import org.sonar.core.resource.ResourceDao;
-import org.sonar.core.resource.ResourceDto;
-import org.sonar.core.resource.ResourceQuery;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.user.AuthorizationDao;
-import org.sonar.core.user.DefaultUser;
-import org.sonar.server.issue.actionplan.ActionPlanService;
-import org.sonar.server.user.UserSession;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-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
-  IssueDao issueDao;
-
-  @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;
-
-  @Before
-  public void before() {
-    when(userSession.isLoggedIn()).thenReturn(true);
-    when(userSession.userId()).thenReturn(10);
-    when(userSession.login()).thenReturn("arthur");
-
-    when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(true);
-    when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult);
-    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, issueDao,
-      authorizationDao, userFinder, mock(PreviewCache.class));
-  }
-
-  @Test
-  public void load_issue() {
-    IssueQueryResult result = issueService.loadIssue("ABCD");
-    assertThat(result).isEqualTo(issueQueryResult);
-  }
-
-  @Test
-  public void fail_to_load_issue() {
-    when(issueQueryResult.issues()).thenReturn(Collections.<Issue>emptyList());
-    when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult);
-
-    try {
-      issueService.loadIssue("ABCD");
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issue not found: ABCD");
-    }
-  }
-
-  @Test
-  public void list_status() {
-    issueService.listStatus();
-    verify(workflow).statusKeys();
-  }
-
-  @Test
-  public void list_transitions() {
-    List<Transition> transitions = newArrayList(transition);
-    when(workflow.outTransitions(issue)).thenReturn(transitions);
-
-    List<Transition> result = issueService.listTransitions("ABCD", userSession);
-    assertThat(result).hasSize(1);
-    assertThat(result.get(0)).isEqualTo(transition);
-  }
-
-  @Test
-  public void return_no_transition() {
-    when(issueQueryResult.first()).thenReturn(null);
-    when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) new DefaultIssue()));
-
-    assertThat(issueService.listTransitions("ABCD", userSession)).isEmpty();
-    verifyZeroInteractions(workflow);
-  }
-
-  @Test
-  public void do_transition() {
-    when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.doTransition("ABCD", transition.key(), userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(workflow).doTransition(eq(issue), eq(transition.key()), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-  }
-
-  @Test
-  public void not_do_transition() {
-    when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(false);
-
-    Issue result = issueService.doTransition("ABCD", transition.key(), userSession);
-    assertThat(result).isNotNull();
-    verify(workflow).doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class));
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void fail_do_transition_if_not_logged() {
-    when(userSession.isLoggedIn()).thenReturn(false);
-    try {
-      issueService.doTransition("ABCD", transition.key(), userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User is not logged in");
-    }
-    verifyZeroInteractions(authorizationDao);
-  }
-
-  @Test
-  public void assign() {
-    String assignee = "perceval";
-    User user = new DefaultUser();
-
-    when(userFinder.findByLogin(assignee)).thenReturn(user);
-    when(issueUpdater.assign(eq(issue), eq(user), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.assign("ABCD", assignee, userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(issueUpdater).assign(eq(issue), eq(user), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-  }
-
-  @Test
-  public void unassign() {
-    when(issueUpdater.assign(eq(issue), eq((User) null), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.assign("ABCD", null, userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(issueUpdater).assign(eq(issue), eq((User) null), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-    verify(userFinder, never()).findByLogin(anyString());
-  }
-
-  @Test
-  public void not_assign() {
-    String assignee = "perceval";
-    User user = new DefaultUser();
-
-    when(userFinder.findByLogin(assignee)).thenReturn(user);
-    when(issueUpdater.assign(eq(issue), eq(user), any(IssueChangeContext.class))).thenReturn(false);
-
-    Issue result = issueService.assign("ABCD", assignee, userSession);
-    assertThat(result).isNotNull();
-
-    verify(issueUpdater).assign(eq(issue), eq(user), any(IssueChangeContext.class));
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void fail_assign_if_assignee_not_found() {
-    String assignee = "perceval";
-
-    when(userFinder.findByLogin(assignee)).thenReturn(null);
-
-    try {
-      issueService.assign("ABCD", assignee, userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown user: perceval");
-    }
-
-    verifyZeroInteractions(issueUpdater);
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void plan() {
-    String actionPlanKey = "EFGH";
-
-    ActionPlan actionPlan = new DefaultActionPlan();
-
-    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(actionPlan);
-    when(issueUpdater.plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.plan("ABCD", actionPlanKey, userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(issueUpdater).plan(eq(issue), eq(actionPlan), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-  }
-
-  @Test
-  public void unplan() {
-    when(issueUpdater.plan(eq(issue), eq((ActionPlan) null), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.plan("ABCD", null, userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(issueUpdater).plan(eq(issue), eq((ActionPlan) null), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-    verify(actionPlanService, never()).findByKey(anyString(), any(UserSession.class));
-  }
-
-  @Test
-  public void not_plan() {
-    String actionPlanKey = "EFGH";
-
-    ActionPlan actionPlan = new DefaultActionPlan();
-
-    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(actionPlan);
-    when(issueUpdater.plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class))).thenReturn(false);
-
-    Issue result = issueService.plan("ABCD", actionPlanKey, userSession);
-    assertThat(result).isNotNull();
-    verify(issueUpdater).plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class));
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void fail_plan_if_action_plan_not_found() {
-    String actionPlanKey = "EFGH";
-
-    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(null);
-    try {
-      issueService.plan("ABCD", actionPlanKey, userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown action plan: EFGH");
-    }
-
-    verifyZeroInteractions(issueUpdater);
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void set_severity() {
-    String severity = "MINOR";
-    when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(true);
-
-    Issue result = issueService.setSeverity("ABCD", severity, userSession);
-    assertThat(result).isNotNull();
-
-    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
-    verify(issueUpdater).setManualSeverity(eq(issue), eq(severity), measureCaptor.capture());
-    verify(issueStorage).save(issue);
-
-    IssueChangeContext issueChangeContext = measureCaptor.getValue();
-    assertThat(issueChangeContext.login()).isEqualTo("arthur");
-    assertThat(issueChangeContext.date()).isNotNull();
-
-    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
-  }
-
-  @Test
-  public void not_set_severity() {
-    String severity = "MINOR";
-    when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(false);
-
-    Issue result = issueService.setSeverity("ABCD", severity, userSession);
-    assertThat(result).isNotNull();
-    verify(issueUpdater).setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class));
-    verifyZeroInteractions(issueStorage);
-    verifyZeroInteractions(issueNotifications);
-  }
-
-  @Test
-  public void create_manual_issue() {
-    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
-    when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
-    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
-    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
-
-    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "Fix it", null, null, 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(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");
-    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);
-
-    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "", null, null, 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(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER));
-  }
-
-  @Test
-  public void 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(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
-    when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false);
-
-    try {
-      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null, userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User does not have the required role");
-    }
-  }
-
-  @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);
-
-    RuleKey ruleKey = RuleKey.of("squid", "s100");
-    try {
-      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null, userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues can be created only on rules marked as 'manual': squid:s100");
-    }
-    verifyZeroInteractions(issueStorage);
-  }
-
-  @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);
-
-    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
-    when(ruleFinder.findByKey(ruleKey)).thenReturn(null);
-    try {
-      issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, null, null, null, userSession);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown rule: manual:manualRuleKey");
-    }
-    verifyZeroInteractions(issueStorage);
-  }
-
-  @Test
-  public void fail_create_manual_issue_if_component_not_found() {
-    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
-    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);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown component: org.sonar.Sample");
-    }
-    verifyZeroInteractions(issueStorage);
-  }
-
-  @Test
-  public void find_rules_by_component() throws Exception {
-    DbSession session = mock(DbSession.class);
-    String componentKey = "org.sonar.Sample";
-
-    Date date = new Date();
-    when(issueDao.findRulesByComponent(componentKey, date, session)).thenReturn(newArrayList(
-        RuleDto.createFor(RuleKey.of("repo", "rule")).setName("Rule name"),
-        RuleDto.createFor(RuleKey.of("repo", "rule")).setName("Rule name")
-    ));
-
-    RulesAggregation result = issueService.findRulesByComponent(componentKey, date, session);
-    assertThat(result.rules()).hasSize(1);
-  }
-
-  @Test
-  public void find_rules_by_severity() throws Exception {
-    DbSession session = mock(DbSession.class);
-    String componentKey = "org.sonar.Sample";
-
-    Date date = new Date();
-    when(issueDao.findSeveritiesByComponent(componentKey, date, session)).thenReturn(newArrayList("MAJOR", "MAJOR", "INFO"));
-
-    Multiset<String> result = issueService.findSeveritiesByComponent(componentKey, date, session);
-    assertThat(result.count("MAJOR")).isEqualTo(2);
-    assertThat(result.count("INFO")).isEqualTo(1);
-    assertThat(result.count("UNKNOWN")).isEqualTo(0);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/OldDefaultIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/OldDefaultIssueServiceTest.java
new file mode 100644 (file)
index 0000000..ceb1db1
--- /dev/null
@@ -0,0 +1,538 @@
+/*
+ * 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.issue;
+
+import com.google.common.collect.Multiset;
+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;
+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.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.DefaultActionPlan;
+import org.sonar.core.issue.IssueNotifications;
+import org.sonar.core.issue.IssueUpdater;
+import org.sonar.core.issue.db.IssueDao;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.issue.workflow.IssueWorkflow;
+import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.preview.PreviewCache;
+import org.sonar.core.resource.ResourceDao;
+import org.sonar.core.resource.ResourceDto;
+import org.sonar.core.resource.ResourceQuery;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.user.AuthorizationDao;
+import org.sonar.core.user.DefaultUser;
+import org.sonar.server.issue.actionplan.ActionPlanService;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.user.UserSession;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class OldDefaultIssueServiceTest {
+
+  @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
+  IssueDao issueDao;
+
+  @Mock
+  AuthorizationDao authorizationDao;
+
+  @Mock
+  UserFinder userFinder;
+
+  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");
+
+  OldIssueService issueService;
+
+  @Before
+  public void before() {
+    userSession = MockUserSession.set()
+      .setLogin("arthur")
+      .setUserId(10)
+      .setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN)
+      .addProjectPermissions(UserRole.USER, project.getKey())
+      .addProjectPermissions(UserRole.ISSUE_ADMIN, project.getKey());
+
+    when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(true);
+    when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult);
+    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 OldIssueService(finder, workflow, issueStorage, issueUpdater, issueNotifications, actionPlanService, ruleFinder, resourceDao, issueDao,
+      authorizationDao, userFinder, mock(PreviewCache.class));
+  }
+
+  @Test
+  public void load_issue() {
+    IssueQueryResult result = issueService.loadIssue("ABCD");
+    assertThat(result).isEqualTo(issueQueryResult);
+  }
+
+  @Test
+  public void fail_to_load_issue() {
+    when(issueQueryResult.issues()).thenReturn(Collections.<Issue>emptyList());
+    when(finder.find(any(IssueQuery.class))).thenReturn(issueQueryResult);
+
+    try {
+      issueService.loadIssue("ABCD");
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issue not found: ABCD");
+    }
+  }
+
+  @Test
+  public void list_status() {
+    issueService.listStatus();
+    verify(workflow).statusKeys();
+  }
+
+  @Test
+  public void list_transitions() {
+    List<Transition> transitions = newArrayList(transition);
+    when(workflow.outTransitions(issue)).thenReturn(transitions);
+
+    List<Transition> result = issueService.listTransitions("ABCD");
+    assertThat(result).hasSize(1);
+    assertThat(result.get(0)).isEqualTo(transition);
+  }
+
+  @Test
+  public void return_no_transition() {
+    when(issueQueryResult.first()).thenReturn(null);
+    when(issueQueryResult.issues()).thenReturn(newArrayList((Issue) new DefaultIssue()));
+
+    assertThat(issueService.listTransitions("ABCD")).isEmpty();
+    verifyZeroInteractions(workflow);
+  }
+
+  @Test
+  public void do_transition() {
+    when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.doTransition("ABCD", transition.key());
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(workflow).doTransition(eq(issue), eq(transition.key()), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+  }
+
+  @Test
+  public void not_do_transition() {
+    when(workflow.doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class))).thenReturn(false);
+
+    Issue result = issueService.doTransition("ABCD", transition.key());
+    assertThat(result).isNotNull();
+    verify(workflow).doTransition(eq(issue), eq(transition.key()), any(IssueChangeContext.class));
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void fail_do_transition_if_not_logged() {
+    MockUserSession.set();
+    try {
+      issueService.doTransition("ABCD", transition.key());
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User is not logged in");
+    }
+    verifyZeroInteractions(authorizationDao);
+  }
+
+  @Test
+  public void assign() {
+    String assignee = "perceval";
+    User user = new DefaultUser();
+
+    when(userFinder.findByLogin(assignee)).thenReturn(user);
+    when(issueUpdater.assign(eq(issue), eq(user), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.assign("ABCD", assignee);
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(issueUpdater).assign(eq(issue), eq(user), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+  }
+
+  @Test
+  public void unassign() {
+    when(issueUpdater.assign(eq(issue), eq((User) null), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.assign("ABCD", null);
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(issueUpdater).assign(eq(issue), eq((User) null), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+    verify(userFinder, never()).findByLogin(anyString());
+  }
+
+  @Test
+  public void not_assign() {
+    String assignee = "perceval";
+    User user = new DefaultUser();
+
+    when(userFinder.findByLogin(assignee)).thenReturn(user);
+    when(issueUpdater.assign(eq(issue), eq(user), any(IssueChangeContext.class))).thenReturn(false);
+
+    Issue result = issueService.assign("ABCD", assignee);
+    assertThat(result).isNotNull();
+
+    verify(issueUpdater).assign(eq(issue), eq(user), any(IssueChangeContext.class));
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void fail_assign_if_assignee_not_found() {
+    String assignee = "perceval";
+
+    when(userFinder.findByLogin(assignee)).thenReturn(null);
+
+    try {
+      issueService.assign("ABCD", assignee);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown user: perceval");
+    }
+
+    verifyZeroInteractions(issueUpdater);
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void plan() {
+    String actionPlanKey = "EFGH";
+
+    ActionPlan actionPlan = new DefaultActionPlan();
+
+    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(actionPlan);
+    when(issueUpdater.plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.plan("ABCD", actionPlanKey);
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(issueUpdater).plan(eq(issue), eq(actionPlan), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+  }
+
+  @Test
+  public void unplan() {
+    when(issueUpdater.plan(eq(issue), eq((ActionPlan) null), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.plan("ABCD", null);
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(issueUpdater).plan(eq(issue), eq((ActionPlan) null), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+    verify(actionPlanService, never()).findByKey(anyString(), any(UserSession.class));
+  }
+
+  @Test
+  public void not_plan() {
+    String actionPlanKey = "EFGH";
+
+    ActionPlan actionPlan = new DefaultActionPlan();
+
+    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(actionPlan);
+    when(issueUpdater.plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class))).thenReturn(false);
+
+    Issue result = issueService.plan("ABCD", actionPlanKey);
+    assertThat(result).isNotNull();
+    verify(issueUpdater).plan(eq(issue), eq(actionPlan), any(IssueChangeContext.class));
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void fail_plan_if_action_plan_not_found() {
+    String actionPlanKey = "EFGH";
+
+    when(actionPlanService.findByKey(actionPlanKey, userSession)).thenReturn(null);
+    try {
+      issueService.plan("ABCD", actionPlanKey);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown action plan: EFGH");
+    }
+
+    verifyZeroInteractions(issueUpdater);
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void set_severity() {
+    String severity = "MINOR";
+    when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(true);
+
+    Issue result = issueService.setSeverity("ABCD", severity);
+    assertThat(result).isNotNull();
+
+    ArgumentCaptor<IssueChangeContext> measureCaptor = ArgumentCaptor.forClass(IssueChangeContext.class);
+    verify(issueUpdater).setManualSeverity(eq(issue), eq(severity), measureCaptor.capture());
+    verify(issueStorage).save(issue);
+
+    IssueChangeContext issueChangeContext = measureCaptor.getValue();
+    assertThat(issueChangeContext.login()).isEqualTo("arthur");
+    assertThat(issueChangeContext.date()).isNotNull();
+
+    verify(issueNotifications).sendChanges(eq(issue), eq(issueChangeContext), eq(issueQueryResult));
+  }
+
+  @Test
+  public void not_set_severity() {
+    String severity = "MINOR";
+    when(issueUpdater.setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class))).thenReturn(false);
+
+    Issue result = issueService.setSeverity("ABCD", severity);
+    assertThat(result).isNotNull();
+    verify(issueUpdater).setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class));
+    verifyZeroInteractions(issueStorage);
+    verifyZeroInteractions(issueNotifications);
+  }
+
+  @Test
+  public void create_manual_issue() {
+    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    when(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
+    when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(resource);
+    when(resourceDao.getRootProjectByComponentKey(anyString())).thenReturn(project);
+
+    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "Fix it", null, null);
+    assertThat(result).isNotNull();
+    assertThat(result.message()).isEqualTo("Fix it");
+    assertThat(result.creationDate()).isNotNull();
+    assertThat(result.updateDate()).isNotNull();
+
+    verify(issueStorage).save(any(DefaultIssue.class));
+    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");
+    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);
+
+    Issue result = issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, "", null, null);
+    assertThat(result).isNotNull();
+    assertThat(result.message()).isEqualTo("Manual Rule");
+    assertThat(result.creationDate()).isNotNull();
+    assertThat(result.updateDate()).isNotNull();
+
+    verify(issueStorage).save(any(DefaultIssue.class));
+    verify(authorizationDao).isAuthorizedComponentKey(anyString(), anyInt(), eq(UserRole.USER));
+  }
+
+  @Test
+  public void 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(ruleFinder.findByKey(ruleKey)).thenReturn(Rule.create("manual", "manualRuleKey"));
+    when(authorizationDao.isAuthorizedComponentKey(anyString(), eq(10), anyString())).thenReturn(false);
+
+    try {
+      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User does not have the required role");
+    }
+  }
+
+  @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);
+
+    RuleKey ruleKey = RuleKey.of("squid", "s100");
+    try {
+      issueService.createManualIssue("org.sonar.Sample", ruleKey, null, null, null, null);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues can be created only on rules marked as 'manual': squid:s100");
+    }
+    verifyZeroInteractions(issueStorage);
+  }
+
+  @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);
+
+    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    when(ruleFinder.findByKey(ruleKey)).thenReturn(null);
+    try {
+      issueService.createManualIssue("org.sonar.Sample", RuleKey.of("manual", "manualRuleKey"), null, null, null, null);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown rule: manual:manualRuleKey");
+    }
+    verifyZeroInteractions(issueStorage);
+  }
+
+  @Test
+  public void fail_create_manual_issue_if_component_not_found() {
+    RuleKey ruleKey = RuleKey.of("manual", "manualRuleKey");
+    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);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown component: org.sonar.Sample");
+    }
+    verifyZeroInteractions(issueStorage);
+  }
+
+  @Test
+  public void find_rules_by_component() throws Exception {
+    DbSession session = mock(DbSession.class);
+    String componentKey = "org.sonar.Sample";
+
+    Date date = new Date();
+    when(issueDao.findRulesByComponent(componentKey, date, session)).thenReturn(newArrayList(
+        RuleDto.createFor(RuleKey.of("repo", "rule")).setName("Rule name"),
+        RuleDto.createFor(RuleKey.of("repo", "rule")).setName("Rule name")
+    ));
+
+    RulesAggregation result = issueService.findRulesByComponent(componentKey, date, session);
+    assertThat(result.rules()).hasSize(1);
+  }
+
+  @Test
+  public void find_rules_by_severity() throws Exception {
+    DbSession session = mock(DbSession.class);
+    String componentKey = "org.sonar.Sample";
+
+    Date date = new Date();
+    when(issueDao.findSeveritiesByComponent(componentKey, date, session)).thenReturn(newArrayList("MAJOR", "MAJOR", "INFO"));
+
+    Multiset<String> result = issueService.findSeveritiesByComponent(componentKey, date, session);
+    assertThat(result.count("MAJOR")).isEqualTo(2);
+    assertThat(result.count("INFO")).isEqualTo(1);
+    assertThat(result.count("UNKNOWN")).isEqualTo(0);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyDefaultIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyDefaultIssueServiceTest.java
new file mode 100644 (file)
index 0000000..27d10b6
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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.issue;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.sonar.api.issue.IssueFinder;
+import org.sonar.api.issue.IssueQuery;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+import static java.util.Arrays.asList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.*;
+
+public class PublicRubyDefaultIssueServiceTest {
+
+  IssueFinder finder = mock(IssueFinder.class);
+  PublicRubyIssueService facade = new PublicRubyIssueService(finder);
+
+  @Test
+  public void find_by_issue_keys() throws Exception {
+    facade.find("ABCDE");
+    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
+      @Override
+      public boolean matches(Object o) {
+        IssueQuery query = (IssueQuery) o;
+        return query.issueKeys().contains("ABCDE") && UserRole.USER.equals(query.requiredRole());
+      }
+    }));
+  }
+
+  @Test
+  public void find_by_params() throws Exception {
+    facade.find(ImmutableMap.<String, Object>of("issues", Lists.newArrayList("ABCDE")));
+    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
+      @Override
+      public boolean matches(Object o) {
+        IssueQuery query = (IssueQuery) o;
+        return query.issueKeys().contains("ABCDE") && UserRole.USER.equals(query.requiredRole());
+      }
+    }));
+  }
+
+  @Test
+  public void create_query_from_parameters() {
+    Map<String, Object> map = newHashMap();
+    map.put("issues", newArrayList("ABCDE1234"));
+    map.put("severities", newArrayList("MAJOR", "MINOR"));
+    map.put("statuses", newArrayList("CLOSED"));
+    map.put("resolutions", newArrayList("FALSE-POSITIVE"));
+    map.put("resolved", true);
+    map.put("components", newArrayList("org.apache"));
+    map.put("componentRoots", newArrayList("org.sonar"));
+    map.put("reporters", newArrayList("marilyn"));
+    map.put("assignees", newArrayList("joanna"));
+    map.put("languages", newArrayList("xoo"));
+    map.put("assigned", true);
+    map.put("planned", true);
+    map.put("hideRules", true);
+    map.put("createdAfter", "2013-04-16T09:08:24+0200");
+    map.put("createdBefore", "2013-04-17T09:08:24+0200");
+    map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
+    map.put("pageSize", 10l);
+    map.put("pageIndex", 50);
+    map.put("sort", "CREATION_DATE");
+    map.put("asc", true);
+
+    IssueQuery query = new PublicRubyIssueService(finder).toQuery(map);
+    assertThat(query.issueKeys()).containsOnly("ABCDE1234");
+    assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
+    assertThat(query.statuses()).containsOnly("CLOSED");
+    assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
+    assertThat(query.resolved()).isTrue();
+    assertThat(query.components()).containsOnly("org.apache");
+    assertThat(query.componentRoots()).containsOnly("org.sonar");
+    assertThat(query.reporters()).containsOnly("marilyn");
+    assertThat(query.assignees()).containsOnly("joanna");
+    assertThat(query.languages()).containsOnly("xoo");
+    assertThat(query.assigned()).isTrue();
+    assertThat(query.planned()).isTrue();
+    assertThat(query.hideRules()).isTrue();
+    assertThat(query.rules()).hasSize(2);
+    assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
+    assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
+    assertThat(query.pageSize()).isEqualTo(10);
+    assertThat(query.pageIndex()).isEqualTo(50);
+    assertThat(query.sort()).isEqualTo(IssueQuery.SORT_BY_CREATION_DATE);
+    assertThat(query.asc()).isTrue();
+  }
+
+  @Test
+  public void parse_list_of_rules() {
+    assertThat(PublicRubyIssueService.toRules(null)).isNull();
+    assertThat(PublicRubyIssueService.toRules("")).isEmpty();
+    assertThat(PublicRubyIssueService.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
+    assertThat(PublicRubyIssueService.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+    assertThat(PublicRubyIssueService.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+  }
+
+  @Test
+  public void start() throws Exception {
+    facade.start();
+    // nothing is done
+    verifyZeroInteractions(finder);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/PublicRubyIssueServiceTest.java
deleted file mode 100644 (file)
index 95bc3a3..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.issue;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import org.junit.Test;
-import org.mockito.ArgumentMatcher;
-import org.sonar.api.issue.IssueFinder;
-import org.sonar.api.issue.IssueQuery;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.web.UserRole;
-
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-import static java.util.Arrays.asList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.*;
-
-public class PublicRubyIssueServiceTest {
-
-  IssueFinder finder = mock(IssueFinder.class);
-  PublicRubyIssueService facade = new PublicRubyIssueService(finder);
-
-  @Test
-  public void find_by_issue_keys() throws Exception {
-    facade.find("ABCDE");
-    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
-      @Override
-      public boolean matches(Object o) {
-        IssueQuery query = (IssueQuery) o;
-        return query.issueKeys().contains("ABCDE") && UserRole.USER.equals(query.requiredRole());
-      }
-    }));
-  }
-
-  @Test
-  public void find_by_params() throws Exception {
-    facade.find(ImmutableMap.<String, Object>of("issues", Lists.newArrayList("ABCDE")));
-    verify(finder).find(argThat(new ArgumentMatcher<IssueQuery>() {
-      @Override
-      public boolean matches(Object o) {
-        IssueQuery query = (IssueQuery) o;
-        return query.issueKeys().contains("ABCDE") && UserRole.USER.equals(query.requiredRole());
-      }
-    }));
-  }
-
-  @Test
-  public void create_query_from_parameters() {
-    Map<String, Object> map = newHashMap();
-    map.put("issues", newArrayList("ABCDE1234"));
-    map.put("severities", newArrayList("MAJOR", "MINOR"));
-    map.put("statuses", newArrayList("CLOSED"));
-    map.put("resolutions", newArrayList("FALSE-POSITIVE"));
-    map.put("resolved", true);
-    map.put("components", newArrayList("org.apache"));
-    map.put("componentRoots", newArrayList("org.sonar"));
-    map.put("reporters", newArrayList("marilyn"));
-    map.put("assignees", newArrayList("joanna"));
-    map.put("languages", newArrayList("xoo"));
-    map.put("assigned", true);
-    map.put("planned", true);
-    map.put("hideRules", true);
-    map.put("createdAfter", "2013-04-16T09:08:24+0200");
-    map.put("createdBefore", "2013-04-17T09:08:24+0200");
-    map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
-    map.put("pageSize", 10l);
-    map.put("pageIndex", 50);
-    map.put("sort", "CREATION_DATE");
-    map.put("asc", true);
-
-    IssueQuery query = new PublicRubyIssueService(finder).toQuery(map);
-    assertThat(query.issueKeys()).containsOnly("ABCDE1234");
-    assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
-    assertThat(query.statuses()).containsOnly("CLOSED");
-    assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
-    assertThat(query.resolved()).isTrue();
-    assertThat(query.components()).containsOnly("org.apache");
-    assertThat(query.componentRoots()).containsOnly("org.sonar");
-    assertThat(query.reporters()).containsOnly("marilyn");
-    assertThat(query.assignees()).containsOnly("joanna");
-    assertThat(query.languages()).containsOnly("xoo");
-    assertThat(query.assigned()).isTrue();
-    assertThat(query.planned()).isTrue();
-    assertThat(query.hideRules()).isTrue();
-    assertThat(query.rules()).hasSize(2);
-    assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
-    assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
-    assertThat(query.pageSize()).isEqualTo(10);
-    assertThat(query.pageIndex()).isEqualTo(50);
-    assertThat(query.sort()).isEqualTo(IssueQuery.SORT_BY_CREATION_DATE);
-    assertThat(query.asc()).isTrue();
-  }
-
-  @Test
-  public void parse_list_of_rules() {
-    assertThat(PublicRubyIssueService.toRules(null)).isNull();
-    assertThat(PublicRubyIssueService.toRules("")).isEmpty();
-    assertThat(PublicRubyIssueService.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
-    assertThat(PublicRubyIssueService.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
-    assertThat(PublicRubyIssueService.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
-  }
-
-  @Test
-  public void start() throws Exception {
-    facade.start();
-    // nothing is done
-    verifyZeroInteractions(finder);
-  }
-}
index b2a231eb6943aeff0e59a7455acdf6c82116ee15..7cae13f4c4d6f6f7fd0e2b9eb29561337b76de33 100644 (file)
@@ -50,7 +50,8 @@ import static org.fest.assertions.Assertions.assertThat;
 public class IssueBackendMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.issues.use_es_backend", "true");
 
   DbClient dbClient;
   IndexClient indexClient;
index 44d4efb6b31cf8dc010caaf028b3c5173aa69d1d..5034e196290c733c7c0e716573b72cb1b58f3906 100644 (file)
@@ -23,15 +23,20 @@ import com.google.common.collect.ImmutableMap;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.api.utils.System2;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.server.rule.RuleTesting;
 
 import java.util.Date;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 public class IssueDaoTest extends AbstractDaoTestCase {
 
@@ -51,9 +56,42 @@ public class IssueDaoTest extends AbstractDaoTestCase {
     this.session.close();
   }
 
+  @Test
+  public void get_by_key() {
+    setupData("shared", "get_by_key");
+
+    IssueDto issue = dao.getByKey(session, "ABCDE");
+    assertThat(issue.getKee()).isEqualTo("ABCDE");
+    assertThat(issue.getId()).isEqualTo(100L);
+    assertThat(issue.getComponentId()).isEqualTo(401);
+    assertThat(issue.getRootComponentId()).isEqualTo(399);
+    assertThat(issue.getRuleId()).isEqualTo(500);
+    assertThat(issue.getSeverity()).isEqualTo("BLOCKER");
+    assertThat(issue.isManualSeverity()).isFalse();
+    assertThat(issue.getMessage()).isNull();
+    assertThat(issue.getLine()).isEqualTo(200);
+    assertThat(issue.getEffortToFix()).isEqualTo(4.2);
+    assertThat(issue.getStatus()).isEqualTo("OPEN");
+    assertThat(issue.getResolution()).isEqualTo("FIXED");
+    assertThat(issue.getChecksum()).isEqualTo("XXX");
+    assertThat(issue.getAuthorLogin()).isEqualTo("karadoc");
+    assertThat(issue.getReporter()).isEqualTo("arthur");
+    assertThat(issue.getAssignee()).isEqualTo("perceval");
+    assertThat(issue.getIssueAttributes()).isEqualTo("JIRA=FOO-1234");
+    assertThat(issue.getIssueCreationDate()).isNotNull();
+    assertThat(issue.getIssueUpdateDate()).isNotNull();
+    assertThat(issue.getIssueCloseDate()).isNotNull();
+    assertThat(issue.getCreatedAt()).isNotNull();
+    assertThat(issue.getUpdatedAt()).isNotNull();
+    assertThat(issue.getRuleRepo()).isEqualTo("squid");
+    assertThat(issue.getRule()).isEqualTo("AvoidCycle");
+    assertThat(issue.getComponentKey()).isEqualTo("Action.java");
+    assertThat(issue.getRootComponentKey()).isEqualTo("struts");
+  }
+
   @Test
   public void find_after_dates() throws Exception {
-    setupData("shared", "should_select_all");
+    setupData("shared", "some_issues");
 
     Date t0 = new Date(0);
     assertThat(dao.findAfterDate(session, t0)).hasSize(3);
@@ -68,4 +106,76 @@ public class IssueDaoTest extends AbstractDaoTestCase {
 
     assertThat(dao.findAfterDate(session, DateUtils.parseDate("2014-01-01"), ImmutableMap.of("project", "struts"))).hasSize(1);
   }
+
+  @Test
+  public void insert() throws Exception {
+    when(system2.now()).thenReturn(DateUtils.parseDate("2013-05-22").getTime());
+
+    IssueDto dto = new IssueDto();
+    dto.setComponent(new ComponentDto().setKey("struts:Action").setId(123L));
+    dto.setRootComponent(new ComponentDto().setKey("struts").setId(100L));
+    dto.setRule(RuleTesting.newDto(RuleKey.of("squid", "S001")).setId(200));
+    dto.setKee("ABCDE");
+    dto.setLine(500);
+    dto.setEffortToFix(3.14);
+    dto.setDebt(10L);
+    dto.setResolution("FIXED");
+    dto.setStatus("RESOLVED");
+    dto.setSeverity("BLOCKER");
+    dto.setReporter("emmerik");
+    dto.setAuthorLogin("morgan");
+    dto.setAssignee("karadoc");
+    dto.setActionPlanKey("current_sprint");
+    dto.setIssueAttributes("JIRA=FOO-1234");
+    dto.setChecksum("123456789");
+    dto.setMessage("the message");
+
+    dto.setIssueCreationDate(DateUtils.parseDate("2013-05-18"));
+    dto.setIssueUpdateDate(DateUtils.parseDate("2013-05-19"));
+    dto.setIssueCloseDate(DateUtils.parseDate("2013-05-20"));
+    dto.setCreatedAt(DateUtils.parseDate("2013-05-21"));
+    dto.setUpdatedAt(DateUtils.parseDate("2013-05-22"));
+
+    dao.insert(session, dto);
+    session.commit();
+
+    checkTables("insert", new String[]{"id"}, "issues");
+  }
+
+  @Test
+  public void update() throws Exception {
+    when(system2.now()).thenReturn(DateUtils.parseDate("2013-05-22").getTime());
+
+    setupData("update");
+
+    IssueDto dto = new IssueDto();
+    dto.setComponent(new ComponentDto().setKey("struts:Action").setId(123L));
+    dto.setRootComponent(new ComponentDto().setKey("struts").setId(101L));
+    dto.setRule(RuleTesting.newDto(RuleKey.of("squid", "S001")).setId(200));
+    dto.setKee("ABCDE");
+    dto.setLine(500);
+    dto.setEffortToFix(3.14);
+    dto.setDebt(10L);
+    dto.setResolution("FIXED");
+    dto.setStatus("RESOLVED");
+    dto.setSeverity("BLOCKER");
+    dto.setReporter("emmerik");
+    dto.setAuthorLogin("morgan");
+    dto.setAssignee("karadoc");
+    dto.setActionPlanKey("current_sprint");
+    dto.setIssueAttributes("JIRA=FOO-1234");
+    dto.setChecksum("123456789");
+    dto.setMessage("the message");
+
+    dto.setIssueCreationDate(DateUtils.parseDate("2013-05-18"));
+    dto.setIssueUpdateDate(DateUtils.parseDate("2013-05-19"));
+    dto.setIssueCloseDate(DateUtils.parseDate("2013-05-20"));
+    dto.setCreatedAt(DateUtils.parseDate("2013-05-21"));
+    dto.setUpdatedAt(DateUtils.parseDate("2013-05-22"));
+
+    dao.update(session, dto);
+    session.commit();
+
+    checkTables("update", new String[]{"id"}, "issues");
+  }
 }
index 0895eedaa5be7ed19d48ec43c45ea7d5f5a1ce6b..6d9942bbbc71eb6952e868ad0c19dd5a7b30dc46 100644 (file)
@@ -42,7 +42,8 @@ import static org.fest.assertions.Assertions.assertThat;
 public class IssueAuthorizationIndexMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.issues.use_es_backend", "true");
 
   DbClient db;
   DbSession session;
index 0fdc78077e7b2c06a9c267c0aba674f13c76dd0e..fb95a3f198c09b23e5ed26ff8645e19c0f951370 100644 (file)
@@ -54,7 +54,8 @@ import static org.fest.assertions.Assertions.assertThat;
 public class IssueIndexMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.issues.use_es_backend", "true");
 
   DbClient db;
   DbSession session;
index bb8d97e87b00b7916d8be685c79b6a37eccce144..0970c2223321cc5f231d7785a3bbe49f7d0f133e 100644 (file)
@@ -37,12 +37,10 @@ import org.sonar.core.issue.workflow.Transition;
 import org.sonar.server.issue.ActionService;
 import org.sonar.server.issue.IssueService;
 import org.sonar.server.user.MockUserSession;
-import org.sonar.server.user.UserSession;
 
 import java.io.StringWriter;
 
 import static com.google.common.collect.Lists.newArrayList;
-import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -77,8 +75,7 @@ public class IssueActionsWriterTest {
       "{\"actions\": " +
         "[" +
         "\"comment\", \"assign\", \"assign_to_me\", \"plan\", \"set_severity\"\n" +
-        "]}"
-    );
+        "]}");
   }
 
   @Test
@@ -98,8 +95,7 @@ public class IssueActionsWriterTest {
       "{\"actions\": " +
         "[" +
         "\"comment\", \"assign\", \"assign_to_me\", \"plan\", \"link-to-jira\"\n" +
-        "]}"
-    );
+        "]}");
   }
 
   @Test
@@ -117,8 +113,7 @@ public class IssueActionsWriterTest {
       "{\"actions\": " +
         "[" +
         "\"comment\"" +
-        "]}"
-    );
+        "]}");
   }
 
   @Test
@@ -132,8 +127,7 @@ public class IssueActionsWriterTest {
     MockUserSession.set();
 
     testActions(issue,
-      "{\"actions\": []}"
-    );
+      "{\"actions\": []}");
   }
 
   @Test
@@ -151,8 +145,7 @@ public class IssueActionsWriterTest {
       "{\"actions\": " +
         "[" +
         "\"comment\", \"assign\", \"plan\"\n" +
-        "]}"
-    );
+        "]}");
   }
 
   @Test
@@ -163,14 +156,13 @@ public class IssueActionsWriterTest {
       .setProjectKey("sample")
       .setRuleKey(RuleKey.of("squid", "AvoidCycle"));
 
-    when(issueService.listTransitions(eq(issue), any(UserSession.class))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
+    when(issueService.listTransitions(eq(issue))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
     MockUserSession.set().setLogin("john");
 
     testTransitions(issue,
       "{\"transitions\": [\n" +
         "        \"reopen\"\n" +
-        "      ]}"
-    );
+        "      ]}");
   }
 
   @Test
@@ -184,8 +176,7 @@ public class IssueActionsWriterTest {
     MockUserSession.set().setLogin("john");
 
     testTransitions(issue,
-      "{\"transitions\": []}"
-    );
+      "{\"transitions\": []}");
   }
 
   private void testActions(Issue issue, String expected) throws JSONException {
index 95c8ff3da4d2a356fc3c27634b7290a1188d2331..9325f7745c350eac3b7a6c330a2879cde470d2eb 100644 (file)
@@ -52,7 +52,6 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.issue.ActionService;
 import org.sonar.server.issue.IssueService;
 import org.sonar.server.user.MockUserSession;
-import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.WsTester;
 
 import java.util.*;
@@ -243,7 +242,7 @@ public class IssueSearchActionTest {
     issues.add(issue);
 
     MockUserSession.set().setLogin("john");
-    when(issueService.listTransitions(eq(issue), any(UserSession.class))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
+    when(issueService.listTransitions(eq(issue))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
 
     result.addActionPlans(newArrayList((ActionPlan) new DefaultActionPlan().setKey("AP-ABCD").setName("1.0")));
 
index 2871fa8cd7cc77574d77f8a212aba915bd34ffcd..66a73144b72ddacff668be8de6616e9da1faf394 100644 (file)
@@ -53,7 +53,6 @@ import org.sonar.server.issue.IssueChangelog;
 import org.sonar.server.issue.IssueChangelogService;
 import org.sonar.server.issue.IssueService;
 import org.sonar.server.user.MockUserSession;
-import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.WsTester;
 
 import java.util.ArrayList;
@@ -431,7 +430,7 @@ public class IssueShowActionTest {
       .setResolution("FIXED");
     issues.add(issue);
 
-    when(issueService.listTransitions(eq(issue), any(UserSession.class))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
+    when(issueService.listTransitions(eq(issue))).thenReturn(newArrayList(Transition.create("reopen", "RESOLVED", "REOPEN")));
 
     MockUserSession.set().setLogin("john");
     WsTester.TestRequest request = tester.newGetRequest("api/issues", "show").setParam("key", issue.key());
index d86c17e1ff80b772b959e0573c7ac2d6332e96d2..6cfd273bce40f91e655b0a000d620d937c6d4499 100644 (file)
@@ -97,6 +97,7 @@ public class RuleTesting {
 
   public static RuleDto newManualRule(String manualKey){
     return new RuleDto().setRuleKey(manualKey)
+      .setName("Name " + manualKey)
       .setRepositoryKey("manual")
       .setDescription("Description " + manualKey)
       .setStatus(RuleStatus.READY);
index 8048b57beca0f1ef123c36b4b760dc9d085a08c3..1e31323634384c4c5f01492ef14c1927c39c5a39 100644 (file)
@@ -23,6 +23,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
+import org.sonar.api.config.Settings;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.DbClient;
@@ -36,7 +37,8 @@ import static org.fest.assertions.Assertions.assertThat;
 public class IndexSynchronizerMediumTest {
 
   @ClassRule
-  public static ServerTester tester = new ServerTester();
+  public static ServerTester tester = new ServerTester()
+    .setProperty("sonar.issues.use_es_backend", "true");
 
   IndexSynchronizer synchronizer;
   DbClient dbClient;
@@ -50,7 +52,7 @@ public class IndexSynchronizerMediumTest {
     indexClient = tester.get(IndexClient.class);
     platform = tester.get(Platform.class);
     dbSession = dbClient.openSession(false);
-    synchronizer = new IndexSynchronizer(dbClient, indexClient);
+    synchronizer = new IndexSynchronizer(dbClient, indexClient, tester.get(Settings.class));
     tester.clearDbAndIndexes();
   }
 
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/get_by_key.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/get_by_key.xml
new file mode 100644 (file)
index 0000000..9a5cc94
--- /dev/null
@@ -0,0 +1,28 @@
+<dataset>
+
+  <issues
+      id="100"
+      kee="ABCDE"
+      component_id="401"
+      root_component_id="399"
+      rule_id="500"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="[null]"
+      line="200"
+      effort_to_fix="4.2"
+      status="OPEN"
+      resolution="FIXED"
+      checksum="XXX"
+      reporter="arthur"
+      assignee="perceval"
+      author_login="karadoc"
+      issue_attributes="JIRA=FOO-1234"
+      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="2013-04-16"
+      />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/insert-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/insert-result.xml
new file mode 100644 (file)
index 0000000..3d73638
--- /dev/null
@@ -0,0 +1,28 @@
+<dataset>
+  <issues
+      id="100"
+      kee="ABCDE"
+      component_id="123"
+      root_component_id="100"
+      rule_id="200"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="the message"
+      line="500"
+      effort_to_fix="3.14"
+      technical_debt="10"
+      status="RESOLVED"
+      resolution="FIXED"
+      checksum="123456789"
+      reporter="emmerik"
+      author_login="morgan"
+      assignee="karadoc"
+      issue_attributes="JIRA=FOO-1234"
+      issue_creation_date="2013-05-18"
+      issue_update_date="2013-05-19"
+      issue_close_date="2013-05-20"
+      created_at="2013-05-21"
+      updated_at="2013-05-22"
+      action_plan_key="current_sprint"
+      />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/should_select_all.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/should_select_all.xml
deleted file mode 100644 (file)
index 96ada68..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<dataset>
-
-  <!-- rule 500 -->
-  <issues
-          id="100"
-          kee="ABCDE-1"
-          component_id="401"
-          root_component_id="399"
-          rule_id="500"
-          severity="BLOCKER"
-          manual_severity="[false]"
-          message="[null]"
-          line="200"
-          effort_to_fix="4.2"
-          status="OPEN"
-          resolution="FIXED"
-          checksum="XXX"
-          reporter="arthur"
-          assignee="perceval"
-          author_login="[null]"
-          issue_attributes="JIRA=FOO-1234"
-          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="2013-04-16"
-          />
-
-  <issues
-          id="101"
-          kee="ABCDE-2"
-          component_id="401"
-          root_component_id="399"
-          rule_id="500"
-          severity="BLOCKER"
-          manual_severity="[false]"
-          message="[null]"
-          line="200"
-          effort_to_fix="4.2"
-          status="OPEN"
-          resolution="FIXED"
-          checksum="XXX"
-          reporter="arthur"
-          assignee="perceval"
-          author_login="[null]"
-          issue_attributes="JIRA=FOO-1234"
-          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="2013-04-16"
-          />
-
-
-  <!-- rule 501 -->
-  <issues
-          id="102"
-          kee="ABCDE-3"
-          component_id="401"
-          root_component_id="399"
-          rule_id="501"
-          severity="BLOCKER"
-          manual_severity="[false]"
-          message="[null]"
-          line="200"
-          effort_to_fix="4.2"
-          status="OPEN"
-          resolution="FIXED"
-          checksum="XXX"
-          reporter="arthur"
-          assignee="perceval"
-          author_login="[null]"
-          issue_attributes="JIRA=FOO-1234"
-          issue_creation_date="2014-04-16"
-          issue_update_date="2014-04-16"
-          issue_close_date="2014-04-16"
-          created_at="2014-04-16"
-          updated_at="2014-04-16"
-          />
-</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/some_issues.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/some_issues.xml
new file mode 100644 (file)
index 0000000..96ada68
--- /dev/null
@@ -0,0 +1,80 @@
+<dataset>
+
+  <!-- rule 500 -->
+  <issues
+          id="100"
+          kee="ABCDE-1"
+          component_id="401"
+          root_component_id="399"
+          rule_id="500"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          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="2013-04-16"
+          />
+
+  <issues
+          id="101"
+          kee="ABCDE-2"
+          component_id="401"
+          root_component_id="399"
+          rule_id="500"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          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="2013-04-16"
+          />
+
+
+  <!-- rule 501 -->
+  <issues
+          id="102"
+          kee="ABCDE-3"
+          component_id="401"
+          root_component_id="399"
+          rule_id="501"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          message="[null]"
+          line="200"
+          effort_to_fix="4.2"
+          status="OPEN"
+          resolution="FIXED"
+          checksum="XXX"
+          reporter="arthur"
+          assignee="perceval"
+          author_login="[null]"
+          issue_attributes="JIRA=FOO-1234"
+          issue_creation_date="2014-04-16"
+          issue_update_date="2014-04-16"
+          issue_close_date="2014-04-16"
+          created_at="2014-04-16"
+          updated_at="2014-04-16"
+          />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update-result.xml
new file mode 100644 (file)
index 0000000..a923dfa
--- /dev/null
@@ -0,0 +1,28 @@
+<dataset>
+  <issues
+      id="100"
+      kee="ABCDE"
+      component_id="123"
+      root_component_id="101"
+      rule_id="200"
+      severity="BLOCKER"
+      manual_severity="[false]"
+      message="the message"
+      line="500"
+      effort_to_fix="3.14"
+      technical_debt="10"
+      status="RESOLVED"
+      resolution="FIXED"
+      checksum="123456789"
+      reporter="emmerik"
+      author_login="morgan"
+      assignee="karadoc"
+      issue_attributes="JIRA=FOO-1234"
+      issue_creation_date="2013-05-18"
+      issue_update_date="2013-05-19"
+      issue_close_date="2013-05-20"
+      created_at="[null]"
+      updated_at="2013-05-22"
+      action_plan_key="current_sprint"
+      />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update.xml b/server/sonar-server/src/test/resources/org/sonar/server/issue/db/IssueDaoTest/update.xml
new file mode 100644 (file)
index 0000000..4c6f701
--- /dev/null
@@ -0,0 +1,28 @@
+<dataset>
+  <issues
+      id="100"
+      kee="ABCDE"
+      component_id="123"
+      root_component_id="100"
+      rule_id="200"
+      severity="INFO"
+      manual_severity="[false]"
+      message="old"
+      line="[null]"
+      effort_to_fix="[null]"
+      technical_debt="[null]"
+      status="OPEN"
+      resolution="[null]"
+      checksum="[null]"
+      reporter="[null]"
+      author_login="[null]"
+      assignee="[null]"
+      issue_attributes="[null]"
+      issue_creation_date="[null]"
+      issue_update_date="[null]"
+      issue_close_date="[null]"
+      created_at="[null]"
+      updated_at="2009-01-01"
+      action_plan_key="[null]"
+      />
+</dataset>
index 39b56b1644d6807159aaeca0e2f369a12ed6c49b..44262e5dc5d9b06ee30f6bd63acba32050edf7da 100644 (file)
@@ -37,6 +37,7 @@ import org.sonar.api.utils.DateUtils;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import java.io.Serializable;
 import java.util.List;
 import java.util.Map;
@@ -71,7 +72,14 @@ public class IssueNotifications implements BatchComponent, ServerComponent {
   public List<Notification> sendChanges(DefaultIssue issue, IssueChangeContext context, IssueQueryResult queryResult) {
     Map<DefaultIssue, Rule> issues = Maps.newHashMap();
     issues.put(issue, queryResult.rule(issue));
-    return sendChanges(issues, context, queryResult.project(issue), queryResult.component(issue));
+    return sendChanges(issue, context, queryResult.rule(issue), queryResult.project(issue), queryResult.component(issue));
+  }
+
+  @CheckForNull
+  public List<Notification> sendChanges(DefaultIssue issue, IssueChangeContext context, Rule rule, Component project, @Nullable Component component) {
+    Map<DefaultIssue, Rule> issues = Maps.newHashMap();
+    issues.put(issue, rule);
+    return sendChanges(issues, context, project, component);
   }
 
   @CheckForNull
@@ -131,6 +139,7 @@ public class IssueNotifications implements BatchComponent, ServerComponent {
     return notification;
   }
 
+  @CheckForNull
   private String ruleName(@Nullable Rule rule) {
     // this code should definitely be shared in api
     if (rule == null) {
index 63278903bf2156b05ca7cc1c133cd5753b0fec10..fa67f6872a9589ad1d2057895fa172ac8920cf85 100644 (file)
@@ -136,7 +136,7 @@ public final class IssueDto extends Dto<String> implements Serializable {
   }
 
   /**
-   * @deprecated please use setRootComponent;
+   * @deprecated please use setRootComponent
    */
   @Deprecated
   public IssueDto setRootComponentId(Long rootComponentId) {
@@ -349,6 +349,10 @@ public final class IssueDto extends Dto<String> implements Serializable {
     return ruleRepo;
   }
 
+  public RuleKey getRuleKey(){
+    return RuleKey.of(ruleRepo, ruleKey);
+  }
+
   public String getComponentKey() {
     return componentKey;
   }
@@ -369,6 +373,8 @@ public final class IssueDto extends Dto<String> implements Serializable {
 
   /**
    * Should only be used to persist in E/S
+   *
+   * Please use {@link #setRule(org.sonar.core.rule.RuleDto)} instead
    */
   public IssueDto setRuleKey(String repo, String rule) {
     this.ruleRepo = repo;
@@ -378,6 +384,8 @@ public final class IssueDto extends Dto<String> implements Serializable {
 
   /**
    * Should only be used to persist in E/S
+   *
+   * Please use {@link #setComponent(org.sonar.core.component.ComponentDto)} instead
    */
   public IssueDto setComponentKey(String componentKey) {
     this.componentKey = componentKey;
@@ -386,6 +394,8 @@ public final class IssueDto extends Dto<String> implements Serializable {
 
   /**
    * Should only be used to persist in E/S
+   *
+   * Please use {@link #setRootComponent(org.sonar.core.component.ComponentDto)} instead
    */
   public IssueDto setRootComponentKey(String rootComponentKey) {
     this.rootComponentKey = rootComponentKey;
@@ -474,7 +484,7 @@ public final class IssueDto extends Dto<String> implements Serializable {
     issue.setComponentId(componentId);
     issue.setProjectKey(rootComponentKey);
     issue.setManualSeverity(manualSeverity);
-    issue.setRuleKey(RuleKey.of(ruleRepo, ruleKey));
+    issue.setRuleKey(getRuleKey());
     issue.setActionPlanKey(actionPlanKey);
     issue.setAuthorLogin(authorLogin);
     issue.setNew(false);
index 6bf273c5176086efd6206e61d499aa7ffca9b6b3..7fb5c14598d37004805cddef3859ae56d3589760 100644 (file)
@@ -42,6 +42,8 @@ import java.util.List;
  * This facade wraps db operations related to permissions
  *
  * Should be removed when batch will no more create permission, and be replaced by a new PermissionService in module server (probably be a merge with InternalPermissionService)
+ *
+ * WARNING, this class is called by Views to apply default permission template on new views
  */
 public class PermissionFacade implements TaskComponent, ServerComponent {
 
index b327c37d4f391e1c5af11af947327168214a1030..37ea218345fd4f15f189c6089986c496b4673ea2 100644 (file)
@@ -31,7 +31,9 @@ import java.util.List;
 
 /**
  * @since 3.6
+ * @deprecated since 5.0
  */
+@Deprecated
 public interface IssueQueryResult {
   /**
    * Non-null paginated list of issues.