]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5531 Bulk change is no more using IssueFinder
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 22 Sep 2014 08:48:39 +0000 (10:48 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 22 Sep 2014 16:22:45 +0000 (18:22 +0200)
13 files changed:
server/sonar-server/src/main/java/org/sonar/server/issue/DefaultIssueService.java
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
server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterService.java
server/sonar-server/src/main/java/org/sonar/server/search/QueryContext.java
server/sonar-server/src/test/java/org/sonar/server/issue/DefaultIssueServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyDefaultIssueServiceTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/OldIssueServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/filter/IssueFilterServiceTest.java
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/issues_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/views/issues/_bulk_change_form.html.erb

index a49abf0c58309f86c10ceb9fb1e0ecef852e367b..cb151d9c92fbbb25ba208535390ea67df9186d2f 100644 (file)
@@ -347,7 +347,15 @@ public class DefaultIssueService implements IssueService {
   }
 
   /**
-   * Used by the bulk change
+   * Warning, paging is not taken into account when using this method, max limit is set. (Only used to execute query for bulk change)
+   * TODO move it to the IssueFilterService when OldIssueService will be removed
+   */
+  public List<Issue> searchFromQuery(IssueQuery query) {
+    return indexClient.get(IssueIndex.class).search(query, new QueryContext().setMaxLimit()).getHits();
+  }
+
+  /**
+   * Used by the bulk change : first load issues from E/S to load only authorized issues then load issues from DB in order to update them.
    * TODO move it to the IssueBulkChangeService when OldIssueService will be removed
    */
   @Override
index e919ba8f6dc9abfc14d1ce356e94dec2b47bcf4e..559e5b0ed1b9c12daba989e851f2668f2178290c 100644 (file)
@@ -479,6 +479,25 @@ public class InternalRubyIssueService implements ServerComponent {
     return issueFilterService.execute(issueQuery);
   }
 
+  /**
+   * Execute issue filter from parameters
+   */
+  public List<Issue> execute2(Map<String, Object> props) {
+    IssueQuery issueQuery = PublicRubyIssueService.toQuery(props);
+    return issueFilterService.execute2(issueQuery);
+  }
+
+  /**
+   * Execute issue filter from existing filter with optional overridable parameters
+   */
+  public List<Issue> execute2(Long issueFilterId, Map<String, Object> overrideProps) {
+    DefaultIssueFilter issueFilter = issueFilterService.find(issueFilterId, UserSession.get());
+    Map<String, Object> props = issueFilterService.deserializeIssueFilterQuery(issueFilter);
+    overrideProps(props, overrideProps);
+    IssueQuery issueQuery = PublicRubyIssueService.toQuery(props);
+    return issueFilterService.execute2(issueQuery);
+  }
+
   private void overrideProps(Map<String, Object> props, Map<String, Object> overrideProps) {
     for (Map.Entry<String, Object> entry : overrideProps.entrySet()) {
       props.put(entry.getKey(), entry.getValue());
@@ -620,4 +639,8 @@ public class InternalRubyIssueService implements ServerComponent {
     }
   }
 
+  public int maxPageSize(){
+    return IssueQuery.MAX_PAGE_SIZE;
+  }
+
 }
index 4b7b313047ff4ee55fb0a3a8d9595a8da56c36ec..0d6a6fc10eb338347902ee875759fc0ca49bd97c 100644 (file)
@@ -23,6 +23,7 @@ package org.sonar.server.issue;
 import com.google.common.collect.Multiset;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.IssueQuery;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.core.issue.workflow.Transition;
@@ -61,6 +62,8 @@ public interface IssueService extends ServerComponent {
 
   DefaultIssue getIssueByKey(String key);
 
+  List<Issue> searchFromQuery(IssueQuery query);
+
   List<Issue> search(List<String> issues);
 
 }
index fdb7fa9f56399943403b5f4c23b1f81ff359cbdc..665572b520814e52367f5c94da4c77135d2f8fbb 100644 (file)
@@ -231,7 +231,7 @@ public class OldIssueService implements IssueService {
     }
     Rule rule = findRule(ruleKey);
 
-    DefaultIssue issue = (DefaultIssue) new DefaultIssueBuilder()
+    DefaultIssue issue = new DefaultIssueBuilder()
       .componentKey(component.getKey())
       .projectKey(project.getKey())
       .line(line)
@@ -288,8 +288,6 @@ public class OldIssueService implements IssueService {
   }
 
   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
@@ -308,6 +306,10 @@ public class OldIssueService implements IssueService {
     return (DefaultIssue) loadIssue(key).first();
   }
 
+  public List<Issue> searchFromQuery(IssueQuery issueQuery) {
+    return finder.find(issueQuery).issues();
+  }
+
   @Override
   public List<Issue> search(List<String> issues) {
     return finder.find(IssueQuery.builder().issueKeys(issues).pageSize(-1).requiredRole(UserRole.USER).build()).issues();
index 0cc2a2a7c78de8a55fe9095df9ac6217431f2a74..315dd89376c35474d7b227022848ac582411f13a 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.IssueFinder;
 import org.sonar.api.issue.IssueQuery;
 import org.sonar.api.issue.IssueQueryResult;
@@ -40,9 +41,11 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.issue.IssueService;
 import org.sonar.server.user.UserSession;
 
 import javax.annotation.CheckForNull;
+
 import java.util.List;
 import java.util.Map;
 
@@ -53,15 +56,17 @@ public class IssueFilterService implements ServerComponent {
   private final IssueFilterDao filterDao;
   private final IssueFilterFavouriteDao favouriteDao;
   private final IssueFinder finder;
+  private final IssueService issueService;
   private final AuthorizationDao authorizationDao;
   private final IssueFilterSerializer serializer;
 
   public IssueFilterService(IssueFilterDao filterDao, IssueFilterFavouriteDao favouriteDao,
-                            IssueFinder finder, AuthorizationDao authorizationDao,
+                            IssueFinder finder, IssueService issueService, AuthorizationDao authorizationDao,
                             IssueFilterSerializer serializer) {
     this.filterDao = filterDao;
     this.favouriteDao = favouriteDao;
     this.finder = finder;
+    this.issueService = issueService;
     this.authorizationDao = authorizationDao;
     this.serializer = serializer;
   }
@@ -70,6 +75,10 @@ public class IssueFilterService implements ServerComponent {
     return createIssueFilterResult(finder.find(issueQuery), issueQuery);
   }
 
+  public List<Issue> execute2(IssueQuery issueQuery) {
+    return issueService.searchFromQuery(issueQuery);
+  }
+
   public DefaultIssueFilter find(Long id, UserSession userSession) {
     return findIssueFilterDto(id, getLoggedLogin(userSession)).toIssueFilter();
   }
index b2cfae1854bcb450db77d0b612ad4b7a79554eb9..b25d52ff11b5a14f0211177795f1d5d2a517da14 100644 (file)
@@ -31,7 +31,7 @@ import java.util.Set;
 import static com.google.common.collect.Sets.newHashSet;
 
 /**
- * Various Elasticsearch request options: paging, sorting, fields and facets
+ * Various Elasticsearch request options: paging, fields and facets
  *
  * @since 4.4
  */
index efd6cf718be51681f513801fe6f5ec2a7fda5571..61b368122734a7aa659844969eb12d6c900354ce 100644 (file)
@@ -386,6 +386,16 @@ public class DefaultIssueServiceMediumTest {
     assertThat(result).hasSize(1);
   }
 
+  @Test
+  public void search_from_query() {
+    IssueDto issue = newIssue();
+    tester.get(IssueDao.class).insert(session, issue);
+    session.commit();
+
+    List<Issue> result = service.searchFromQuery(IssueQuery.builder().build());
+    assertThat(result).hasSize(1);
+  }
+
   private IssueDto newIssue() {
     return new IssueDto()
       .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
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
deleted file mode 100644 (file)
index b807c0b..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 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
new file mode 100644 (file)
index 0000000..a6dcce2
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * 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
+  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 execute2_issue_filter_from_issue_query() {
+    service.execute2(Maps.<String, Object>newHashMap());
+    verify(issueFilterService).execute2(any(IssueQuery.class));
+  }
+
+  @Test
+  public void execute2_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.execute2(10L, overrideProps);
+    ArgumentCaptor<IssueQuery> captor = ArgumentCaptor.forClass(IssueQuery.class);
+    verify(issueFilterService).execute2(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));
+  }
+
+  @Test
+  public void max_query_size() {
+    assertThat(service.maxPageSize()).isEqualTo(500);
+  }
+
+  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;
+  }
+
+}
index adc7258a1e1003c100289f3f4c84e3147cedd49b..c594ffb8af26bcb7c22becb027ddbebf9ab4c328 100644 (file)
@@ -540,4 +540,11 @@ public class OldIssueServiceTest {
   public void search_issues() {
     assertThat(issueService.search(newArrayList("ABCD"))).hasSize(1);
   }
+
+  @Test
+  public void search_from_query() {
+    IssueQuery query = mock(IssueQuery.class);
+    issueService.searchFromQuery(query);
+    verify(finder).find(query);
+  }
 }
index 8248907912c5f6c6ccf217dfa32adb9e6fcd5042..f61451b499fa802941705078bb32846ac723747f 100644 (file)
@@ -41,6 +41,7 @@ import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.issue.IssueService;
 import org.sonar.server.user.MockUserSession;
 import org.sonar.server.user.UserSession;
 
@@ -64,10 +65,11 @@ public class IssueFilterServiceTest {
   IssueFilterDao issueFilterDao = mock(IssueFilterDao.class);
   IssueFilterFavouriteDao issueFilterFavouriteDao = mock(IssueFilterFavouriteDao.class);
   IssueFinder issueFinder = mock(IssueFinder.class);
+  IssueService issueService = mock(IssueService.class);
   AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
   IssueFilterSerializer issueFilterSerializer = mock(IssueFilterSerializer.class);
   UserSession userSession = MockUserSession.create().setLogin("john");
-  IssueFilterService service = new IssueFilterService(issueFilterDao, issueFilterFavouriteDao, issueFinder, authorizationDao, issueFilterSerializer);
+  IssueFilterService service = new IssueFilterService(issueFilterDao, issueFilterFavouriteDao, issueFinder, issueService, authorizationDao, issueFilterSerializer);
 
   @Test
   public void should_find_by_id() {
@@ -527,6 +529,15 @@ public class IssueFilterServiceTest {
     verify(issueFinder).find(issueQuery);
   }
 
+  @Test
+  public void should_execute2_from_issue_query() {
+    IssueQuery issueQuery = IssueQuery.builder().build();
+
+    service.execute2(issueQuery);
+
+    verify(issueService).searchFromQuery(issueQuery);
+  }
+
   @Test
   public void should_find_shared_issue_filter() {
     when(issueFilterDao.selectSharedFilters()).thenReturn(newArrayList(
index 7690cea09be4f502d697d2094329df30ab9ebe28..7bc3a3f5531bdb8ce48bebbee777b9a5d6280ed1 100644 (file)
@@ -152,10 +152,12 @@ class IssuesController < ApplicationController
     # SONAR-4654 pagination parameters should be remove when loading issues for bulk change
     issues_query_params.delete('pageIndex')
     if params[:id]
-      @issue_filter_result = Internal.issues.execute(params[:id].to_i, issues_query_params)
+      @issues = Internal.issues.execute2(params[:id].to_i, issues_query_params)
     else
-      @issue_filter_result = Internal.issues.execute(issues_query_params)
+      @issues = Internal.issues.execute2(issues_query_params)
     end
+    @projects = Set.new(@issues.map {|issue| issue.projectKey()})
+
     render :partial => 'issues/bulk_change_form'
   end
 
index 168d2e5e9eac709cc6e40fa1310557e3fc52fef7..729cd13e2cf5d10142120b2758a5db2f9fd9c97d 100644 (file)
@@ -1,9 +1,6 @@
 <%
-   issues_result = @issue_filter_result.result
-
-   issues = issues_result.issues
-   max_page_size_reached = issues_result.issues.size >= issues_result.paging.pageSize()
-   project_key = issues_result.project(issues.to_a.first).key if !issues.empty? && issues_result.projects().to_a.size == 1
+   project_key = @projects.to_a.first if !@projects.empty? && @projects.to_a.size == 1
+   max_page_size_reached = @issues.size >= Internal.issues.maxPageSize()
 
    transitions_by_issues = {}
    unresolved_issues = 0
@@ -11,7 +8,7 @@
    at_least_one_issue_is_planned = false
    at_least_one_issue_is_assigned = false
    all_issues_are_assigned_to_current_user = true
-   issues.each do |issue|
+   @issues.each do |issue|
      transitions = Internal.issues.listTransitions(issue)
      transitions.each do |transition|
        issues_for_transition = transitions_by_issues[transition.key] || 0
    end
 %>
 <form id="bulk-change-form" method="post" action="<%= ApplicationController.root_context -%>/issues/bulk_change">
-  <input type="hidden" name="issues" value="<%= issues.map { |issue| issue.key() }.join(',') -%>">
+  <input type="hidden" name="issues" value="<%= @issues.map { |issue| issue.key() }.join(',') -%>">
   <input type="hidden" name="actions[]" id="bulk-change-transition-action">
   <fieldset>
     <div class="modal-head">
-      <h2><%= message('issue_bulk_change.form.title', {:params => issues.size.to_s}) -%></h2>
+      <h2><%= message('issue_bulk_change.form.title', {:params => @issues.size.to_s}) -%></h2>
     </div>
     <div class="modal-body">
       <div>
       <% if max_page_size_reached %>
-        <p class="notes"><%= message('issue_bulk_change.max_issues_reached', :params => issues.size) -%></p>
+        <p class="notes"><%= message('issue_bulk_change.max_issues_reached', :params => @issues.size) -%></p>
       <% end %>
       </div>
       <div class="modal-error"/>