*/
package org.sonar.server.issue;
+import java.util.Collections;
import java.util.List;
import org.sonar.db.issue.IssueDto;
import org.sonar.server.user.UserSession;
import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Objects.requireNonNull;
import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.server.issue.AssignAction.ASSIGN_KEY;
+import static org.sonar.server.issue.CommentAction.COMMENT_KEY;
+import static org.sonar.server.issue.SetSeverityAction.SET_SEVERITY_KEY;
+import static org.sonar.server.issue.SetTypeAction.SET_TYPE_KEY;
-/**
- * @since 3.6
- */
public class ActionFinder {
private final UserSession userSession;
public List<String> listAvailableActions(IssueDto issue) {
List<String> availableActions = newArrayList();
String login = userSession.getLogin();
- if (login != null) {
- availableActions.add("comment");
- if (issue.getResolution() == null) {
- availableActions.add("assign");
- availableActions.add("set_tags");
- availableActions.add("set_type");
- if (!login.equals(issue.getAssignee())) {
- availableActions.add("assign_to_me");
- }
- String projectUuid = issue.getProjectUuid();
- if (projectUuid != null && userSession.hasComponentUuidPermission(ISSUE_ADMIN, projectUuid)) {
- availableActions.add("set_severity");
- }
- }
+ if (login == null) {
+ return Collections.emptyList();
+ }
+ availableActions.add(COMMENT_KEY);
+ if (issue.getResolution() != null) {
+ return availableActions;
+ }
+ availableActions.add(ASSIGN_KEY);
+ availableActions.add("set_tags");
+ if (!login.equals(issue.getAssignee())) {
+ // This action will be removed by
+ availableActions.add("assign_to_me");
+ }
+ if (userSession.hasComponentUuidPermission(ISSUE_ADMIN, requireNonNull(issue.getProjectUuid()))) {
+ availableActions.add(SET_TYPE_KEY);
+ availableActions.add(SET_SEVERITY_KEY);
}
return availableActions;
}
import java.util.Map;
import javax.annotation.Nullable;
import org.sonar.api.ce.ComputeEngineSide;
-import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ServerSide;
import org.sonar.api.user.User;
import org.sonar.api.user.UserFinder;
-import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.db.DbClient;
}
}
- public void setSeverity(String issueKey, String severity) {
- userSession.checkLoggedIn();
-
- DbSession session = dbClient.openSession(false);
- try {
- DefaultIssue issue = issueFinder.getByKey(session, issueKey).toDefaultIssue();
- userSession.checkComponentUuidPermission(UserRole.ISSUE_ADMIN, issue.projectUuid());
-
- IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.getLogin());
- if (issueFieldsSetter.setManualSeverity(issue, severity, context)) {
- issueUpdater.saveIssue(session, issue, context, null);
- }
- } finally {
- session.close();
- }
- }
-
- public void setType(String issueKey, RuleType type) {
- userSession.checkLoggedIn();
-
- DbSession session = dbClient.openSession(false);
- try {
- DefaultIssue issue = issueFinder.getByKey(session, issueKey).toDefaultIssue();
- userSession.checkComponentUuidPermission(UserRole.ISSUE_ADMIN, issue.projectUuid());
-
- IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.getLogin());
- if (issueFieldsSetter.setType(issue, type, context)) {
- issueUpdater.saveIssue(session, issue, context, null);
- }
- } finally {
- session.close();
- }
- }
-
/**
* Search for all tags, whatever issue resolution or user access rights
*/
*/
package org.sonar.server.issue;
-import com.google.common.base.Strings;
import java.util.Collection;
import java.util.Map;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.user.UserSession;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
@ServerSide
public class SetSeverityAction extends Action {
@Override
public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) {
- severity(properties);
+ verifySeverityParameter(properties);
return true;
}
@Override
public boolean execute(Map<String, Object> properties, Context context) {
- return issueUpdater.setManualSeverity(context.issue(), severity(properties), context.issueChangeContext());
+ return issueUpdater.setManualSeverity(context.issue(), verifySeverityParameter(properties), context.issueChangeContext());
}
- private static String severity(Map<String, Object> properties) {
+ private static String verifySeverityParameter(Map<String, Object> properties) {
String param = (String) properties.get(SEVERITY_PARAMETER);
- if (Strings.isNullOrEmpty(param)) {
- throw new IllegalArgumentException("Missing parameter : 'severity'");
- }
+ checkArgument(!isNullOrEmpty(param), "Missing parameter : '%s'", SEVERITY_PARAMETER);
return param;
}
}
*/
package org.sonar.server.issue;
-import com.google.common.base.Preconditions;
import java.util.Collection;
import java.util.Map;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.rules.RuleType;
+import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.server.user.UserSession;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
public class SetTypeAction extends Action {
public static final String TYPE_PARAMETER = "type";
private final IssueFieldsSetter issueUpdater;
+ private final UserSession userSession;
- public SetTypeAction(IssueFieldsSetter issueUpdater) {
+ public SetTypeAction(IssueFieldsSetter issueUpdater, UserSession userSession) {
super(SET_TYPE_KEY);
this.issueUpdater = issueUpdater;
- super.setConditions(new IsUnResolved());
+ this.userSession = userSession;
+ super.setConditions(new IsUnResolved(), issue -> isCurrentUserIssueAdmin(issue.projectUuid()));
+ }
+
+ private boolean isCurrentUserIssueAdmin(String projectUuid) {
+ return userSession.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, projectUuid);
}
@Override
public boolean verify(Map<String, Object> properties, Collection<DefaultIssue> issues, UserSession userSession) {
- newValue(properties);
+ verifyTypeParameter(properties);
return true;
}
@Override
public boolean execute(Map<String, Object> properties, Context context) {
- String type = newValue(properties);
+ String type = verifyTypeParameter(properties);
return issueUpdater.setType(context.issue(), RuleType.valueOf(type), context.issueChangeContext());
}
- private static String newValue(Map<String, Object> properties) {
+ private static String verifyTypeParameter(Map<String, Object> properties) {
String type = (String) properties.get(TYPE_PARAMETER);
- Preconditions.checkArgument(!isNullOrEmpty(type), "Missing parameter: '%s'", TYPE_PARAMETER);
- Preconditions.checkArgument(RuleType.names().contains(type), "Unknown type: %s", type);
+ checkArgument(!isNullOrEmpty(type), "Missing parameter : '%s'", TYPE_PARAMETER);
+ checkArgument(RuleType.names().contains(type), "Unknown type : %s", type);
return type;
}
}
.build();
}
- private static class ActionContext implements Action.Context {
+ public static class ActionContext implements Action.Context {
private final DefaultIssue issue;
private final IssueChangeContext changeContext;
- ActionContext(DefaultIssue issue, IssueChangeContext changeContext) {
+ public ActionContext(DefaultIssue issue, IssueChangeContext changeContext) {
this.issue = issue;
this.changeContext = changeContext;
}
package org.sonar.server.issue.ws;
import com.google.common.io.Resources;
+import java.util.Date;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
import org.sonar.core.util.Uuids;
-import org.sonar.server.issue.IssueService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.IssueFinder;
+import org.sonar.server.issue.IssueUpdater;
+import org.sonar.server.user.UserSession;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SET_SEVERITY;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SEVERITY;
public class SetSeverityAction implements IssuesWsAction {
- private final IssueService issueService;
+ private final UserSession userSession;
+ private final DbClient dbClient;
+ private final IssueFinder issueFinder;
+ private final IssueFieldsSetter issueFieldsSetter;
+ private final IssueUpdater issueUpdater;
private final OperationResponseWriter responseWriter;
- public SetSeverityAction(IssueService issueService, OperationResponseWriter responseWriter) {
- this.issueService = issueService;
+ public SetSeverityAction(UserSession userSession, DbClient dbClient, IssueFinder issueFinder, IssueFieldsSetter issueFieldsSetter, IssueUpdater issueUpdater,
+ OperationResponseWriter responseWriter) {
+ this.userSession = userSession;
+ this.dbClient = dbClient;
+ this.issueFinder = issueFinder;
+ this.issueFieldsSetter = issueFieldsSetter;
+ this.issueUpdater = issueUpdater;
this.responseWriter = responseWriter;
}
@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction(ACTION_SET_SEVERITY)
- .setDescription("Change severity. Requires authentication and Browse permission on project")
+ .setDescription("Change severity.<br/>" +
+ "Requires the following permissions:" +
+ "<ul>" +
+ " <li>'Authentication'</li>" +
+ " <li>'Browse' rights on project of the specified issue</li>" +
+ " <li>'Administer Issues' rights on project of the specified issue</li>" +
+ "</ul>")
.setSince("3.6")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "set_severity-example.json"))
@Override
public void handle(Request request, Response response) throws Exception {
- String key = request.mandatoryParam(PARAM_ISSUE);
- issueService.setSeverity(key, request.mandatoryParam(PARAM_SEVERITY));
+ userSession.checkLoggedIn();
+ String issueKey = request.mandatoryParam(PARAM_ISSUE);
+ String severity = request.mandatoryParam(PARAM_SEVERITY);
+ try (DbSession session = dbClient.openSession(false)) {
+ setType(session, issueKey, severity);
+ }
+ responseWriter.write(issueKey, request, response);
+ }
+
+ private void setType(DbSession session, String issueKey, String severity) {
+ DefaultIssue issue = issueFinder.getByKey(session, issueKey).toDefaultIssue();
+ userSession.checkComponentUuidPermission(ISSUE_ADMIN, issue.projectUuid());
- responseWriter.write(key, request, response);
+ IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.getLogin());
+ if (issueFieldsSetter.setManualSeverity(issue, severity, context)) {
+ issueUpdater.saveIssue(session, issue, context, null);
+ }
}
}
package org.sonar.server.issue.ws;
import com.google.common.io.Resources;
+import java.util.Date;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.IssueChangeContext;
import org.sonar.core.util.Uuids;
-import org.sonar.server.issue.IssueService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.IssueFinder;
+import org.sonar.server.issue.IssueUpdater;
+import org.sonar.server.user.UserSession;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SET_TYPE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ISSUE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TYPE;
public class SetTypeAction implements IssuesWsAction {
- private final IssueService issueService;
+ private final UserSession userSession;
+ private final DbClient dbClient;
+ private final IssueFinder issueFinder;
+ private final IssueFieldsSetter issueFieldsSetter;
+ private final IssueUpdater issueUpdater;
private final OperationResponseWriter responseWriter;
- public SetTypeAction(IssueService issueService, OperationResponseWriter responseWriter) {
- this.issueService = issueService;
+ public SetTypeAction(UserSession userSession, DbClient dbClient, IssueFinder issueFinder, IssueFieldsSetter issueFieldsSetter, IssueUpdater issueUpdater,
+ OperationResponseWriter responseWriter) {
+ this.userSession = userSession;
+ this.dbClient = dbClient;
+ this.issueFinder = issueFinder;
+ this.issueFieldsSetter = issueFieldsSetter;
+ this.issueUpdater = issueUpdater;
this.responseWriter = responseWriter;
}
@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction(ACTION_SET_TYPE)
- .setDescription("Change type of issue, for instance from 'code smell' to 'bug'. Requires authentication and Browse permission on project.")
+ .setDescription("Change type of issue, for instance from 'code smell' to 'bug'.<br/>" +
+ "Requires the following permissions:" +
+ "<ul>" +
+ " <li>'Authentication'</li>" +
+ " <li>'Browse' rights on project of the specified issue</li>" +
+ " <li>'Administer Issues' rights on project of the specified issue</li>" +
+ "</ul>")
.setSince("5.5")
.setHandler(this)
.setResponseExample(Resources.getResource(this.getClass(), "set_type-example.json"))
@Override
public void handle(Request request, Response response) throws Exception {
- String key = request.mandatoryParam(PARAM_ISSUE);
- issueService.setType(key, RuleType.valueOf(request.mandatoryParam(PARAM_TYPE)));
+ userSession.checkLoggedIn();
+ String issueKey = request.mandatoryParam(PARAM_ISSUE);
+ RuleType ruleType = RuleType.valueOf(request.mandatoryParam(PARAM_TYPE));
+ try (DbSession session = dbClient.openSession(false)) {
+ setType(session, issueKey, ruleType);
+ }
+ responseWriter.write(issueKey, request, response);
+ }
+
+ private void setType(DbSession session, String issueKey, RuleType ruleType) {
+ DefaultIssue issue = issueFinder.getByKey(session, issueKey).toDefaultIssue();
+ userSession.checkComponentUuidPermission(ISSUE_ADMIN, issue.projectUuid());
- responseWriter.write(key, request, response);
+ IssueChangeContext context = IssueChangeContext.createUser(new Date(), userSession.getLogin());
+ if (issueFieldsSetter.setType(issue, ruleType, context)) {
+ issueUpdater.saveIssue(session, issue, context, null);
+ }
}
+
}
private ActionFinder underTest = new ActionFinder(userSession);
@Test
- public void return_provided_actions_without_set_severity_when_not_issue_admin() {
- assertThat(underTest.listAvailableActions(issue)).containsOnly("comment", "assign", "set_tags", "set_type", "assign_to_me");
+ public void return_provided_actions_without_set_severity_and_set_tpye_when_not_issue_admin() {
+ assertThat(underTest.listAvailableActions(issue)).containsOnly("comment", "assign", "set_tags", "assign_to_me");
}
@Test
- public void return_provided_actions_with_set_severity_when_issue_admin() {
+ public void return_provided_actions_with_set_severity_and_set_type_when_issue_admin() {
userSession.addProjectUuidPermissions(ISSUE_ADMIN, PROJECT_UUID);
assertThat(underTest.listAvailableActions(issue)).containsOnly("comment", "assign", "set_tags", "set_type", "assign_to_me", "set_severity");
}
}
@Test
- public void should_support_only_unresolved_issues() {
+ public void support_only_unresolved_issues() {
assertThat(action.supports(new DefaultIssue().setResolution(null))).isTrue();
assertThat(action.supports(new DefaultIssue().setResolution(Issue.RESOLUTION_FIXED))).isFalse();
}
+
}
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.issue.Issue;
-import org.sonar.api.rule.Severity;
-import org.sonar.api.rules.RuleType;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.db.DbClient;
}
}
- @Test
- public void set_severity() {
- RuleDto rule = newRule();
- ComponentDto project = newProject();
- ComponentDto file = newFile(project);
- userSessionRule.login("john")
- .addProjectUuidPermissions(UserRole.USER, project.uuid())
- .addProjectUuidPermissions(UserRole.ISSUE_ADMIN, project.uuid());
-
- IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project).setSeverity(Severity.BLOCKER));
-
- assertThat(issueIndex.getByKey(issue.getKey()).severity()).isEqualTo(Severity.BLOCKER);
-
- service.setSeverity(issue.getKey(), Severity.MINOR);
-
- assertThat(issueIndex.getByKey(issue.getKey()).severity()).isEqualTo(Severity.MINOR);
- }
-
- @Test
- public void set_type() {
- RuleDto rule = newRule();
- ComponentDto project = newProject();
- ComponentDto file = newFile(project);
- userSessionRule.login("john")
- .addProjectUuidPermissions(UserRole.USER, project.uuid())
- .addProjectUuidPermissions(UserRole.ISSUE_ADMIN, project.uuid());
-
- IssueDto issue = saveIssue(IssueTesting.newDto(rule, file, project).setType(RuleType.CODE_SMELL));
-
- assertThat(issueIndex.getByKey(issue.getKey()).type()).isEqualTo(RuleType.CODE_SMELL);
-
- service.setType(issue.getKey(), RuleType.BUG);
-
- assertThat(issueIndex.getByKey(issue.getKey()).type()).isEqualTo(RuleType.BUG);
- }
-
@Test
public void list_tags() {
RuleDto rule = newRule();
*/
package org.sonar.server.issue;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import java.util.Date;
import java.util.Map;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.issue.Issue;
-import org.sonar.api.web.UserRole;
import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
import org.sonar.core.issue.IssueChangeContext;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.issue.ws.BulkChangeAction;
import org.sonar.server.tester.AnonymousMockUserSession;
import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.UserSession;
-import static com.google.common.collect.Maps.newHashMap;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.sonar.api.rule.Severity.MAJOR;
+import static org.sonar.api.rule.Severity.MINOR;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.issue.IssueTesting.newDto;
+import static org.sonar.db.rule.RuleTesting.newRuleDto;
public class SetSeverityActionTest {
+ private static final Date NOW = new Date(10_000_000_000L);
+ private static final String USER_LOGIN = "john";
+
@Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ public ExpectedException expectedException = ExpectedException.none();
- private UserSession userSessionMock = mock(UserSession.class);
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
- private SetSeverityAction action;
+ @Rule
+ public DbTester db = DbTester.create();
- private IssueFieldsSetter issueUpdater = mock(IssueFieldsSetter.class);
+ private IssueFieldsSetter issueUpdater = new IssueFieldsSetter();
- @Before
- public void before() {
- action = new SetSeverityAction(issueUpdater, userSessionRule);
- userSessionRule.set(userSessionMock);
- }
+ private SetSeverityAction action = new SetSeverityAction(issueUpdater, userSession);
@Test
- public void should_execute() {
- String severity = "MINOR";
- Map<String, Object> properties = newHashMap();
- properties.put("severity", severity);
- DefaultIssue issue = mock(DefaultIssue.class);
+ public void set_severity() {
+ DefaultIssue issue = newIssue().setSeverity(MAJOR).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(issue.projectUuid());
+ BulkChangeAction.ActionContext context = new BulkChangeAction.ActionContext(issue, IssueChangeContext.createUser(NOW, userSession.getLogin()));
- Action.Context context = mock(Action.Context.class);
- when(context.issue()).thenReturn(issue);
+ action.execute(ImmutableMap.of("severity", MINOR), context);
- action.execute(properties, context);
- verify(issueUpdater).setManualSeverity(eq(issue), eq(severity), any(IssueChangeContext.class));
+ assertThat(issue.severity()).isEqualTo(MINOR);
+ assertThat(issue.isChanged()).isTrue();
+ assertThat(issue.manualSeverity()).isTrue();
+ assertThat(issue.updateDate()).isEqualTo(NOW);
+ assertThat(issue.mustSendNotifications()).isTrue();
+ Map<String, FieldDiffs.Diff> change = issue.currentChange().diffs();
+ assertThat(change.get("severity").newValue()).isEqualTo(MINOR);
+ assertThat(change.get("severity").oldValue()).isEqualTo(MAJOR);
}
@Test
- public void should_verify_fail_if_parameter_not_found() {
- Map<String, Object> properties = newHashMap();
- properties.put("unknwown", "unknown value");
- try {
- action.verify(properties, Lists.newArrayList(), new AnonymousMockUserSession());
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Missing parameter : 'severity'");
- }
- verifyZeroInteractions(issueUpdater);
+ public void fail_if_parameter_not_found() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Missing parameter : 'severity'");
+
+ action.verify(ImmutableMap.of("unknwown", MINOR), Lists.newArrayList(), new AnonymousMockUserSession());
}
@Test
- public void should_support_only_unresolved_issues() {
- when(userSessionMock.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, "foo:bar")).thenReturn(true);
- assertThat(action.supports(new DefaultIssue().setProjectUuid("foo:bar").setResolution(null))).isTrue();
- assertThat(action.supports(new DefaultIssue().setProjectUuid("foo:bar").setResolution(Issue.RESOLUTION_FIXED))).isFalse();
+ public void support_only_unresolved_issues() {
+ DefaultIssue issue = newIssue().setSeverity(MAJOR).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(issue.projectUuid());
+
+ assertThat(action.supports(issue.setResolution(null))).isTrue();
+ assertThat(action.supports(issue.setResolution(Issue.RESOLUTION_FIXED))).isFalse();
}
@Test
- public void should_support_only_issues_with_issue_admin_permission() {
- when(userSessionMock.hasComponentUuidPermission(UserRole.ISSUE_ADMIN, "foo:bar")).thenReturn(true);
- assertThat(action.supports(new DefaultIssue().setProjectUuid("foo:bar").setResolution(null))).isTrue();
- assertThat(action.supports(new DefaultIssue().setProjectUuid("foo:bar2").setResolution(null))).isFalse();
+ public void support_only_issues_with_issue_admin_permission() {
+ DefaultIssue authorizedIssue = newIssue().setSeverity(MAJOR).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(authorizedIssue.projectUuid());
+ DefaultIssue unauthorizedIssue = newIssue().setSeverity(MAJOR).toDefaultIssue();
+
+ assertThat(action.supports(authorizedIssue.setResolution(null))).isTrue();
+ assertThat(action.supports(unauthorizedIssue.setResolution(null))).isFalse();
+ }
+
+ private void setUserWithBrowseAndAdministerIssuePermission(String projectUuid) {
+ userSession.login(USER_LOGIN)
+ .addProjectUuidPermissions(ISSUE_ADMIN, projectUuid)
+ .addProjectUuidPermissions(USER, projectUuid);
+ }
+
+ private IssueDto newIssue() {
+ RuleDto rule = db.rules().insertRule(newRuleDto());
+ ComponentDto project = db.components().insertProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ return newDto(rule, file, project);
}
}
*/
package org.sonar.server.issue;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import java.util.Date;
import java.util.Map;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.sonar.api.issue.Issue;
-import org.sonar.api.rules.RuleType;
import org.sonar.core.issue.DefaultIssue;
+import org.sonar.core.issue.FieldDiffs;
import org.sonar.core.issue.IssueChangeContext;
-import org.sonar.server.tester.AnonymousMockUserSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.issue.ws.BulkChangeAction;
import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.UserSession;
-import static com.google.common.collect.Maps.newHashMap;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.sonar.api.rules.RuleType.BUG;
+import static org.sonar.api.rules.RuleType.VULNERABILITY;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.issue.IssueTesting.newDto;
+import static org.sonar.db.rule.RuleTesting.newRuleDto;
public class SetTypeActionTest {
+ private static final Date NOW = new Date(10_000_000_000L);
+ private static final String USER_LOGIN = "john";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
@Rule
- public UserSessionRule userSessionRule = UserSessionRule.standalone();
+ public DbTester db = DbTester.create();
+
+ private IssueFieldsSetter issueUpdater = new IssueFieldsSetter();
+
+ private SetTypeAction action = new SetTypeAction(issueUpdater, userSession);
+
+ @Test
+ public void set_type() {
+ DefaultIssue issue = newIssue().setType(BUG).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(issue.projectUuid());
- UserSession userSessionMock = mock(UserSession.class);
- IssueFieldsSetter issueUpdater = mock(IssueFieldsSetter.class);
- SetTypeAction underTest;
+ action.execute(ImmutableMap.of("type", VULNERABILITY.name()), new BulkChangeAction.ActionContext(issue, IssueChangeContext.createUser(NOW, userSession.getLogin())));
- @Before
- public void before() {
- underTest = new SetTypeAction(issueUpdater);
- userSessionRule.set(userSessionMock);
+ assertThat(issue.type()).isEqualTo(VULNERABILITY);
+ assertThat(issue.isChanged()).isTrue();
+ assertThat(issue.updateDate()).isEqualTo(NOW);
+ assertThat(issue.mustSendNotifications()).isFalse();
+ Map<String, FieldDiffs.Diff> change = issue.currentChange().diffs();
+ assertThat(change.get("type").newValue()).isEqualTo(VULNERABILITY);
+ assertThat(change.get("type").oldValue()).isEqualTo(BUG);
}
@Test
- public void should_execute() {
- String type = "BUG";
- Map<String, Object> properties = newHashMap();
- properties.put("type", "BUG");
- DefaultIssue issue = mock(DefaultIssue.class);
+ public void verify_fail_if_parameter_not_found() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Missing parameter : 'type'");
- Action.Context context = mock(Action.Context.class);
- when(context.issue()).thenReturn(issue);
+ action.verify(ImmutableMap.of("unknwown", VULNERABILITY.name()), Lists.newArrayList(), userSession);
+ }
+
+ @Test
+ public void verify_fail_if_type_is_invalid() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Unknown type : unknown");
- underTest.execute(properties, context);
- verify(issueUpdater).setType(eq(issue), eq(RuleType.BUG), any(IssueChangeContext.class));
+ action.verify(ImmutableMap.of("type", "unknown"), Lists.newArrayList(), userSession);
}
@Test
- public void should_verify_fail_if_parameter_not_found() {
- Map<String, Object> properties = newHashMap();
- try {
- underTest.verify(properties, Lists.newArrayList(), new AnonymousMockUserSession());
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Missing parameter: 'type'");
- }
- verifyZeroInteractions(issueUpdater);
+ public void support_only_unresolved_issues() {
+ DefaultIssue issue = newIssue().setType(BUG).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(issue.projectUuid());
+
+ assertThat(action.supports(issue.setResolution(null))).isTrue();
+ assertThat(action.supports(issue.setResolution(Issue.RESOLUTION_FIXED))).isFalse();
}
@Test
- public void should_support_only_unresolved_issues() {
- assertThat(underTest.supports(new DefaultIssue().setResolution(null))).isTrue();
- assertThat(underTest.supports(new DefaultIssue().setResolution(Issue.RESOLUTION_FIXED))).isFalse();
+ public void support_only_issues_with_issue_admin_permission() {
+ DefaultIssue authorizedIssue = newIssue().setType(BUG).toDefaultIssue();
+ setUserWithBrowseAndAdministerIssuePermission(authorizedIssue.projectUuid());
+ DefaultIssue unauthorizedIssue = newIssue().setType(BUG).toDefaultIssue();
+
+ assertThat(action.supports(authorizedIssue.setResolution(null))).isTrue();
+ assertThat(action.supports(unauthorizedIssue.setResolution(null))).isFalse();
+ }
+
+ private void setUserWithBrowseAndAdministerIssuePermission(String projectUuid) {
+ userSession.login(USER_LOGIN)
+ .addProjectUuidPermissions(ISSUE_ADMIN, projectUuid)
+ .addProjectUuidPermissions(USER, projectUuid);
+ }
+
+ private IssueDto newIssue() {
+ RuleDto rule = db.rules().insertRule(newRuleDto());
+ ComponentDto project = db.components().insertProject();
+ ComponentDto file = db.components().insertComponent(newFileDto(project));
+ return newDto(rule, file, project);
}
}
private DbClient dbClient = db.getDbClient();
private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
+ private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
private IssueStorage issueStorage = new ServerIssueStorage(system2, new DefaultRuleFinder(dbClient), dbClient, new IssueIndexer(system2, dbClient, es.client()));
private NotificationManager notificationManager = mock(NotificationManager.class);
private List<Action> actions = new ArrayList<>();
@Before
public void setUp() throws Exception {
+ issueWorkflow.start();
rule = db.rules().insertRule(newRuleDto());
project = db.components().insertProject();
file = db.components().insertComponent(newFileDto(project));
@Test
public void set_type() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
@Test
public void set_severity() throws Exception {
- setUserPermissions(USER, ISSUE_ADMIN);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setSeverity(MAJOR));
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
@Test
public void add_tags() throws Exception {
- setUserPermissions(USER, ISSUE_ADMIN);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setTags(asList("tag1", "tag2")));
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
@Test
public void remove_assignee() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setAssignee("arthur"));
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
@Test
public void bulk_change_with_comment() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
.setIssues(singletonList(issueDto.getKey()))
- .setSetType(RuleType.CODE_SMELL.name())
+ .setDoTransition("confirm")
.setComment("type was badly defined")
.build());
@Test
public void bulk_change_many_issues() throws Exception {
- setUserPermissions(USER, ISSUE_ADMIN);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
UserDto userToAssign = db.users().insertUser("arthur");
IssueDto issue1 = db.issues().insertIssue(newUnresolvedIssue().setAssignee(user.getLogin())).setType(BUG).setSeverity(MINOR);
IssueDto issue2 = db.issues().insertIssue(newUnresolvedIssue().setAssignee(userToAssign.getLogin())).setType(BUG).setSeverity(MAJOR);
@Test
public void send_notification() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
ArgumentCaptor<IssueChangeNotification> issueChangeNotificationCaptor = ArgumentCaptor.forClass(IssueChangeNotification.class);
BulkChangeWsResponse response = call(BulkChangeRequest.builder()
.setIssues(singletonList(issueDto.getKey()))
- .setSetType(RuleType.CODE_SMELL.name())
+ .setDoTransition("confirm")
.setSendNotifications(true)
.build());
@Test
public void send_notification_only_on_changed_issues() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issue1 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
IssueDto issue2 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
IssueDto issue3 = db.issues().insertIssue(newUnresolvedIssue().setType(VULNERABILITY));
@Test
public void ignore_issues_when_condition_does_not_match() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issue1 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
// These 2 issues will be ignored as they are resolved, changing type is not possible
IssueDto issue2 = db.issues().insertIssue(newResolvedIssue().setType(BUG));
@Test
public void ignore_issues_when_there_is_nothing_to_do() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issue1 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG).setSeverity(MINOR));
// These 2 issues will be ignored as there's nothing to do
IssueDto issue2 = db.issues().insertIssue(newUnresolvedIssue().setType(VULNERABILITY));
@Test
public void add_comment_only_on_changed_issues() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
IssueDto issue1 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG).setSeverity(MINOR));
// These 2 issues will be ignored as there's nothing to do
IssueDto issue2 = db.issues().insertIssue(newUnresolvedIssue().setType(VULNERABILITY));
}
@Test
- public void not_authorized_issues_are_not_taking_into_account() throws Exception {
- setUserPermissions(USER);
+ public void issues_on_which_user_has_not_browse_permission_are_ignored() throws Exception {
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
ComponentDto anotherProject = db.components().insertProject();
ComponentDto anotherFile = db.components().insertComponent(newFileDto(anotherProject));
IssueDto authorizedIssue = db.issues().insertIssue(newUnresolvedIssue(rule, file, project).setType(BUG));
- // User has no permission on these 2 issues
+ // User has not browse permission on these 2 issues
IssueDto notAuthorizedIssue1 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setType(BUG));
IssueDto notAuthorizedIssue2 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setType(BUG));
tuple(notAuthorizedIssue2.getKey(), BUG.getDbConstant(), notAuthorizedIssue2.getUpdatedAt()));
}
+ @Test
+ public void does_not_update_type_when_no_issue_admin_permission() throws Exception {
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
+ ComponentDto anotherProject = db.components().insertProject();
+ ComponentDto anotherFile = db.components().insertComponent(newFileDto(anotherProject));
+ addUserProjectPermissions(anotherProject, USER);
+
+ IssueDto authorizedIssue1 = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
+ // User has not issue admin permission on these 2 issues
+ IssueDto notAuthorizedIssue1 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setType(BUG));
+ IssueDto notAuthorizedIssue2 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setType(BUG));
+
+ BulkChangeWsResponse response = call(BulkChangeRequest.builder()
+ .setIssues(asList(authorizedIssue1.getKey(), notAuthorizedIssue1.getKey(), notAuthorizedIssue2.getKey()))
+ .setSetType(VULNERABILITY.name())
+ .build());
+
+ checkResponse(response, 3, 1, 2, 0);
+ assertThat(getIssueByKeys(authorizedIssue1.getKey(), notAuthorizedIssue1.getKey(), notAuthorizedIssue2.getKey()))
+ .extracting(IssueDto::getKey, IssueDto::getType, IssueDto::getUpdatedAt)
+ .containsOnly(
+ tuple(authorizedIssue1.getKey(), VULNERABILITY.getDbConstant(), NOW),
+ tuple(notAuthorizedIssue1.getKey(), BUG.getDbConstant(), notAuthorizedIssue1.getUpdatedAt()),
+ tuple(notAuthorizedIssue2.getKey(), BUG.getDbConstant(), notAuthorizedIssue2.getUpdatedAt()));
+ }
+
+ @Test
+ public void does_not_update_severity_when_no_issue_admin_permission() throws Exception {
+ setUserProjectPermissions(USER, ISSUE_ADMIN);
+ ComponentDto anotherProject = db.components().insertProject();
+ ComponentDto anotherFile = db.components().insertComponent(newFileDto(anotherProject));
+ addUserProjectPermissions(anotherProject, USER);
+
+ IssueDto authorizedIssue1 = db.issues().insertIssue(newUnresolvedIssue().setSeverity(MAJOR));
+ // User has not issue admin permission on these 2 issues
+ IssueDto notAuthorizedIssue1 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setSeverity(MAJOR));
+ IssueDto notAuthorizedIssue2 = db.issues().insertIssue(newUnresolvedIssue(rule, anotherFile, anotherProject).setSeverity(MAJOR));
+
+ BulkChangeWsResponse response = call(BulkChangeRequest.builder()
+ .setIssues(asList(authorizedIssue1.getKey(), notAuthorizedIssue1.getKey(), notAuthorizedIssue2.getKey()))
+ .setSetSeverity(MINOR)
+ .build());
+
+ checkResponse(response, 3, 1, 2, 0);
+ assertThat(getIssueByKeys(authorizedIssue1.getKey(), notAuthorizedIssue1.getKey(), notAuthorizedIssue2.getKey()))
+ .extracting(IssueDto::getKey, IssueDto::getSeverity, IssueDto::getUpdatedAt)
+ .containsOnly(
+ tuple(authorizedIssue1.getKey(), MINOR, NOW),
+ tuple(notAuthorizedIssue1.getKey(), MAJOR, notAuthorizedIssue1.getUpdatedAt()),
+ tuple(notAuthorizedIssue2.getKey(), MAJOR, notAuthorizedIssue2.getUpdatedAt()));
+ }
+
@Test
public void fail_when_only_comment_action() throws Exception {
- setUserPermissions(USER);
+ setUserProjectPermissions(USER);
IssueDto issueDto = db.issues().insertIssue(newUnresolvedIssue().setType(BUG));
expectedException.expectMessage("At least one action must be provided");
expectedException.expect(IllegalArgumentException.class);
}
}
- private void setUserPermissions(String... permissions) {
- UserSessionRule userSessionRule = userSession.login(user);
+ private void setUserProjectPermissions(String... permissions) {
+ userSession.login(user);
+ addUserProjectPermissions(project, permissions);
+ }
+
+ private void addUserProjectPermissions(ComponentDto project, String... permissions) {
for (String permission : permissions) {
db.users().insertProjectPermissionOnUser(user, permission, project);
- userSessionRule.addProjectUuidPermissions(permission, project.uuid());
+ userSession.addProjectUuidPermissions(permission, project.uuid());
}
}
- private void checkResponse(BulkChangeWsResponse response, int total, int success, int ignored, int failure) {
- assertThat(response.getTotal()).isEqualTo(total);
- assertThat(response.getSuccess()).isEqualTo(success);
- assertThat(response.getIgnored()).isEqualTo(ignored);
- assertThat(response.getFailures()).isEqualTo(failure);
+ private void checkResponse(BulkChangeWsResponse response, long total, long success, long ignored, long failure) {
+ assertThat(response)
+ .extracting(BulkChangeWsResponse::getTotal, BulkChangeWsResponse::getSuccess, BulkChangeWsResponse::getIgnored, BulkChangeWsResponse::getFailures)
+ .as("Total, success, ignored, failure")
+ .containsOnly(total, success, ignored, failure);
}
private List<IssueDto> getIssueByKeys(String... issueKeys) {
private void addActions() {
actions.add(new org.sonar.server.issue.AssignAction(new DefaultUserFinder(db.getDbClient().userDao()), issueFieldsSetter));
actions.add(new org.sonar.server.issue.SetSeverityAction(issueFieldsSetter, userSession));
- actions.add(new org.sonar.server.issue.SetTypeAction(issueFieldsSetter));
- actions.add(new org.sonar.server.issue.TransitionAction(new TransitionService(userSession, new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter))));
+ actions.add(new org.sonar.server.issue.SetTypeAction(issueFieldsSetter, userSession));
+ actions.add(new org.sonar.server.issue.TransitionAction(new TransitionService(userSession, issueWorkflow)));
actions.add(new org.sonar.server.issue.AddTagsAction(issueFieldsSetter));
actions.add(new org.sonar.server.issue.RemoveTagsAction(issueFieldsSetter));
actions.add(new org.sonar.server.issue.CommentAction(issueFieldsSetter));
*/
package org.sonar.server.issue.ws;
+import java.util.Arrays;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.web.UserRole;
import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_SEARCH;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.CONTROLLER_ISSUES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_MODE_DEBT;
db.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com"));
db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("PROJECT_KEY").setLanguage("java"));
- setDefaultProjectPermission(project);
ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, null, "FILE_ID").setKey("FILE_KEY").setLanguage("js"));
+ setProjectPermission(project, USER);
IssueDto issue = IssueTesting.newDto(newRule(), file, project)
.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
session.commit();
tester.get(IssueIndexer.class).indexAll();
- userSessionRule.login("john");
WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, ACTION_SEARCH)
.setParam("additionalFields", "_all").execute();
result.assertJson(this.getClass(), "load_additional_fields.json");
}
+ @Test
+ public void load_additional_fields_with_issue_admin_permission() throws Exception {
+ db.userDao().insert(session, new UserDto().setLogin("simon").setName("Simon").setEmail("simon@email.com"));
+ db.userDao().insert(session, new UserDto().setLogin("fabrice").setName("Fabrice").setEmail("fabrice@email.com"));
+ ComponentDto project = insertComponent(ComponentTesting.newProjectDto("PROJECT_ID").setKey("PROJECT_KEY").setLanguage("java"));
+ ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, null, "FILE_ID").setKey("FILE_KEY").setLanguage("js"));
+ setProjectPermission(project, USER, ISSUE_ADMIN);
+
+ IssueDto issue = IssueTesting.newDto(newRule(), file, project)
+ .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
+ .setAuthorLogin("John")
+ .setAssignee("simon");
+ db.issueDao().insert(session, issue);
+ session.commit();
+ tester.get(IssueIndexer.class).indexAll();
+
+ WsTester.Result result = wsTester.newGetRequest(CONTROLLER_ISSUES, ACTION_SEARCH)
+ .setParam("additionalFields", "_all").execute();
+ result.assertJson(this.getClass(), "load_additional_fields_with_issue_admin_permission.json");
+ }
+
@Test
public void issue_on_removed_file() throws Exception {
RuleDto rule = newRule();
tester.get(PermissionUpdater.class).apply(session, asList(permissionChange));
}
+ private void setProjectPermission(ComponentDto project, String... permissions) {
+ // project can be seen by anyone and by code viewer
+ userSessionRule.login("admin");
+ Arrays.stream(permissions).forEach(permission -> userSessionRule.addProjectUuidPermissions(permission, project.uuid()));
+ tester.get(PermissionUpdater.class).apply(session, Arrays.stream(permissions)
+ // TODO correctly feed default organization. Not a problem as long as issues search does not support "anyone" for each organization
+ .map(permission -> new GroupPermissionChange(PermissionChange.Operation.ADD, permission, new ProjectId(project), GroupIdOrAnyone.forAnyone("TODO")))
+ .collect(Collectors.toList()));
+ }
+
private ComponentDto insertComponent(ComponentDto component) {
db.componentDao().insert(session, component);
session.commit();
*/
package org.sonar.server.issue.ws;
+import java.util.List;
+import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonar.api.config.MapSettings;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.ws.WsAction;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.core.issue.FieldDiffs;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.issue.IssueDbTester;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.IssueFinder;
+import org.sonar.server.issue.IssueUpdater;
+import org.sonar.server.issue.ServerIssueStorage;
+import org.sonar.server.issue.index.IssueIndexDefinition;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.notification.NotificationManager;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.sonar.api.rule.Severity.MAJOR;
+import static org.sonar.api.rule.Severity.MINOR;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.issue.IssueTesting.newDto;
+import static org.sonar.db.rule.RuleTesting.newRuleDto;
public class SetSeverityActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- IssueService issueService = mock(IssueService.class);
- OperationResponseWriter responseWriter = mock(OperationResponseWriter.class);
- WsAction underTest = new SetSeverityAction(issueService, responseWriter);
- WsActionTester tester = new WsActionTester(underTest);
+ @Rule
+ public DbTester dbTester = DbTester.create();
+
+ @Rule
+ public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()));
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ private System2 system2 = mock(System2.class);
+
+ private DbClient dbClient = dbTester.getDbClient();
+
+ private IssueDbTester issueDbTester = new IssueDbTester(dbTester);
+
+ private OperationResponseWriter responseWriter = mock(OperationResponseWriter.class);
+
+ private WsActionTester tester = new WsActionTester(new SetSeverityAction(userSession, dbClient, new IssueFinder(dbClient, userSession), new IssueFieldsSetter(),
+ new IssueUpdater(dbClient,
+ new ServerIssueStorage(system2, new DefaultRuleFinder(dbClient), dbClient, new IssueIndexer(system2, dbClient, esTester.client())), mock(NotificationManager.class)),
+ responseWriter));
@Test
public void set_severity() throws Exception {
- tester.newRequest()
- .setParam("issue", "ABC")
- .setParam("severity", "BLOCKER")
- .execute();
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setSeverity(MAJOR));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
+ call(issueDto.getKey(), MINOR);
- verify(issueService).setSeverity("ABC", "BLOCKER");
- verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class));
+ verify(responseWriter).write(eq(issueDto.getKey()), any(Request.class), any(Response.class));
+ IssueDto issueReloaded = dbClient.issueDao().selectByKey(dbTester.getSession(), issueDto.getKey()).get();
+ assertThat(issueReloaded.getSeverity()).isEqualTo(MINOR);
+ assertThat(issueReloaded.isManualSeverity()).isTrue();
}
@Test
- public void fail_if_bad_severity_value() {
+ public void insert_entry_in_changelog_when_setting_severity() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setSeverity(MAJOR));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
+ call(issueDto.getKey(), MINOR);
+
+ List<FieldDiffs> fieldDiffs = dbClient.issueChangeDao().selectChangelogByIssue(dbTester.getSession(), issueDto.getKey());
+ assertThat(fieldDiffs).hasSize(1);
+ assertThat(fieldDiffs.get(0).diffs()).hasSize(1);
+ assertThat(fieldDiffs.get(0).diffs().get("severity").newValue()).isEqualTo(MINOR);
+ assertThat(fieldDiffs.get(0).diffs().get("severity").oldValue()).isEqualTo(MAJOR);
+ }
+
+ @Test
+ public void fail_if_bad_severity() {
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setSeverity("unknown"));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Value of parameter 'severity' (unknown) must be one of: [INFO, MINOR, MAJOR, CRITICAL, BLOCKER]");
+ call(issueDto.getKey(), "unknown");
+ }
+
+ @Test
+ public void fail_when_not_authenticated() throws Exception {
+ expectedException.expect(UnauthorizedException.class);
+ call("ABCD", MAJOR);
+ }
+
+ @Test
+ public void fail_when_missing_browse_permission() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue();
+ userSession.login("john").addProjectUuidPermissions(ISSUE_ADMIN, issueDto.getProjectUuid());
+
+ expectedException.expect(ForbiddenException.class);
+ call(issueDto.getKey(), MAJOR);
+ }
+
+ @Test
+ public void fail_when_missing_administer_issue_permission() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue();
+ userSession.login("john").addProjectUuidPermissions(USER, issueDto.getProjectUuid());
+
+ expectedException.expect(ForbiddenException.class);
+ call(issueDto.getKey(), MAJOR);
+ }
+
+ @Test
+ public void test_definition() {
+ WebService.Action action = tester.getDef();
+ assertThat(action.key()).isEqualTo("set_severity");
+ assertThat(action.isPost()).isTrue();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.params()).hasSize(2);
+ assertThat(action.responseExample()).isNotNull();
+ }
+
+ private TestResponse call(@Nullable String issueKey, @Nullable String severity) {
+ TestRequest request = tester.newRequest();
+ setNullable(issueKey, issue -> request.setParam("issue", issue));
+ setNullable(severity, value -> request.setParam("severity", value));
+ return request.execute();
+ }
+
+ private IssueDto newIssue() {
+ RuleDto rule = dbTester.rules().insertRule(newRuleDto());
+ ComponentDto project = dbTester.components().insertProject();
+ ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
+ return newDto(rule, file, project);
+ }
- tester.newRequest()
- .setParam("issue", "ABC")
- .setParam("severity", "WAT")
- .execute();
+ private void setUserWithBrowseAndAdministerIssuePermission(String projectUuid) {
+ userSession.login("john")
+ .addProjectUuidPermissions(ISSUE_ADMIN, projectUuid)
+ .addProjectUuidPermissions(USER, projectUuid);
}
}
*/
package org.sonar.server.issue.ws;
+import java.util.List;
+import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.rules.RuleType;
+import org.sonar.api.config.MapSettings;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.ws.WsAction;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.core.issue.FieldDiffs;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.issue.IssueDbTester;
+import org.sonar.db.issue.IssueDto;
+import org.sonar.db.rule.RuleDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.IssueFinder;
+import org.sonar.server.issue.IssueUpdater;
+import org.sonar.server.issue.ServerIssueStorage;
+import org.sonar.server.issue.index.IssueIndexDefinition;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.notification.NotificationManager;
+import org.sonar.server.rule.DefaultRuleFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
+import static org.sonar.api.rules.RuleType.BUG;
+import static org.sonar.api.rules.RuleType.CODE_SMELL;
+import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.db.component.ComponentTesting.newFileDto;
+import static org.sonar.db.issue.IssueTesting.newDto;
+import static org.sonar.db.rule.RuleTesting.newRuleDto;
public class SetTypeActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- IssueService issueService = mock(IssueService.class);
- OperationResponseWriter responseWriter = mock(OperationResponseWriter.class);
- WsAction underTest = new SetTypeAction(issueService, responseWriter);
- WsActionTester tester = new WsActionTester(underTest);
+ @Rule
+ public DbTester dbTester = DbTester.create();
+
+ @Rule
+ public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings()));
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ private System2 system2 = mock(System2.class);
+
+ private DbClient dbClient = dbTester.getDbClient();
+
+ private IssueDbTester issueDbTester = new IssueDbTester(dbTester);
+
+ private OperationResponseWriter responseWriter = mock(OperationResponseWriter.class);
+
+ private WsActionTester tester = new WsActionTester(new SetTypeAction(userSession, dbClient, new IssueFinder(dbClient, userSession), new IssueFieldsSetter(),
+ new IssueUpdater(dbClient,
+ new ServerIssueStorage(system2, new DefaultRuleFinder(dbClient), dbClient, new IssueIndexer(system2, dbClient, esTester.client())), mock(NotificationManager.class)),
+ responseWriter));
@Test
public void set_type() throws Exception {
- tester.newRequest()
- .setParam("issue", "ABC")
- .setParam("type", "BUG")
- .execute();
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(CODE_SMELL));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
+ call(issueDto.getKey(), BUG.name());
- verify(issueService).setType("ABC", RuleType.BUG);
- verify(responseWriter).write(eq("ABC"), any(Request.class), any(Response.class));
+ verify(responseWriter).write(eq(issueDto.getKey()), any(Request.class), any(Response.class));
+ IssueDto issueReloaded = dbClient.issueDao().selectByKey(dbTester.getSession(), issueDto.getKey()).get();
+ assertThat(issueReloaded.getType()).isEqualTo(BUG.getDbConstant());
+ }
+
+ @Test
+ public void insert_entry_in_changelog_when_setting_type() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(CODE_SMELL));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
+ call(issueDto.getKey(), BUG.name());
+
+ List<FieldDiffs> fieldDiffs = dbClient.issueChangeDao().selectChangelogByIssue(dbTester.getSession(), issueDto.getKey());
+ assertThat(fieldDiffs).hasSize(1);
+ assertThat(fieldDiffs.get(0).diffs()).hasSize(1);
+ assertThat(fieldDiffs.get(0).diffs().get("type").newValue()).isEqualTo(BUG.name());
+ assertThat(fieldDiffs.get(0).diffs().get("type").oldValue()).isEqualTo(CODE_SMELL.name());
}
@Test
public void fail_if_bad_type_value() {
+ IssueDto issueDto = issueDbTester.insertIssue(newIssue().setType(CODE_SMELL));
+ setUserWithBrowseAndAdministerIssuePermission(issueDto.getProjectUuid());
+
expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Value of parameter 'type' (unknown) must be one of: [CODE_SMELL, BUG, VULNERABILITY]");
+ call(issueDto.getKey(), "unknown");
+ }
+
+ @Test
+ public void fail_when_not_authenticated() throws Exception {
+ expectedException.expect(UnauthorizedException.class);
+ call("ABCD", BUG.name());
+ }
+
+ @Test
+ public void fail_when_missing_browse_permission() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue();
+ userSession.login("john").addProjectUuidPermissions(ISSUE_ADMIN, issueDto.getProjectUuid());
+
+ expectedException.expect(ForbiddenException.class);
+ call(issueDto.getKey(), BUG.name());
+ }
+
+ @Test
+ public void fail_when_missing_administer_issue_permission() throws Exception {
+ IssueDto issueDto = issueDbTester.insertIssue();
+ userSession.login("john").addProjectUuidPermissions(USER, issueDto.getProjectUuid());
+
+ expectedException.expect(ForbiddenException.class);
+ call(issueDto.getKey(), BUG.name());
+ }
+
+ @Test
+ public void test_definition() {
+ WebService.Action action = tester.getDef();
+ assertThat(action.key()).isEqualTo("set_type");
+ assertThat(action.isPost()).isTrue();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.params()).hasSize(2);
+ assertThat(action.responseExample()).isNotNull();
+ }
+
+ private TestResponse call(@Nullable String issueKey, @Nullable String type) {
+ TestRequest request = tester.newRequest();
+ setNullable(issueKey, issue -> request.setParam("issue", issue));
+ setNullable(type, t -> request.setParam("type", t));
+ return request.execute();
+ }
+
+ private IssueDto newIssue() {
+ RuleDto rule = dbTester.rules().insertRule(newRuleDto());
+ ComponentDto project = dbTester.components().insertProject();
+ ComponentDto file = dbTester.components().insertComponent(newFileDto(project));
+ return newDto(rule, file, project);
+ }
- tester.newRequest()
- .setParam("issue", "ABC")
- .setParam("severity", "WAT")
- .execute();
+ private void setUserWithBrowseAndAdministerIssuePermission(String projectUuid) {
+ userSession.login("john")
+ .addProjectUuidPermissions(ISSUE_ADMIN, projectUuid)
+ .addProjectUuidPermissions(USER, projectUuid);
}
}
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
"assignee": "simon",
"actions": [
- "comment", "assign", "set_tags", "set_type", "assign_to_me"
+ "comment",
+ "assign",
+ "set_tags",
+ "assign_to_me"
],
"transitions": [
- "confirm", "resolve"
+ "confirm",
+ "resolve"
]
}
],
"name": "Simon",
"email": "simon@email.com",
"active": true
+ },
+ {
+ "login": "admin",
+ "name": "Administrator",
+ "email": "",
+ "active": true
}
]
}
--- /dev/null
+{
+ "issues": [
+ {
+ "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
+ "assignee": "simon",
+ "actions": [
+ "comment",
+ "assign",
+ "set_tags",
+ "assign_to_me",
+ "set_type",
+ "set_severity"
+ ],
+ "transitions": [
+ "confirm",
+ "resolve",
+ "falsepositive",
+ "wontfix"
+ ],
+ }
+ ],
+ "users": [
+ {
+ "login": "simon",
+ "name": "Simon",
+ "email": "simon@email.com",
+ "active": true
+ },
+ {
+ "login": "admin",
+ "name": "Administrator",
+ "email": "",
+ "active": true
+ }
+ ]
+}