]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12723 remove hotspots from issues API
authorJacek <jacek.poreda@sonarsource.com>
Wed, 11 Dec 2019 15:35:02 +0000 (16:35 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 13 Jan 2020 19:46:33 +0000 (20:46 +0100)
server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/IssueFinder.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/EditCommentActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java [deleted file]
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java

index c700eef43303fc070c60659b64a10315d654e5c4..2a921520f238322de157094838c8f12130ea23a4 100644 (file)
@@ -19,7 +19,9 @@
  */
 package org.sonar.db.issue;
 
+import java.util.Arrays;
 import java.util.Date;
+import java.util.Random;
 import org.apache.commons.lang.math.RandomUtils;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.resources.Qualifiers;
@@ -40,6 +42,8 @@ import static org.apache.commons.lang.math.RandomUtils.nextInt;
 import static org.apache.commons.lang.math.RandomUtils.nextLong;
 
 public class IssueTesting {
+  private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOTS = Arrays.stream(RuleType.values())
+    .filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);
 
   private IssueTesting() {
     // only statics
@@ -52,7 +56,7 @@ public class IssueTesting {
     return new IssueDto()
       .setKee("uuid_" + randomAlphabetic(5))
       .setRule(rule)
-      .setType(RuleType.values()[nextInt(RuleType.values().length)])
+      .setType(RULE_TYPES_EXCEPT_HOTSPOTS[new Random().nextInt(RULE_TYPES_EXCEPT_HOTSPOTS.length)])
       .setProject(project)
       .setComponent(file)
       .setStatus(Issue.STATUS_OPEN)
index 2c813e77e1da5ac10b5481109896fa37176dc58e..063e0359daa875429c8d573dd353489bef5a823c 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.issue;
 
+import org.sonar.api.rules.RuleType;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -28,6 +29,7 @@ import org.sonar.server.user.UserSession;
 
 import static java.lang.String.format;
 import static java.util.Objects.requireNonNull;
+import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
 
 public class IssueFinder {
 
@@ -41,6 +43,12 @@ public class IssueFinder {
 
   public IssueDto getByKey(DbSession session, String issueKey) {
     IssueDto issue = dbClient.issueDao().selectByKey(session, issueKey).orElseThrow(() -> new NotFoundException(format("Issue with key '%s' does not exist", issueKey)));
+
+    RuleType ruleType = RuleType.valueOfNullable(issue.getType());
+    if (SECURITY_HOTSPOT.equals(ruleType)) {
+      throw new NotFoundException(format("Issue with key '%s' does not exist", issueKey));
+    }
+
     userSession.checkComponentUuidPermission(UserRole.USER, requireNonNull(issue.getProjectUuid()));
     return issue;
   }
index e51e384c0e5aa764eac65be0d1fd7f1319d43064..9b217558ea1afa49192250c39fd743f6990bb9d0 100644 (file)
@@ -19,7 +19,6 @@
  */
 package org.sonar.server.issue.ws;
 
-import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import java.util.ArrayList;
@@ -27,14 +26,11 @@ import java.util.Arrays;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.search.SearchHit;
-import org.sonar.api.Startable;
-import org.sonar.api.config.Configuration;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.server.ws.Change;
@@ -47,7 +43,6 @@ import org.sonar.api.utils.System2;
 import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.user.UserDto;
 import org.sonar.server.es.Facets;
 import org.sonar.server.es.SearchOptions;
@@ -81,7 +76,6 @@ import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
 import static org.sonar.api.server.ws.WebService.Param.FACETS;
 import static org.sonar.api.utils.Paging.forPageIndex;
 import static org.sonar.core.util.stream.MoreCollectors.toSet;
-import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
 import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
 import static org.sonar.server.issue.index.IssueIndex.FACET_ASSIGNED_TO_ME;
 import static org.sonar.server.issue.index.IssueIndex.FACET_PROJECTS;
@@ -135,9 +129,10 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TYPES;
 
-public class SearchAction implements IssuesWsAction, Startable {
+public class SearchAction implements IssuesWsAction {
 
   private static final String LOGIN_MYSELF = "__me__";
+  private static final EnumSet<RuleType> ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS = EnumSet.complementOf(EnumSet.of(RuleType.SECURITY_HOTSPOT));
 
   static final List<String> SUPPORTED_FACETS = ImmutableList.of(
     FACET_PROJECTS,
@@ -163,26 +158,22 @@ public class SearchAction implements IssuesWsAction, Startable {
 
   private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. ";
   private static final Set<String> FACETS_REQUIRING_PROJECT_OR_ORGANIZATION = newHashSet(PARAM_MODULE_UUIDS, PARAM_FILE_UUIDS, PARAM_DIRECTORIES);
-  private static final Joiner COMA_JOINER = Joiner.on(",");
 
   private final UserSession userSession;
   private final IssueIndex issueIndex;
   private final IssueQueryFactory issueQueryFactory;
   private final SearchResponseLoader searchResponseLoader;
   private final SearchResponseFormat searchResponseFormat;
-  private final Configuration config;
   private final System2 system2;
   private final DbClient dbClient;
-  private boolean isOnSonarCloud;
 
   public SearchAction(UserSession userSession, IssueIndex issueIndex, IssueQueryFactory issueQueryFactory, SearchResponseLoader searchResponseLoader,
-    SearchResponseFormat searchResponseFormat, Configuration config, System2 system2, DbClient dbClient) {
+    SearchResponseFormat searchResponseFormat, System2 system2, DbClient dbClient) {
     this.userSession = userSession;
     this.issueIndex = issueIndex;
     this.issueQueryFactory = issueQueryFactory;
     this.searchResponseLoader = searchResponseLoader;
     this.searchResponseFormat = searchResponseFormat;
-    this.config = config;
     this.system2 = system2;
     this.dbClient = dbClient;
   }
@@ -199,8 +190,10 @@ public class SearchAction implements IssuesWsAction, Startable {
         PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS)
       .setSince("3.6")
       .setChangelog(
-        new Change("8.1", "response field 'fromHotspot' has been deprecated and is no more populated"),
-        new Change("8.1", format("Status %s for Security Hotspots has been deprecated", STATUS_IN_REVIEW)),
+        new Change("8.2", "'REVIEWED', 'TO_REVIEW' status param values are no longer supported"),
+        new Change("8.2", "Security hotspots are no longer returned"),
+        new Change("8.2", "response field 'fromHotspot' has been deprecated and is no more populated"),
+        new Change("8.2", format("Status %s for Security Hotspots has been deprecated", STATUS_IN_REVIEW)),
         new Change("7.8", format("added new Security Hotspots statuses : %s, %s and %s", STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)),
         new Change("7.8", "Security hotspots are returned by default"),
         new Change("7.7", format("Value '%s' in parameter '%s' is deprecated, please use '%s' instead", DEPRECATED_PARAM_AUTHORS, FACETS, PARAM_AUTHOR)),
@@ -261,7 +254,7 @@ public class SearchAction implements IssuesWsAction, Startable {
     action.createParam(PARAM_TYPES)
       .setDescription("Comma-separated list of types.")
       .setSince("5.5")
-      .setPossibleValues(RuleType.values())
+      .setPossibleValues(ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS)
       .setExampleValue(format("%s,%s", RuleType.CODE_SMELL, RuleType.BUG));
     action.createParam(PARAM_OWASP_TOP_10)
       .setDescription("Comma-separated list of OWASP Top 10 lowercase categories.")
@@ -391,14 +384,14 @@ public class SearchAction implements IssuesWsAction, Startable {
   public final void handle(Request request, Response response) {
     try (DbSession dbSession = dbClient.openSession(false)) {
       SearchRequest searchRequest = toSearchWsRequest(dbSession, request);
-      SearchWsResponse searchWsResponse = doHandle(dbSession, searchRequest);
+      SearchWsResponse searchWsResponse = doHandle(searchRequest);
       writeProtobuf(searchWsResponse, request, response);
     }
   }
 
-  private SearchWsResponse doHandle(DbSession dbSession, SearchRequest request) {
+  private SearchWsResponse doHandle(SearchRequest request) {
     // prepare the Elasticsearch request
-    SearchOptions options = createSearchOptionsFromRequest(dbSession, request);
+    SearchOptions options = createSearchOptionsFromRequest(request);
     EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request);
     IssueQuery query = issueQueryFactory.create(request);
 
@@ -407,7 +400,7 @@ public class SearchAction implements IssuesWsAction, Startable {
       .collect(toSet());
     checkArgument(facetsRequiringProjectOrOrganizationParameter.isEmpty() ||
       (!query.projectUuids().isEmpty()) || query.organizationUuid() != null, "Facet(s) '%s' require to also filter by project or organization",
-      COMA_JOINER.join(facetsRequiringProjectOrOrganizationParameter));
+      String.join(",", facetsRequiringProjectOrOrganizationParameter));
 
     // execute request
     SearchResponse result = issueIndex.search(query, options);
@@ -436,7 +429,7 @@ public class SearchAction implements IssuesWsAction, Startable {
     return searchResponseFormat.formatSearch(additionalFields, data, paging, facets);
   }
 
-  private SearchOptions createSearchOptionsFromRequest(DbSession dbSession, SearchRequest request) {
+  private SearchOptions createSearchOptionsFromRequest(SearchRequest request) {
     SearchOptions options = new SearchOptions();
     options.setPage(request.getPage(), request.getPageSize());
 
@@ -446,29 +439,13 @@ public class SearchAction implements IssuesWsAction, Startable {
       return options;
     }
 
-    List<String> requestedFacets = new ArrayList<>(facets);
-    if (isOnSonarCloud) {
-      Optional<OrganizationDto> organizationDto = Optional.empty();
-      String organizationKey = request.getOrganization();
-      if (organizationKey != null) {
-        organizationDto = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
-      }
-
-      if (!organizationDto.isPresent() || !userSession.hasMembership(organizationDto.get())) {
-        // In order to display the authors facet, the organization parameter must be set and the user
-        // must be member of this organization
-        requestedFacets.remove(PARAM_AUTHOR);
-        requestedFacets.remove(DEPRECATED_PARAM_AUTHORS);
-      }
-    }
-
-    options.addFacets(requestedFacets);
+    options.addFacets(facets);
     return options;
   }
 
   private void completeFacets(Facets facets, SearchRequest request, IssueQuery query) {
     addMandatoryValuesToFacet(facets, PARAM_SEVERITIES, Severity.ALL);
-    addMandatoryValuesToFacet(facets, PARAM_STATUSES, STATUSES);
+    addMandatoryValuesToFacet(facets, PARAM_STATUSES, STATUSES.stream().filter(s -> !STATUS_TO_REVIEW.equals(s)).filter(s -> !STATUS_REVIEWED.equals(s)).collect(toList()));
     addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), RESOLUTIONS));
     addMandatoryValuesToFacet(facets, FACET_PROJECTS, query.projectUuids());
     addMandatoryValuesToFacet(facets, PARAM_MODULE_UUIDS, query.moduleUuids());
@@ -486,13 +463,23 @@ public class SearchAction implements IssuesWsAction, Startable {
     addMandatoryValuesToFacet(facets, PARAM_RULES, query.rules().stream().map(IssueDoc::formatRuleId).collect(toList()));
     addMandatoryValuesToFacet(facets, PARAM_LANGUAGES, request.getLanguages());
     addMandatoryValuesToFacet(facets, PARAM_TAGS, request.getTags());
-    addMandatoryValuesToFacet(facets, PARAM_TYPES, RuleType.names());
+
+    setTypesFacet(facets);
+
     addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10, request.getOwaspTop10());
     addMandatoryValuesToFacet(facets, PARAM_SANS_TOP_25, request.getSansTop25());
     addMandatoryValuesToFacet(facets, PARAM_CWE, request.getCwe());
     addMandatoryValuesToFacet(facets, PARAM_SONARSOURCE_SECURITY, request.getSonarsourceSecurity());
   }
 
+  private void setTypesFacet(Facets facets) {
+    Map<String, Long> typeFacet = facets.get(PARAM_TYPES);
+    if (typeFacet != null) {
+      typeFacet.remove(RuleType.SECURITY_HOTSPOT.name());
+    }
+    addMandatoryValuesToFacet(facets, PARAM_TYPES, ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS.stream().map(Enum::name).collect(Collectors.toList()));
+  }
+
   private static void addMandatoryValuesToFacet(Facets facets, String facetName, @Nullable Iterable<String> mandatoryValues) {
     Map<String, Long> buckets = facets.get(facetName);
     if (buckets != null && mandatoryValues != null) {
@@ -562,13 +549,20 @@ public class SearchAction implements IssuesWsAction, Startable {
       .setSeverities(request.paramAsStrings(PARAM_SEVERITIES))
       .setStatuses(request.paramAsStrings(PARAM_STATUSES))
       .setTags(request.paramAsStrings(PARAM_TAGS))
-      .setTypes(request.paramAsStrings(PARAM_TYPES))
+      .setTypes(allRuleTypesExceptHotspotsIfEmpty(request.paramAsStrings(PARAM_TYPES)))
       .setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
       .setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
       .setCwe(request.paramAsStrings(PARAM_CWE))
       .setSonarsourceSecurity(request.paramAsStrings(PARAM_SONARSOURCE_SECURITY));
   }
 
+  private List<String> allRuleTypesExceptHotspotsIfEmpty(@Nullable List<String> types) {
+    if (types == null || types.isEmpty()) {
+      return ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS.stream().map(Enum::name).collect(toList());
+    }
+    return types;
+  }
+
   private List<String> getLogins(DbSession dbSession, @Nullable List<String> assigneeLogins) {
     List<String> userLogins = new ArrayList<>();
 
@@ -592,14 +586,4 @@ public class SearchAction implements IssuesWsAction, Startable {
     }
     return assigneeUuid;
   }
-
-  @Override
-  public void start() {
-    this.isOnSonarCloud = config.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false);
-  }
-
-  @Override
-  public void stop() {
-    // Nothing to do
-  }
 }
index b97344b5c963cacdccb16bafbd87dce22de1dd9c..80310ccd178e3b43cf95ea6c72fdbb861918b55e 100644 (file)
  */
 package org.sonar.server.issue.ws;
 
+import java.util.Arrays;
+import java.util.Random;
 import javax.annotation.Nullable;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.ArgumentCaptor;
+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;
@@ -57,6 +60,8 @@ import static org.sonar.api.web.UserRole.USER;
 public class EditCommentActionTest {
 
   private static final long NOW = 10_000_000_000L;
+  private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOTS = Arrays.stream(RuleType.values())
+    .filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);
 
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
@@ -81,7 +86,7 @@ public class EditCommentActionTest {
 
   @Test
   public void edit_comment() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
     loginWithBrowsePermission(user, USER, issueDto);
@@ -98,7 +103,7 @@ public class EditCommentActionTest {
 
   @Test
   public void edit_comment_using_deprecated_key_parameter() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
     loginWithBrowsePermission(user, USER, issueDto);
@@ -115,7 +120,7 @@ public class EditCommentActionTest {
 
   @Test
   public void fail_when_comment_does_not_belong_to_current_user() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
     UserDto another = dbTester.users().insertUser();
@@ -128,7 +133,7 @@ public class EditCommentActionTest {
 
   @Test
   public void fail_when_comment_has_not_user() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, null, "please fix it");
     loginWithBrowsePermission(user, USER, issueDto);
@@ -164,7 +169,7 @@ public class EditCommentActionTest {
 
   @Test
   public void fail_when_empty_comment_text() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
     loginWithBrowsePermission(user, USER, issueDto);
@@ -181,7 +186,7 @@ public class EditCommentActionTest {
 
   @Test
   public void fail_when_not_enough_permission() {
-    IssueDto issueDto = issueDbTester.insertIssue();
+    IssueDto issueDto = newIssue();
     UserDto user = dbTester.users().insertUser();
     IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
     loginWithBrowsePermission(user, CODEVIEWER, issueDto);
@@ -190,6 +195,18 @@ public class EditCommentActionTest {
     call(commentDto.getKey(), "please have a look");
   }
 
+  @Test
+  public void fail_NFE_if_security_hotspots() {
+    IssueDto issueDto = issueDbTester.insertIssue(i -> i.setType(RuleType.SECURITY_HOTSPOT));
+    UserDto user = dbTester.users().insertUser();
+    IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
+    loginWithBrowsePermission(user, CODEVIEWER, issueDto);
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(String.format("Issue with key '%s' does not exist", issueDto.getKey()));
+    call(commentDto.getKey(), "please have a look");
+  }
+
   @Test
   public void test_definition() {
     WebService.Action action = tester.getDef();
@@ -207,6 +224,10 @@ public class EditCommentActionTest {
     return request.execute();
   }
 
+  private IssueDto newIssue() {
+    return issueDbTester.insertIssue(i -> i.setType(RULE_TYPES_EXCEPT_HOTSPOTS[new Random().nextInt(RULE_TYPES_EXCEPT_HOTSPOTS.length)]));
+  }
+
   private void loginWithBrowsePermission(UserDto user, String permission, IssueDto issueDto) {
     userSession.logIn(user).addProjectPermission(permission,
       dbClient.componentDao().selectByUuid(dbTester.getSession(), issueDto.getProjectUuid()).get(),
index 418a6f6cebb29f1b8721f4d59fe565b967c19011..ed890d9f9c09c75a0ec01d8267498e8f4a09bc83 100644 (file)
@@ -25,7 +25,6 @@ import java.util.Date;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.rule.RuleKey;
@@ -110,7 +109,7 @@ public class SearchActionComponentsTest {
   private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
 
   private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
-    new MapSettings().asConfig(), System2.INSTANCE, dbClient));
+    System2.INSTANCE, dbClient));
 
   @Test
   public void search_all_issues_when_no_parameter() {
@@ -169,12 +168,12 @@ public class SearchActionComponentsTest {
     assertThat(ws.newRequest()
       .setParam(PARAM_COMPONENT_KEYS, module1.getKey())
       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
-      .containsExactlyInAnyOrder(issue1.getKey());
+        .containsExactlyInAnyOrder(issue1.getKey());
 
     assertThat(ws.newRequest()
       .setParam(PARAM_MODULE_UUIDS, module1.uuid())
       .executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
-      .containsExactlyInAnyOrder(issue1.getKey());
+        .containsExactlyInAnyOrder(issue1.getKey());
   }
 
   @Test
@@ -482,11 +481,11 @@ public class SearchActionComponentsTest {
       .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
       .executeProtobuf(SearchWsResponse.class).getIssuesList())
-      .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
-      .containsExactlyInAnyOrder(
-        tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
-        tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
-        tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
+        .extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
+        .containsExactlyInAnyOrder(
+          tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
+          tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
+          tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
 
     // Issues on project1Branch1
     assertThat(ws.newRequest()
@@ -494,10 +493,10 @@ public class SearchActionComponentsTest {
       .setParam(PARAM_PROJECTS, project1.getKey())
       .setParam(PARAM_BRANCH, applicationBranch1.getBranch())
       .executeProtobuf(SearchWsResponse.class).getIssuesList())
-      .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
-      .containsExactlyInAnyOrder(
-        tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
-        tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
+        .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
+        .containsExactlyInAnyOrder(
+          tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
+          tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
   }
 
   @Test
@@ -668,24 +667,24 @@ public class SearchActionComponentsTest {
       .setParam(PARAM_COMPONENT_KEYS, project.getKey())
       .setParam(PARAM_BRANCH, branch.getBranch())
       .executeProtobuf(SearchWsResponse.class).getIssuesList())
-      .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
-      .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
+        .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
+        .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
 
     // On project key + branch
     assertThat(ws.newRequest()
       .setParam(PARAM_PROJECT_KEYS, project.getKey())
       .setParam(PARAM_BRANCH, branch.getBranch())
       .executeProtobuf(SearchWsResponse.class).getIssuesList())
-      .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
-      .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
+        .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
+        .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
 
     // On file key + branch
     assertThat(ws.newRequest()
       .setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
       .setParam(PARAM_BRANCH, branch.getBranch())
       .executeProtobuf(SearchWsResponse.class).getIssuesList())
-      .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
-      .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
+        .extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
+        .containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
   }
 
   @Test
index f9efa1812a0640abad81daf4d06deac8fe717bdd..0ae6fd93ab360aa58dac956959914adf7963a616 100644 (file)
@@ -21,12 +21,14 @@ package org.sonar.server.issue.ws;
 
 import com.google.common.collect.ImmutableMap;
 import java.time.Clock;
+import java.util.Arrays;
 import java.util.Map;
+import java.util.Random;
 import java.util.stream.IntStream;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.issue.Issue;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.rules.RuleType;
 import org.sonar.api.server.ws.WebService;
@@ -73,6 +75,10 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;
 
 public class SearchActionFacetsTest {
 
+  private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOT = Arrays.stream(RuleType.values()).filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);
+  private static final String[] ISSUE_STATUSES = Issue.STATUSES.stream().filter(s -> !Issue.STATUS_TO_REVIEW.equals(s)).filter(s -> !Issue.STATUS_REVIEWED.equals(s))
+    .toArray(String[]::new);
+
   @Rule
   public UserSessionRule userSession = standalone();
   @Rule
@@ -92,8 +98,7 @@ public class SearchActionFacetsTest {
   private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
 
   private WsActionTester ws = new WsActionTester(
-    new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
-      new MapSettings().asConfig(), System2.INSTANCE, db.getDbClient()));
+    new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, System2.INSTANCE, db.getDbClient()));
 
   @Test
   public void display_all_facets() {
@@ -117,7 +122,7 @@ public class SearchActionFacetsTest {
       .executeProtobuf(SearchWsResponse.class);
 
     Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L)
-      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
+      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();
 
     assertThat(response.getFacets().getFacetsList())
       .extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -126,7 +131,7 @@ public class SearchActionFacetsTest {
         tuple("statuses", expectedStatuses),
         tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
         tuple("rules", of(rule.getKey().toString(), 1L)),
-        tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
+        tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L)),
         tuple("languages", of(rule.getLanguage(), 1L)),
         tuple("projects", of(project.getKey(), 1L)),
         tuple("moduleUuids", of(module.uuid(), 1L)),
@@ -155,7 +160,7 @@ public class SearchActionFacetsTest {
       .executeProtobuf(SearchWsResponse.class);
 
     Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 10L).put("CONFIRMED", 0L)
-      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
+      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();
 
     assertThat(response.getFacets().getFacetsList())
       .extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -164,7 +169,7 @@ public class SearchActionFacetsTest {
         tuple("statuses", expectedStatuses),
         tuple("resolutions", of("", 10L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
         tuple("rules", of(rule.getKey().toString(), 10L)),
-        tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
+        tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L)),
         tuple("languages", of(rule.getLanguage(), 10L)),
         tuple("projects", of(project.getKey(), 10L)),
         tuple("fileUuids", of(file.uuid(), 10L)),
@@ -420,17 +425,36 @@ public class SearchActionFacetsTest {
   }
 
   @Test
-  public void check_facets_max_size() {
+  public void check_facets_max_size_for_issues() {
     ComponentDto project = db.components().insertPublicProject();
+    Random random = new Random();
     IntStream.rangeClosed(1, 110)
       .forEach(index -> {
-        RuleDefinitionDto rule = db.rules().insert();
         UserDto user = db.users().insertUser();
         ComponentDto module = db.components().insertComponent(newModuleDto(project));
         ComponentDto directory = db.components().insertComponent(newDirectory(module, "dir" + index));
         ComponentDto file = db.components().insertComponent(newFileDto(directory));
-        db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid()));
+
+        RuleDefinitionDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setType(RULE_TYPES_EXCEPT_HOTSPOT[random.nextInt(RULE_TYPES_EXCEPT_HOTSPOT.length)]));
+        db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid())
+          .setStatus(ISSUE_STATUSES[random.nextInt(ISSUE_STATUSES.length)])
+          .setType(rule.getType()));
       });
+
+    // insert some hotspots which should be filtered by default
+    IntStream.rangeClosed(1, 30)
+      .forEach(index -> {
+        UserDto user = db.users().insertUser();
+        ComponentDto module = db.components().insertComponent(newModuleDto(project));
+        ComponentDto directory = db.components().insertComponent(newDirectory(module, "dir" + index));
+        ComponentDto file = db.components().insertComponent(newFileDto(directory));
+
+        RuleDefinitionDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setType(RuleType.SECURITY_HOTSPOT));
+        db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid())
+          .setStatus(random.nextBoolean() ? Issue.STATUS_TO_REVIEW : Issue.STATUS_REVIEWED)
+          .setType(rule.getType()));
+      });
+
     indexPermissions();
     indexIssues();
 
@@ -450,10 +474,10 @@ public class SearchActionFacetsTest {
         // Assignees contains one additional element : it's the empty string that will return number of unassigned issues
         tuple("assignees", 101),
         // Following facets returned fixed number of elements
-        tuple("statuses", 7),
+        tuple("statuses", 5),
         tuple("resolutions", 5),
         tuple("severities", 5),
-        tuple("types", 4));
+        tuple("types", 3));
   }
 
   @Test
@@ -509,7 +533,7 @@ public class SearchActionFacetsTest {
       .executeProtobuf(SearchWsResponse.class);
 
     Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L)
-      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
+      .put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();
 
     assertThat(response.getFacets().getFacetsList())
       .extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -518,7 +542,7 @@ public class SearchActionFacetsTest {
         tuple("statuses", expectedStatuses),
         tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
         tuple("rules", of(rule1.getKey().toString(), 1L, rule2.getKey().toString(), 0L)),
-        tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
+        tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L)),
         tuple("languages", of(rule1.getLanguage(), 1L, rule2.getLanguage(), 0L)),
         tuple("projects", of(project1.getKey(), 1L, project2.getKey(), 0L)),
         tuple("moduleUuids", of(module1.uuid(), 1L, module2.uuid(), 0L)),
index dc8b4969586c2344c78f5780192dded717eb5b97..478092d78ff089721e5023fca6faa73345892d94 100644 (file)
@@ -28,7 +28,6 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.resources.Languages;
 import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.rules.RuleType;
@@ -51,12 +50,12 @@ import org.sonar.db.rule.RuleDefinitionDto;
 import org.sonar.db.rule.RuleDto;
 import org.sonar.db.rule.RuleTesting;
 import org.sonar.db.user.UserDto;
-import org.sonar.server.issue.TextRangeResponseFormatter;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.es.SearchOptions;
 import org.sonar.server.es.StartupIndexer;
 import org.sonar.server.issue.AvatarResolverImpl;
 import org.sonar.server.issue.IssueFieldsSetter;
+import org.sonar.server.issue.TextRangeResponseFormatter;
 import org.sonar.server.issue.TransitionService;
 import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.issue.index.IssueIndexer;
@@ -92,7 +91,6 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
 import static org.sonar.db.issue.IssueTesting.newDto;
 import static org.sonar.server.tester.UserSessionRule.standalone;
 import static org.sonarqube.ws.Common.RuleType.BUG;
-import static org.sonarqube.ws.Common.RuleType.SECURITY_HOTSPOT;
 import static org.sonarqube.ws.Common.RuleType.VULNERABILITY;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS;
@@ -123,8 +121,8 @@ public class SearchActionTest {
   private Languages languages = new Languages();
   private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
   private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
-  private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
-    new MapSettings().asConfig(), System2.INSTANCE, dbClient));
+  private WsActionTester ws = new WsActionTester(
+    new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, System2.INSTANCE, dbClient));
   private StartupIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer);
 
   @Before
@@ -682,7 +680,7 @@ public class SearchActionTest {
   }
 
   @Test
-  public void security_hotspots_are_returned_by_default() {
+  public void security_hotspots_are_not_returned_by_default() {
     ComponentDto project = db.components().insertPublicProject();
     ComponentDto file = db.components().insertComponent(newFileDto(project));
     RuleDefinitionDto rule = db.rules().insert();
@@ -697,11 +695,11 @@ public class SearchActionTest {
 
     assertThat(result.getIssuesList())
       .extracting(Issue::getType)
-      .containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL, SECURITY_HOTSPOT);
+      .containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL);
   }
 
   @Test
-  public void security_hotspot_type_included_when_explicitly_selected() {
+  public void fail_if_trying_to_filter_issues_by_hotspots() {
     ComponentDto project = db.components().insertPublicProject();
     ComponentDto file = db.components().insertComponent(newFileDto(project));
     RuleDefinitionDto rule = newRule().getDefinition();
@@ -712,17 +710,12 @@ public class SearchActionTest {
     indexPermissions();
     indexIssues();
 
-    assertThat(ws.newRequest()
-      .setParam("types", RuleType.SECURITY_HOTSPOT.toString())
-      .executeProtobuf(SearchWsResponse.class).getIssuesList())
-        .extracting(Issue::getType)
-        .containsExactlyInAnyOrder(SECURITY_HOTSPOT);
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Value of parameter 'types' (SECURITY_HOTSPOT) must be one of: [CODE_SMELL, BUG, VULNERABILITY]");
 
-    assertThat(ws.newRequest()
-      .setParam("types", String.format("%s,%s", RuleType.BUG, RuleType.SECURITY_HOTSPOT))
-      .executeProtobuf(SearchWsResponse.class).getIssuesList())
-        .extracting(Issue::getType)
-        .containsExactlyInAnyOrder(BUG, SECURITY_HOTSPOT);
+    ws.newRequest()
+      .setParam("types", RuleType.SECURITY_HOTSPOT.toString())
+      .execute();
   }
 
   @Test
@@ -750,27 +743,6 @@ public class SearchActionTest {
       .containsExactlyInAnyOrder(tuple("MAJOR", 3L), tuple("INFO", 0L), tuple("MINOR", 0L), tuple("CRITICAL", 0L), tuple("BLOCKER", 0L));
   }
 
-  @Test
-  public void do_not_return_severity_on_security_hotspots() {
-    ComponentDto project = db.components().insertPublicProject();
-    ComponentDto file = db.components().insertComponent(newFileDto(project));
-    RuleDefinitionDto rule = db.rules().insert();
-    db.issues().insert(rule, project, file, i -> i.setType(RuleType.BUG).setSeverity(Severity.MAJOR.name()));
-    db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR.name()));
-    indexPermissions();
-    indexIssues();
-
-    SearchWsResponse result = ws.newRequest()
-      .setParam("types", String.format("%s,%s", RuleType.BUG, RuleType.SECURITY_HOTSPOT))
-      .executeProtobuf(SearchWsResponse.class);
-
-    assertThat(result.getIssuesList())
-      .extracting(Issue::getType, Issue::hasSeverity)
-      .containsExactlyInAnyOrder(
-        tuple(BUG, true),
-        tuple(SECURITY_HOTSPOT, false));
-  }
-
   @Test
   public void return_total_effort() {
     UserDto john = db.users().insertUser();
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java
deleted file mode 100644 (file)
index 544b1a0..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program 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.
- *
- * This program 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.ws;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-import java.time.Clock;
-import java.util.Arrays;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.resources.Languages;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Durations;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.rule.RuleDefinitionDto;
-import org.sonar.db.user.UserDto;
-import org.sonar.server.issue.TextRangeResponseFormatter;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.issue.AvatarResolverImpl;
-import org.sonar.server.issue.IssueFieldsSetter;
-import org.sonar.server.issue.TransitionService;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.issue.index.IssueIndexer;
-import org.sonar.server.issue.index.IssueIteratorFactory;
-import org.sonar.server.issue.index.IssueQueryFactory;
-import org.sonar.server.issue.workflow.FunctionExecutor;
-import org.sonar.server.issue.workflow.IssueWorkflow;
-import org.sonar.server.permission.index.PermissionIndexerTester;
-import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsActionTester;
-import org.sonar.test.JsonAssert;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.api.server.ws.WebService.Param.FACETS;
-import static org.sonar.db.component.ComponentTesting.newFileDto;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ORGANIZATION;
-
-public class SearchActionTestOnSonarCloud {
-  @Rule
-  public UserSessionRule userSession = UserSessionRule.standalone();
-  @Rule
-  public DbTester db = DbTester.create();
-  @Rule
-  public EsTester es = EsTester.create();
-
-  private MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", true);
-
-  private DbClient dbClient = db.getDbClient();
-  private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
-  private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
-  private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
-  private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
-  private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
-  private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
-  private Languages languages = new Languages();
-  private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
-  private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
-  private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);
-
-  private SearchAction underTest = new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
-    mapSettings.asConfig(), System2.INSTANCE, dbClient);
-  private WsActionTester ws = new WsActionTester(underTest);
-
-  private OrganizationDto organization;
-  private UserDto user;
-  private ComponentDto project;
-
-  @Before
-  public void setup() {
-    underTest.start();
-    organization = db.organizations().insert(o -> o.setKey("org-1"));
-    user = db.users().insertUser();
-
-    project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
-    ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
-    RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
-    db.issues().insert(rule, project, file, i -> i.setAuthorLogin("leia").setKee("2bd4eac2-b650-4037-80bc-7b112bd4eac2"));
-    db.issues().insert(rule, project, file, i -> i.setAuthorLogin("luke@skywalker.name").setKee("82fd47d4-b650-4037-80bc-7b1182fd47d4"));
-    db.commit();
-    allowAnyoneOnProjects(project);
-    indexIssues();
-  }
-
-  @Test
-  public void authors_facet_is_hidden_if_organization_is_not_set() {
-    db.organizations().addMember(organization, user);
-    userSession
-      .logIn(user)
-      .addMembership(organization);
-
-    String input = ws.newRequest()
-      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
-      .setParam(FACETS, "authors")
-      .execute()
-      .getInput();
-
-    JsonAssert.assertJson(input).isSimilarTo(this.getClass().getResource(this.getClass().getSimpleName() + "/no_authors_facet.json"));
-
-    JsonElement gson = new JsonParser().parse(input);
-    assertThat(gson.getAsJsonObject().get("facets").getAsJsonArray()).isEmpty();
-  }
-
-  @Test
-  public void authors_facet_is_hidden_if_user_is_not_a_member_of_the_organization() {
-    userSession
-      .logIn(user);
-
-    String input = ws.newRequest()
-      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
-      .setParam(FACETS, "authors")
-      .execute()
-      .getInput();
-
-    JsonAssert.assertJson(input).isSimilarTo(this.getClass().getResource(this.getClass().getSimpleName() + "/no_author_and_no_authors_facet.json"));
-
-    JsonElement gson = new JsonParser().parse(input);
-    assertThat(gson.getAsJsonObject().get("facets").getAsJsonArray()).isEmpty();
-
-  }
-
-  @Test
-  public void authors_facet_is_shown_if_organization_is_set_and_user_is_member_of_the_organization() {
-    db.organizations().addMember(organization, user);
-
-    userSession
-      .logIn(user)
-      .addMembership(organization);
-
-    ws.newRequest()
-      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
-      .setParam(FACETS, "authors")
-      .setParam(PARAM_ORGANIZATION, organization.getKey())
-      .execute()
-      .assertJson(this.getClass(), "with_authors_facet.json");
-  }
-
-  private void indexIssues() {
-    issueIndexer.indexOnStartup(null);
-  }
-
-  private void allowAnyoneOnProjects(ComponentDto... projects) {
-    userSession.registerComponents(projects);
-    Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
-  }
-}
index 8cc50ad6b5b425dae5bddcd64cef691ed6cce74a..87c9ebf0b756906458804a0bc7a563ab48a4fd4c 100644 (file)
@@ -48,6 +48,7 @@ import org.sonar.db.rule.RuleDefinitionDto;
 import org.sonar.db.rule.RuleDto;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
 import org.sonar.server.issue.IssueFieldsSetter;
 import org.sonar.server.issue.IssueFinder;
@@ -189,13 +190,14 @@ public class SetTypeActionTest {
 
   @Test
   @UseDataProvider("allTypesExceptSecurityHotspot")
-  public void fail_if_trying_to_change_type_of_a_hotspot(RuleType type) {
+  public void fail_NFE_if_trying_to_change_type_of_a_hotspot(RuleType type) {
     long now = 1_999_777_234L;
     when(system2.now()).thenReturn(now);
     IssueDto issueDto = issueDbTester.insertHotspot();
     setUserWithBrowseAndAdministerIssuePermission(issueDto);
 
-    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(String.format("Issue with key '%s' does not exist", issueDto.getKey()));
     call(issueDto.getKey(), type.name());
   }