From 3b9408de9e82b118d37bef28f05a7c131e2b13a7 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Tue, 25 Jun 2013 10:41:56 +0200 Subject: [PATCH] SONAR-3714 Add check in plan action that all issues are related to the action plan project --- .../org/sonar/core/resource/ResourceDao.java | 1 + .../java/org/sonar/server/issue/Action.java | 2 +- .../org/sonar/server/issue/AssignAction.java | 4 +- .../org/sonar/server/issue/CommentAction.java | 56 +++++++++++++++ .../server/issue/DefaultIssueFinder.java | 6 +- .../issue/InternalRubyIssueService.java | 4 +- .../server/issue/IssueBulkChangeResult.java | 49 +++++++++++++ .../server/issue/IssueBulkChangeService.java | 24 ++++--- .../org/sonar/server/issue/PlanAction.java | 25 ++++++- .../sonar/server/issue/SetSeverityAction.java | 4 +- .../sonar/server/issue/TransitionAction.java | 56 +++++++++++++++ .../org/sonar/server/platform/Platform.java | 1 + .../sonar/server/issue/AssignActionTest.java | 15 +++- .../sonar/server/issue/CommentActionTest.java | 69 +++++++++++++++++++ .../issue/IssueBulkChangeServiceTest.java | 38 +++++++--- .../sonar/server/issue/PlanActionTest.java | 34 +++++++-- 16 files changed, 350 insertions(+), 38 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java create mode 100644 sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeResult.java create mode 100644 sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java create mode 100644 sonar-server/src/test/java/org/sonar/server/issue/CommentActionTest.java 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 properties, UserSession userSession); + abstract boolean verify(Map properties, List issues, UserSession userSession); abstract boolean execute(Map 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 properties, UserSession userSession){ + public boolean verify(Map properties, List 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 properties, List issues, UserSession userSession) { + return true; + } + + @Override + public boolean execute(Map properties, Context context) { + context.issueUpdater().addComment((DefaultIssue) context.issue(), comment(properties), context.issueChangeContext()); + return true; + } + + private String comment(Map 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 findProjects(Set projectIds) { - return resourceDao.findByIds(projectIds); - } - private Collection findActionPlans(Set 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> executeBulkChange(Map props) { - Result> result = Result.of(); + public Result executeBulkChange(Map props) { + Result 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 issuesChanged = newArrayList(); + List issuesNotChanged = newArrayList(); + + public void addIssueChanged(Issue issue){ + this.issuesChanged.add(issue); + } + + public void addIssueNotChanged(Issue issue){ + this.issuesNotChanged.add(issue); + } + + public List issuesChanged() { + return issuesChanged; + } + + public List 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 execute(IssueBulkChangeQuery issueBulkChangeQuery, UserSession userSession) { - List 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 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 properties, UserSession userSession){ + public boolean verify(Map properties, List 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 properties){ + private String planKey(Map properties) { return (String) properties.get("plan"); } + private void verifyIssuesAreAllRelatedOnActionPlanProject(List 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 properties, UserSession userSession) { + public boolean verify(Map properties, List 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 properties, List issues, UserSession userSession) { + return true; + } + + @Override + public boolean execute(Map properties, Context context) { + context.issueUpdater().addComment((DefaultIssue) context.issue(), transition(properties), context.issueChangeContext()); + return true; + } + + private String transition(Map 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 properties = newHashMap(); properties.put("assignee", assignee); + List 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 properties = newHashMap(); + properties.put("assignee", assignee); + List 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 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 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 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 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 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 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 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,22 +67,46 @@ public class PlanActionTest { } @Test - public void should_verify_action_plan_exists(){ + public void should_verify(){ String planKey = "ABCD"; Map 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 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 properties = newHashMap(); + properties.put("plan", planKey); + List 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 properties = newHashMap(); + properties.put("plan", planKey); + + when(actionPlanService.findByKey(eq(planKey), any(UserSession.class))).thenReturn(new DefaultActionPlan().setProjectKey("struts")); + List 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(); -- 2.39.5