aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-server
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@gmail.com>2013-06-04 15:54:15 +0200
committerSimon Brandhof <simon.brandhof@gmail.com>2013-06-04 15:58:18 +0200
commit2b90c6d9deb4fafe99ae7c88cdc67d02cd1d2d76 (patch)
treef07399be46b8d3032732e976134df5008bc808f9 /sonar-server
parentea4b51a3ad43e7d6ce6b18b9eac32fd45e0cc367 (diff)
downloadsonarqube-2b90c6d9deb4fafe99ae7c88cdc67d02cd1d2d76.tar.gz
sonarqube-2b90c6d9deb4fafe99ae7c88cdc67d02cd1d2d76.zip
SONAR-4284 Display a changelog in the Issue detail page
Diffstat (limited to 'sonar-server')
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java23
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueChangelog.java58
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogService.java59
-rw-r--r--sonar-server/src/main/java/org/sonar/server/issue/IssueCommentService.java (renamed from sonar-server/src/main/java/org/sonar/server/issue/IssueChangeService.java)12
-rw-r--r--sonar-server/src/main/java/org/sonar/server/platform/Platform.java3
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb2
-rw-r--r--sonar-server/src/main/webapp/WEB-INF/app/views/issue/_changelog.html.erb48
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java65
-rw-r--r--sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogServiceTest.java57
9 files changed, 266 insertions, 61 deletions
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 f8ad8068b62..87533a774ab 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
@@ -36,7 +36,6 @@ import org.sonar.api.utils.SonarException;
import org.sonar.core.issue.ActionPlanStats;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssueBuilder;
-import org.sonar.core.issue.db.IssueChangeDto;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
@@ -57,18 +56,20 @@ import java.util.Map;
public class InternalRubyIssueService implements ServerComponent {
private final IssueService issueService;
- private final IssueChangeService changeService;
+ private final IssueCommentService commentService;
+ private final IssueChangelogService changelogService;
private final ActionPlanService actionPlanService;
private final IssueStatsFinder issueStatsFinder;
private final ResourceDao resourceDao;
private final ActionService actionService;
public InternalRubyIssueService(IssueService issueService,
- IssueChangeService changeService,
- ActionPlanService actionPlanService,
+ IssueCommentService commentService,
+ IssueChangelogService changelogService, ActionPlanService actionPlanService,
IssueStatsFinder issueStatsFinder, ResourceDao resourceDao, ActionService actionService) {
this.issueService = issueService;
- this.changeService = changeService;
+ this.commentService = commentService;
+ this.changelogService = changelogService;
this.actionPlanService = actionPlanService;
this.issueStatsFinder = issueStatsFinder;
this.resourceDao = resourceDao;
@@ -95,9 +96,9 @@ public class InternalRubyIssueService implements ServerComponent {
return Issue.RESOLUTIONS;
}
- public List<IssueChangeDto> changelog(String issueKey) {
+ public IssueChangelog changelog(String issueKey) {
// TODO verify security
- return changeService.changelog(issueKey);
+ return changelogService.changelog(issueKey, UserSession.get());
}
public Result<Issue> doTransition(String issueKey, String transitionKey) {
@@ -143,7 +144,7 @@ public class InternalRubyIssueService implements ServerComponent {
public Result<IssueComment> addComment(String issueKey, String text) {
Result<IssueComment> result = Result.of();
try {
- result.set(changeService.addComment(issueKey, text, UserSession.get()));
+ result.set(commentService.addComment(issueKey, text, UserSession.get()));
} catch (Exception e) {
result.addError(e.getMessage());
}
@@ -151,15 +152,15 @@ public class InternalRubyIssueService implements ServerComponent {
}
public IssueComment deleteComment(String commentKey) {
- return changeService.deleteComment(commentKey, UserSession.get());
+ return commentService.deleteComment(commentKey, UserSession.get());
}
public IssueComment editComment(String commentKey, String newText) {
- return changeService.editComment(commentKey, newText, UserSession.get());
+ return commentService.editComment(commentKey, newText, UserSession.get());
}
public IssueComment findComment(String commentKey) {
- return changeService.findComment(commentKey);
+ return commentService.findComment(commentKey);
}
/**
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelog.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelog.java
new file mode 100644
index 00000000000..5eb1e1aeb9b
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelog.java
@@ -0,0 +1,58 @@
+/*
+ * 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 com.google.common.collect.Maps;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.user.User;
+
+import javax.annotation.CheckForNull;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @since 3.6
+ */
+public class IssueChangelog {
+
+ private final List<FieldDiffs> changes;
+ private final Map<String, User> usersByLogin;
+
+ public IssueChangelog(List<FieldDiffs> changes, Collection<User> users) {
+ this.changes = changes;
+ this.usersByLogin = Maps.newHashMap();
+ for (User user : users) {
+ usersByLogin.put(user.login(), user);
+ }
+ }
+
+ public List<FieldDiffs> changes() {
+ return changes;
+ }
+
+ @CheckForNull
+ public User user(FieldDiffs change) {
+ if (change.userLogin() == null) {
+ return null;
+ }
+ return usersByLogin.get(change.userLogin());
+ }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogService.java
new file mode 100644
index 00000000000..3f9101e226c
--- /dev/null
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogService.java
@@ -0,0 +1,59 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.user.User;
+import org.sonar.api.user.UserFinder;
+import org.sonar.core.issue.db.IssueChangeDao;
+import org.sonar.server.user.UserSession;
+
+import java.util.Collection;
+import java.util.List;
+
+public class IssueChangelogService implements ServerComponent {
+
+ private final IssueChangeDao changeDao;
+ private final UserFinder userFinder;
+
+ public IssueChangelogService(IssueChangeDao changeDao, UserFinder userFinder) {
+ this.changeDao = changeDao;
+ this.userFinder = userFinder;
+ }
+
+ public IssueChangelog changelog(String issueKey, UserSession userSession) {
+ // TODO verify security
+ List<FieldDiffs> changes = changeDao.selectChangelogByIssue(issueKey);
+
+ // Load users
+ List<String> logins = Lists.newArrayList();
+ for (FieldDiffs change : changes) {
+ if (change.userLogin() != null) {
+ logins.add(change.userLogin());
+ }
+ }
+ Collection<User> users = userFinder.findByLogins(logins);
+
+ return new IssueChangelog(changes, users);
+
+ }
+}
diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangeService.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueCommentService.java
index 3d73cbdea8c..ba8962c757f 100644
--- a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangeService.java
+++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueCommentService.java
@@ -38,9 +38,8 @@ import org.sonar.server.user.UserSession;
import java.util.Arrays;
import java.util.Date;
-import java.util.List;
-public class IssueChangeService implements ServerComponent {
+public class IssueCommentService implements ServerComponent {
private final IssueUpdater updater;
private final IssueChangeDao changeDao;
@@ -48,7 +47,7 @@ public class IssueChangeService implements ServerComponent {
private final DefaultIssueFinder finder;
private final IssueNotifications issueNotifications;
- public IssueChangeService(IssueUpdater updater, IssueChangeDao changeDao, IssueStorage storage, DefaultIssueFinder finder, IssueNotifications issueNotifications) {
+ public IssueCommentService(IssueUpdater updater, IssueChangeDao changeDao, IssueStorage storage, DefaultIssueFinder finder, IssueNotifications issueNotifications) {
this.updater = updater;
this.changeDao = changeDao;
this.storage = storage;
@@ -56,11 +55,6 @@ public class IssueChangeService implements ServerComponent {
this.issueNotifications = issueNotifications;
}
- public List<IssueChangeDto> changelog(String issueKey) {
- // TODO verify security
- return changeDao.selectIssueChangelog(issueKey);
- }
-
public IssueComment findComment(String commentKey) {
return changeDao.selectCommentByKey(commentKey);
}
@@ -129,7 +123,7 @@ public class IssueChangeService implements ServerComponent {
public IssueQueryResult loadIssue(String issueKey) {
IssueQuery query = IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).requiredRole(UserRole.USER).build();
IssueQueryResult result = finder.find(query);
- if (result.issues().size()!=1) {
+ if (result.issues().size() != 1) {
throw new IllegalStateException("Issue not found: " + issueKey);
}
return result;
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 aaf8182ead1..8a52b6f8124 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
@@ -263,12 +263,13 @@ public final class Platform {
servicesContainer.addSingleton(FunctionExecutor.class);
servicesContainer.addSingleton(IssueWorkflow.class);
servicesContainer.addSingleton(IssueService.class);
- servicesContainer.addSingleton(IssueChangeService.class);
+ servicesContainer.addSingleton(IssueCommentService.class);
servicesContainer.addSingleton(DefaultIssueFinder.class);
servicesContainer.addSingleton(IssueStatsFinder.class);
servicesContainer.addSingleton(PublicRubyIssueService.class);
servicesContainer.addSingleton(InternalRubyIssueService.class);
servicesContainer.addSingleton(ActionPlanService.class);
+ servicesContainer.addSingleton(IssueChangelogService.class);
servicesContainer.addSingleton(IssueNotifications.class);
servicesContainer.addSingleton(ActionService.class);
servicesContainer.addSingleton(Actions.class);
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb
index 980c1bee0cd..bc5ae43b029 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/issue_controller.rb
@@ -193,7 +193,7 @@ class IssueController < ApplicationController
require_parameters :id
@issue_results = Api.issues.find(params[:id])
@issue = @issue_results.first()
- @changes = Internal.issues.changelog(params[:id])
+ @changelog = Internal.issues.changelog(params[:id])
render :partial => 'issue/changelog'
end
diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_changelog.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_changelog.html.erb
index 421d203caad..26c12118c09 100644
--- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_changelog.html.erb
+++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_changelog.html.erb
@@ -1,15 +1,35 @@
-<ul>
- <li>
- <%= format_datetime(@issue.creationDate()) -%>
- <% if @issue.reporter %>
- - <%= message('issue.reported_by') -%> <%= @issue_results.user(@issue.reporter).name -%>
- <% end %>
- - <%= message('created') -%>
- </li>
-
- <% @changes.each do |change| %>
- <li>
- <%= format_datetime(change.createdAt()) -%> - <%= change.userLogin -%> - <%= change.changeData -%>
- </li>
+<table class="spaced">
+ <tr>
+ <td class="thin left top" nowrap><%= format_datetime(@issue.creationDate()) -%></td>
+ <td class="thin left top"nowrap><%= @issue_results.user(@issue.reporter).name if @issue.reporter -%></td>
+ <td class="left top"><%= message('created') -%></td>
+ </tr>
+ <%
+ @changelog.changes.each do |change|
+ user = @changelog.user(change)
+ %>
+ <tr>
+ <td class="thin left top" nowrap><%= format_datetime(change.createdAt()) -%></td>
+ <td class="thin left top" nowrap><%= h(user.name()) if user -%></td>
+ <td class="left top">
+ <%
+ change.diffs.entrySet().each_with_index do |entry, index|
+ key = entry.getKey()
+ diff = entry.getValue()
+ %>
+ <% if index>0 %><br/><% end %>
+ <% if diff.newValue.present? %>
+ <%= message('issue.changelog.changed_to', :params => [message(key), diff.newValue()]) -%>
+ <% else %>
+ <%= message('issue.changelog.removed', :params => [message(key)]) -%>
+ <% end %>
+ <% if diff.oldValue.present? %>
+ (<%= message('issue.changelog.was', :params => [diff.oldValue]) -%>)
+ <% end %>
+ <% end %>
+ </td>
+ </tr>
<% end %>
-</ul> \ No newline at end of file
+</table>
+
+
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
index 7c3b38d610e..93cf0d33881 100644
--- a/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
+++ b/sonar-server/src/test/java/org/sonar/server/issue/InternalRubyIssueServiceTest.java
@@ -24,12 +24,15 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.user.User;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.resource.ResourceDao;
import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceQuery;
import org.sonar.server.user.UserSession;
+import java.util.Collections;
import java.util.Map;
import static com.google.common.collect.Maps.newHashMap;
@@ -39,19 +42,20 @@ import static org.mockito.Mockito.*;
public class InternalRubyIssueServiceTest {
- private InternalRubyIssueService internalRubyIssueService;
- private IssueService issueService = mock(IssueService.class);
- private IssueChangeService commentService = mock(IssueChangeService.class);
- private ActionPlanService actionPlanService = mock(ActionPlanService.class);
- private ResourceDao resourceDao = mock(ResourceDao.class);
- private IssueStatsFinder issueStatsFinder = mock(IssueStatsFinder.class);
- private ActionService actionService = mock(ActionService.class);
+ InternalRubyIssueService service;
+ IssueService issueService = mock(IssueService.class);
+ IssueCommentService commentService = mock(IssueCommentService.class);
+ IssueChangelogService changelogService = mock(IssueChangelogService.class);
+ ActionPlanService actionPlanService = mock(ActionPlanService.class);
+ ResourceDao resourceDao = mock(ResourceDao.class);
+ IssueStatsFinder issueStatsFinder = mock(IssueStatsFinder.class);
+ ActionService actionService = mock(ActionService.class);
@Before
- public void before() {
+ public void setUp() {
ResourceDto project = new ResourceDto().setKey("org.sonar.Sample");
when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(project);
- internalRubyIssueService = new InternalRubyIssueService(issueService, commentService, actionPlanService, issueStatsFinder, resourceDao, actionService);
+ service = new InternalRubyIssueService(issueService, commentService, changelogService, actionPlanService, issueStatsFinder, resourceDao, actionService);
}
@Test
@@ -63,7 +67,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("deadLine", "2113-05-13");
ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
- Result result = internalRubyIssueService.createActionPlan(parameters);
+ Result result = service.createActionPlan(parameters);
assertThat(result.ok()).isTrue();
verify(actionPlanService).create(actionPlanCaptor.capture(), any(UserSession.class));
@@ -87,7 +91,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("project", "org.sonar.MultiSample");
ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
- Result result = internalRubyIssueService.updateActionPlan("ABCD", parameters);
+ Result result = service.updateActionPlan("ABCD", parameters);
assertThat(result.ok()).isTrue();
verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
@@ -110,7 +114,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("deadLine", "2113-05-13");
ArgumentCaptor<ActionPlan> actionPlanCaptor = ArgumentCaptor.forClass(ActionPlan.class);
- Result result = internalRubyIssueService.updateActionPlan("ABCD", parameters);
+ Result result = service.updateActionPlan("ABCD", parameters);
assertThat(result.ok()).isTrue();
verify(actionPlanService).update(actionPlanCaptor.capture(), any(UserSession.class));
@@ -128,7 +132,7 @@ public class InternalRubyIssueServiceTest {
public void should_not_update_action_plan_when_action_plan_is_not_found() {
when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
- Result result = internalRubyIssueService.updateActionPlan("ABCD", 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"));
}
@@ -137,7 +141,7 @@ public class InternalRubyIssueServiceTest {
public void should_delete_action_plan() {
when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
- Result result = internalRubyIssueService.deleteActionPlan("ABCD");
+ Result result = service.deleteActionPlan("ABCD");
verify(actionPlanService).delete(eq("ABCD"), any(UserSession.class));
assertThat(result.ok()).isTrue();
}
@@ -146,7 +150,7 @@ public class InternalRubyIssueServiceTest {
public void should_not_delete_action_plan_if_action_plan_not_found() {
when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(null);
- Result result = internalRubyIssueService.deleteActionPlan("ABCD");
+ 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"));
@@ -156,7 +160,7 @@ public class InternalRubyIssueServiceTest {
public void should_close_action_plan() {
when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
- Result result = internalRubyIssueService.closeActionPlan("ABCD");
+ Result result = service.closeActionPlan("ABCD");
verify(actionPlanService).setStatus(eq("ABCD"), eq("CLOSED"), any(UserSession.class));
assertThat(result.ok()).isTrue();
}
@@ -165,7 +169,7 @@ public class InternalRubyIssueServiceTest {
public void should_open_action_plan() {
when(actionPlanService.findByKey(eq("ABCD"), any(UserSession.class))).thenReturn(DefaultActionPlan.create("Long term"));
- Result result = internalRubyIssueService.openActionPlan("ABCD");
+ Result result = service.openActionPlan("ABCD");
verify(actionPlanService).setStatus(eq("ABCD"), eq("OPEN"), any(UserSession.class));
assertThat(result.ok()).isTrue();
}
@@ -176,7 +180,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("name", "Long term");
parameters.put("description", "Long term issues");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "project"));
}
@@ -188,7 +192,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("description", "Long term issues");
parameters.put("project", "org.sonar.Sample");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("errors.cant_be_empty", "name"));
}
@@ -200,7 +204,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("description", "Long term issues");
parameters.put("project", "org.sonar.Sample");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "name", 200));
}
@@ -212,7 +216,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("description", createLongString(1001));
parameters.put("project", "org.sonar.Sample");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_too_long", "description", 1000));
}
@@ -225,7 +229,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("project", "org.sonar.Sample");
parameters.put("deadLine", "18/05/2013");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("errors.is_not_valid", "date"));
}
@@ -238,7 +242,7 @@ public class InternalRubyIssueServiceTest {
parameters.put("project", "org.sonar.Sample");
parameters.put("deadLine", "2000-01-01");
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ Result result = service.createActionPlanResult(parameters);
assertThat(result.ok()).isFalse();
assertThat(result.errors()).contains(Result.Message.ofL10n("action_plans.date_cant_be_in_past"));
}
@@ -252,7 +256,7 @@ public class InternalRubyIssueServiceTest {
when(actionPlanService.isNameAlreadyUsedForProject(anyString(), anyString())).thenReturn(true);
- Result result = internalRubyIssueService.createActionPlanResult(parameters, DefaultActionPlan.create("Short term"));
+ 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"));
}
@@ -266,10 +270,11 @@ public class InternalRubyIssueServiceTest {
when(resourceDao.getResource(any(ResourceQuery.class))).thenReturn(null);
- Result result = internalRubyIssueService.createActionPlanResult(parameters);
+ 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"));
}
+
public String createLongString(int size) {
String result = "";
for (int i = 0; i < size; i++) {
@@ -277,4 +282,14 @@ public class InternalRubyIssueServiceTest {
}
return result;
}
+
+ @Test
+ public void test_changelog() throws Exception {
+ IssueChangelog changelog = new IssueChangelog(Collections.<FieldDiffs>emptyList(), Collections.<User>emptyList());
+ when(changelogService.changelog(eq("ABCDE"), any(UserSession.class))).thenReturn(changelog);
+
+ IssueChangelog result = service.changelog("ABCDE");
+
+ assertThat(result).isSameAs(changelog);
+ }
}
diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogServiceTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogServiceTest.java
new file mode 100644
index 00000000000..0e517c8ea0f
--- /dev/null
+++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogServiceTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.Test;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.user.User;
+import org.sonar.api.user.UserFinder;
+import org.sonar.core.issue.db.IssueChangeDao;
+import org.sonar.core.user.DefaultUser;
+import org.sonar.server.user.UserSession;
+
+import java.util.Arrays;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class IssueChangelogServiceTest {
+
+ IssueChangeDao changeDao = mock(IssueChangeDao.class);
+ UserFinder userFinder = mock(UserFinder.class);
+ IssueChangelogService service = new IssueChangelogService(changeDao, userFinder);
+
+ @Test
+ public void should_load_changelog_and_related_users() throws Exception {
+ FieldDiffs userChange = new FieldDiffs().setUserLogin("arthur").setDiff("severity", "MAJOR", "BLOCKER");
+ FieldDiffs scanChange = new FieldDiffs().setDiff("status", "RESOLVED", "CLOSED");
+ when(changeDao.selectChangelogByIssue("ABCDE")).thenReturn(Arrays.asList(userChange, scanChange));
+ User arthur = new DefaultUser().setLogin("arthur").setName("Arthur");
+ when(userFinder.findByLogins(Arrays.asList("arthur"))).thenReturn(Arrays.asList(arthur));
+
+ IssueChangelog changelog = service.changelog("ABCDE", mock(UserSession.class));
+
+ assertThat(changelog).isNotNull();
+ assertThat(changelog.changes()).containsOnly(userChange, scanChange);
+ assertThat(changelog.user(scanChange)).isNull();
+ assertThat(changelog.user(userChange)).isSameAs(arthur);
+ }
+}