aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@gmail.com>2013-06-25 10:41:56 +0200
committerJulien Lancelot <julien.lancelot@gmail.com>2013-06-25 10:41:56 +0200
commit3b9408de9e82b118d37bef28f05a7c131e2b13a7 (patch)
tree3ac581b6c6cb17af8ffd7b5a94f5e4b9708744ce
parent1296af33c362310fde9d7e6e4357d5a758a323c4 (diff)
downloadsonarqube-3b9408de9e82b118d37bef28f05a7c131e2b13a7.tar.gz
sonarqube-3b9408de9e82b118d37bef28f05a7c131e2b13a7.zip
SONAR-3714 Add check in plan action that all issues are related to the action plan project
-rw-r--r--sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java1
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/Action.java2
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java56
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java6
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeResult.java49
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java24
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java25
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java4
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java56
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java1
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java15
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java69
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java38
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java34
16 files changed, 350 insertions, 38 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
index bcb7514322d..5dfb4ec22ae 100644
--- a/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
@@ -155,6 +155,7 @@ public class ResourceDao {
}
}
+ @CheckForNull
public Component findByKey(String key) {
ResourceDto resourceDto = getResource(ResourceQuery.create().setKey(key));
return resourceDto != null ? toComponent(resourceDto) : null;
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/Action.java b/sonar-server/src/main/java/org/sonar/server/issue/Action.java
index eddfba173f8..ec56d59ec96 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/Action.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/Action.java
@@ -71,7 +71,7 @@ public abstract class Action implements ServerComponent {
return true;
}
- abstract boolean verify(Map<String, Object> properties, UserSession userSession);
+ abstract boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession);
abstract boolean execute(Map<String, Object> properties, Context context);
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java b/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
index 04a0f82ecd9..15b35697b3c 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/AssignAction.java
@@ -21,11 +21,13 @@
package org.sonar.server.issue;
import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.Issue;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.user.UserFinder;
import org.sonar.server.user.UserSession;
+import java.util.List;
import java.util.Map;
@@ -42,7 +44,7 @@ public class AssignAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, UserSession userSession){
+ public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession){
String assignee = assignee(properties);
if (assignee != null && userFinder.findByLogin(assignee) == null) {
throw new IllegalArgumentException("Unknown user: " + assignee);
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java b/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
new file mode 100644
index 00000000000..da4c244d1cb
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
@@ -0,0 +1,56 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.sonar.api.ServerComponent;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.condition.IsUnResolved;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.server.user.UserSession;
+
+import java.util.List;
+import java.util.Map;
+
+
+public class CommentAction extends Action implements ServerComponent {
+
+ public static final String COMMENT_ACTION_KEY = "comment";
+
+ public CommentAction() {
+ super(COMMENT_ACTION_KEY);
+ super.setConditions(new IsUnResolved());
+ }
+
+ @Override
+ public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ return true;
+ }
+
+ @Override
+ public boolean execute(Map<String, Object> properties, Context context) {
+ context.issueUpdater().addComment((DefaultIssue) context.issue(), comment(properties), context.issueChangeContext());
+ return true;
+ }
+
+ private String comment(Map<String, Object> properties) {
+ return (String) properties.get("comment");
+ }
+} \ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java
index 5fdd5b54e04..2cd7a861fdb 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueFinder.java
@@ -147,7 +147,7 @@ public class DefaultIssueFinder implements IssueFinder {
.setMaxResultsReached(authorizedIssues.size() == query.maxResults())
.addRules(findRules(ruleIds))
.addComponents(findComponents(componentIds))
- .addProjects(findProjects(projectIds))
+ .addProjects(findComponents(projectIds))
.addActionPlans(findActionPlans(actionPlanKeys))
.addUsers(findUsers(users))
.setPaging(paging);
@@ -189,10 +189,6 @@ public class DefaultIssueFinder implements IssueFinder {
return resourceDao.findByIds(componentIds);
}
- private Collection<Component> findProjects(Set<Long> projectIds) {
- return resourceDao.findByIds(projectIds);
- }
-
private Collection<ActionPlan> findActionPlans(Set<String> actionPlanKeys) {
return actionPlanService.findByKeys(actionPlanKeys);
}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
index a3edbcc346a..f25fbd45238 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
@@ -588,8 +588,8 @@ public class InternalRubyIssueService implements ServerComponent {
/**
* Execute a bulk change
*/
- public Result<List<Issue>> executeBulkChange(Map<String, Object> props) {
- Result<List<Issue>> result = Result.of();
+ public Result<IssueBulkChangeResult> executeBulkChange(Map<String, Object> props) {
+ Result<IssueBulkChangeResult> result = Result.of();
try {
IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(props);
result.set(issueBulkChangeService.execute(issueBulkChangeQuery, UserSession.get()));
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeResult.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeResult.java
new file mode 100644
index 00000000000..092f3bfc4bb
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeResult.java
@@ -0,0 +1,49 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.sonar.api.issue.Issue;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class IssueBulkChangeResult {
+
+ List<Issue> issuesChanged = newArrayList();
+ List<Issue> issuesNotChanged = newArrayList();
+
+ public void addIssueChanged(Issue issue){
+ this.issuesChanged.add(issue);
+ }
+
+ public void addIssueNotChanged(Issue issue){
+ this.issuesNotChanged.add(issue);
+ }
+
+ public List<Issue> issuesChanged() {
+ return issuesChanged;
+ }
+
+ public List<Issue> issuesInError() {
+ return issuesNotChanged;
+ }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
index 836eb4774dc..67acadd059a 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
@@ -40,8 +40,6 @@ import javax.annotation.CheckForNull;
import java.util.Date;
import java.util.List;
-import static com.google.common.collect.Lists.newArrayList;
-
public class IssueBulkChangeService {
private static final Logger LOG = LoggerFactory.getLogger(IssueBulkChangeService.class);
@@ -60,18 +58,22 @@ public class IssueBulkChangeService {
this.actions = actions;
}
- public List<Issue> execute(IssueBulkChangeQuery issueBulkChangeQuery, UserSession userSession) {
- List<Issue> issues = newArrayList();
+ public IssueBulkChangeResult execute(IssueBulkChangeQuery issueBulkChangeQuery, UserSession userSession) {
verifyLoggedIn(userSession);
+ IssueBulkChangeResult result = new IssueBulkChangeResult();
+ IssueQueryResult issueQueryResult = issueFinder.find(IssueQuery.builder().issueKeys(issueBulkChangeQuery.issues()).requiredRole(UserRole.USER).build());
+ List<Issue> issues = issueQueryResult.issues();
for (String actionName : issueBulkChangeQuery.actions()) {
Action action = getAction(actionName);
- action.verify(issueBulkChangeQuery.properties(actionName), userSession);
+ if (action == null) {
+ throw new IllegalArgumentException("The action : '"+ actionName + "' is unknown");
+ }
+ action.verify(issueBulkChangeQuery.properties(actionName), issues, userSession);
}
- IssueQueryResult issueQueryResult = issueFinder.find(IssueQuery.builder().issueKeys(issueBulkChangeQuery.issues()).requiredRole(UserRole.USER).build());
IssueChangeContext issueChangeContext = IssueChangeContext.createUser(new Date(), userSession.login());
- for (Issue issue : issueQueryResult.issues()) {
+ for (Issue issue : issues) {
for (String actionName : issueBulkChangeQuery.actions()) {
try {
Action action = getAction(actionName);
@@ -79,15 +81,17 @@ public class IssueBulkChangeService {
if (action.supports(issue) && action.execute(issueBulkChangeQuery.properties(actionName), actionContext)) {
issueStorage.save((DefaultIssue) issue);
issueNotifications.sendChanges((DefaultIssue) issue, issueChangeContext, issueQueryResult);
- issues.add(issue);
+ result.addIssueChanged(issue);
+ } else {
+ result.addIssueNotChanged(issue);
}
} catch (Exception e) {
- // Do nothing, just go to the next issue
+ result.addIssueNotChanged(issue);
LOG.info("An error occur when trying to apply the action : "+ actionName + " on issue : "+ issue.key() + ". This issue has been ignored.", e);
}
}
}
- return issues;
+ return result;
}
@CheckForNull
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java b/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
index c7d9433c199..7c38b6c18c1 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/PlanAction.java
@@ -22,10 +22,13 @@ package org.sonar.server.issue;
import com.google.common.base.Strings;
import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.Issue;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.server.user.UserSession;
+import java.util.List;
import java.util.Map;
@@ -42,9 +45,15 @@ public class PlanAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, UserSession userSession){
+ public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
String actionPlanKey = planKey(properties);
- if (!Strings.isNullOrEmpty(actionPlanKey) && actionPlanService.findByKey(actionPlanKey, userSession) == null) {
+ if (!Strings.isNullOrEmpty(actionPlanKey)) {
+ ActionPlan actionPlan = actionPlanService.findByKey(actionPlanKey, userSession);
+ if (actionPlan == null) {
+ throw new IllegalArgumentException("Unknown action plan: " + actionPlanKey);
+ }
+ verifyIssuesAreAllRelatedOnActionPlanProject(issues, actionPlan);
+ } else {
throw new IllegalArgumentException("Unknown action plan: " + actionPlanKey);
}
return true;
@@ -56,8 +65,18 @@ public class PlanAction extends Action implements ServerComponent {
return true;
}
- private String planKey(Map<String, Object> properties){
+ private String planKey(Map<String, Object> properties) {
return (String) properties.get("plan");
}
+ private void verifyIssuesAreAllRelatedOnActionPlanProject(List<Issue> issues, ActionPlan actionPlan) {
+ String projectKey = actionPlan.projectKey();
+ for (Issue issue : issues) {
+ DefaultIssue defaultIssue = (DefaultIssue) issue;
+ if (!defaultIssue.projectKey().equals(projectKey)) {
+ throw new IllegalArgumentException("Issues are not all related to the action plan project: " + projectKey);
+ }
+ }
+ }
+
} \ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java b/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
index 8f6ccb6c78a..e51501599e4 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
@@ -21,10 +21,12 @@
package org.sonar.server.issue;
import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.Issue;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.server.user.UserSession;
+import java.util.List;
import java.util.Map;
@@ -38,7 +40,7 @@ public class SetSeverityAction extends Action implements ServerComponent {
}
@Override
- public boolean verify(Map<String, Object> properties, UserSession userSession) {
+ public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
return true;
}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java b/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
new file mode 100644
index 00000000000..03790110f8d
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
@@ -0,0 +1,56 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.sonar.api.ServerComponent;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.condition.IsUnResolved;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.server.user.UserSession;
+
+import java.util.List;
+import java.util.Map;
+
+
+public class TransitionAction extends Action implements ServerComponent {
+
+ public static final String TRANSITION_ACTION_KEY = "transition";
+
+ public TransitionAction() {
+ super(TRANSITION_ACTION_KEY);
+ super.setConditions(new IsUnResolved());
+ }
+
+ @Override
+ public boolean verify(Map<String, Object> properties, List<Issue> issues, UserSession userSession) {
+ return true;
+ }
+
+ @Override
+ public boolean execute(Map<String, Object> properties, Context context) {
+ context.issueUpdater().addComment((DefaultIssue) context.issue(), transition(properties), context.issueChangeContext());
+ return true;
+ }
+
+ private String transition(Map<String, Object> properties) {
+ return (String) properties.get("transition");
+ }
+} \ No newline at end of file
diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
index 8968b3d06e0..9bdc3e50d99 100644
--- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
+++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
@@ -281,6 +281,7 @@ public final class Platform {
servicesContainer.addSingleton(AssignAction.class);
servicesContainer.addSingleton(PlanAction.class);
servicesContainer.addSingleton(SetSeverityAction.class);
+ servicesContainer.addSingleton(CommentAction.class);
// rules
servicesContainer.addSingleton(RubyRuleService.class);
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java b/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java
index 0d7b2af26e6..98c3d68e476 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/AssignActionTest.java
@@ -30,8 +30,10 @@ import org.sonar.core.issue.IssueUpdater;
import org.sonar.core.user.DefaultUser;
import org.sonar.server.user.UserSession;
+import java.util.List;
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.mockito.Matchers.any;
@@ -72,12 +74,21 @@ public class AssignActionTest {
Map<String, Object> properties = newHashMap();
properties.put("assignee", assignee);
+ List<Issue> issues = newArrayList((Issue) new DefaultIssue().setKey("ABC"));
when(userFinder.findByLogin(assignee)).thenReturn(new DefaultUser());
- assertThat(action.verify(properties, mock(UserSession.class))).isTrue();
+ assertThat(action.verify(properties, issues, mock(UserSession.class))).isTrue();
+ }
+
+ @Test
+ public void should_fail_if_assignee_does_not_exists(){
+ String assignee = "arthur";
+ Map<String, Object> properties = newHashMap();
+ properties.put("assignee", assignee);
+ List<Issue> issues = newArrayList((Issue) new DefaultIssue().setKey("ABC"));
when(userFinder.findByLogin(assignee)).thenReturn(null);
try {
- action.verify(properties, mock(UserSession.class));
+ action.verify(properties, issues, mock(UserSession.class));
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown user: arthur");
}
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java b/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java
new file mode 100644
index 00000000000..247fe882588
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java
@@ -0,0 +1,69 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.Before;
+import org.junit.Test;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.core.issue.IssueUpdater;
+
+import java.util.Map;
+
+import static com.google.common.collect.Maps.newHashMap;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+public class CommentActionTest {
+
+ private CommentAction action;
+
+ @Before
+ public void before(){
+ action = new CommentAction();
+ }
+
+ @Test
+ public void should_execute(){
+ String comment = "My bulk change comment";
+ Map<String, Object> properties = newHashMap();
+ properties.put("comment", comment);
+ DefaultIssue issue = mock(DefaultIssue.class);
+ IssueUpdater issueUpdater = mock(IssueUpdater.class);
+
+ Action.Context context = mock(Action.Context.class);
+ when(context.issueUpdater()).thenReturn(issueUpdater);
+ when(context.issue()).thenReturn(issue);
+
+ action.execute(properties, context);
+ verify(issueUpdater).addComment(eq(issue), eq(comment), any(IssueChangeContext.class));
+ }
+
+ @Test
+ public void should_support_only_unresolved_issues(){
+ assertThat(action.supports(new DefaultIssue().setStatus(Issue.STATUS_OPEN))).isTrue();
+ assertThat(action.supports(new DefaultIssue().setStatus(Issue.STATUS_CLOSED))).isTrue();
+ }
+
+}
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
index 85e04a983a3..7d6041daacf 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceTest.java
@@ -87,8 +87,9 @@ public class IssueBulkChangeServiceTest {
when(action.execute(eq(properties), any(IssueBulkChangeService.ActionContext.class))).thenReturn(true);
IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
- List<Issue> result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result).hasSize(1);
+ IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+ assertThat(result.issuesChanged).hasSize(1);
+ assertThat(result.issuesNotChanged).isEmpty();
verifyNoMoreInteractions(issueUpdater);
verify(issueStorage).save(eq(issue));
@@ -106,8 +107,9 @@ public class IssueBulkChangeServiceTest {
when(action.supports(any(Issue.class))).thenReturn(false);
IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
- List<Issue> result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result).isEmpty();
+ IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+ assertThat(result.issuesChanged).isEmpty();
+ assertThat(result.issuesNotChanged).hasSize(1);
verifyZeroInteractions(issueUpdater);
verifyZeroInteractions(issueStorage);
@@ -124,8 +126,9 @@ public class IssueBulkChangeServiceTest {
when(action.execute(anyMap(), any(IssueBulkChangeService.ActionContext.class))).thenReturn(false);
IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
- List<Issue> result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result).isEmpty();
+ IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+ assertThat(result.issuesChanged).isEmpty();
+ assertThat(result.issuesNotChanged).hasSize(1);
verifyZeroInteractions(issueUpdater);
verifyZeroInteractions(issueStorage);
@@ -142,8 +145,9 @@ public class IssueBulkChangeServiceTest {
doThrow(new RuntimeException("Error")).when(action).execute(anyMap(), any(IssueBulkChangeService.ActionContext.class));
IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
- List<Issue> result = service.execute(issueBulkChangeQuery, userSession);
- assertThat(result).isEmpty();
+ IssueBulkChangeResult result = service.execute(issueBulkChangeQuery, userSession);
+ assertThat(result.issuesChanged).isEmpty();
+ assertThat(result.issuesNotChanged).hasSize(1);
verifyZeroInteractions(issueUpdater);
verifyZeroInteractions(issueStorage);
@@ -151,7 +155,7 @@ public class IssueBulkChangeServiceTest {
}
@Test
- public void should_fail_if_user_not_loggued() {
+ public void should_fail_if_user_not_logged() {
when(userSession.isLoggedIn()).thenReturn(false);
Map<String, Object> properties = newHashMap();
@@ -165,6 +169,22 @@ public class IssueBulkChangeServiceTest {
assertThat(e).isInstanceOf(IllegalStateException.class).hasMessage("User is not logged in");
}
verifyZeroInteractions(issueUpdater);
+ verifyZeroInteractions(issueStorage);
+ verifyZeroInteractions(issueNotifications);
+ }
+
+ @Test
+ public void should_fail_if_action_not_found() {
+ Map<String, Object> properties = newHashMap();
+ properties.put("issues", "ABCD");
+ properties.put("actions", "unknown");
+ IssueBulkChangeQuery issueBulkChangeQuery = new IssueBulkChangeQuery(properties);
+ try {
+ service.execute(issueBulkChangeQuery, userSession);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The action : 'unknown' is unknown");
+ }
verifyZeroInteractions(issueUpdater);
verifyZeroInteractions(issueStorage);
verifyZeroInteractions(issueNotifications);
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java b/sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java
index 31c6392136d..d610146a221 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/PlanActionTest.java
@@ -29,8 +29,10 @@ import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
+import java.util.List;
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.mockito.Matchers.any;
@@ -65,23 +67,47 @@ public class PlanActionTest {
}
@Test
- public void should_verify_action_plan_exists(){
+ public void should_verify(){
String planKey = "ABCD";
Map<String, Object> properties = newHashMap();
properties.put("plan", planKey);
- when(actionPlanService.findByKey(eq(planKey), any(UserSession.class))).thenReturn(new DefaultActionPlan());
- assertThat(action.verify(properties, mock(UserSession.class))).isTrue();
+ List<Issue> issues = newArrayList((Issue) new DefaultIssue().setKey("ABC").setProjectKey("struts"));
+ when(actionPlanService.findByKey(eq(planKey), any(UserSession.class))).thenReturn(new DefaultActionPlan().setProjectKey("struts"));
+ assertThat(action.verify(properties, issues, mock(UserSession.class))).isTrue();
+ }
+
+ @Test
+ public void should_fail_if_action_plan_does_not_exists(){
+ String planKey = "ABCD";
+ Map<String, Object> properties = newHashMap();
+ properties.put("plan", planKey);
+ List<Issue> issues = newArrayList((Issue) new DefaultIssue().setKey("ABC").setProjectKey("struts"));
when(actionPlanService.findByKey(eq(planKey), any(UserSession.class))).thenReturn(null);
try {
- action.verify(properties, mock(UserSession.class));
+ action.verify(properties, issues, mock(UserSession.class));
} catch (Exception e) {
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Unknown action plan: ABCD");
}
}
@Test
+ public void should_verify_issues_are_on_the_same_project(){
+ String planKey = "ABCD";
+ Map<String, Object> properties = newHashMap();
+ properties.put("plan", planKey);
+
+ when(actionPlanService.findByKey(eq(planKey), any(UserSession.class))).thenReturn(new DefaultActionPlan().setProjectKey("struts"));
+ List<Issue> issues = newArrayList(new DefaultIssue().setKey("ABC").setProjectKey("struts"), (Issue) new DefaultIssue().setKey("ABE").setProjectKey("mybatis"));
+ try {
+ action.verify(properties, issues, mock(UserSession.class));
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Issues are not all related to the action plan project: struts");
+ }
+ }
+
+ @Test
public void should_support_only_unresolved_issues(){
assertThat(action.supports(new DefaultIssue().setStatus(Issue.STATUS_OPEN))).isTrue();
assertThat(action.supports(new DefaultIssue().setStatus(Issue.STATUS_CLOSED))).isTrue();