]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9262 Prevent using files/dirs/modules facets when no proj/org
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 19 Oct 2017 15:50:42 +0000 (17:50 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 20 Oct 2017 11:09:23 +0000 (13:09 +0200)
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java

index 7e99634b893953f13432ed03d61a93e0ad1a8267..e9fac5edb66105e796dfd14db9b68ce9166fc5c5 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.server.issue.ws;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import java.util.Arrays;
@@ -51,6 +52,7 @@ import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.Issues.SearchWsResponse;
 import org.sonarqube.ws.client.issue.SearchWsRequest;
 
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.collect.Iterables.concat;
 import static com.google.common.collect.Sets.newHashSet;
 import static java.lang.String.format;
@@ -107,6 +109,8 @@ public class SearchAction implements IssuesWsAction {
 
   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> IGNORED_FACETS = newHashSet(PARAM_PLANNED, DEPRECATED_PARAM_ACTION_PLANS, PARAM_REPORTERS);
+  private static final Set<String> FACETS_REQUIRING_PROJECT_OR_ORGANIZATION = newHashSet(PARAM_FILE_UUIDS, PARAM_DIRECTORIES, PARAM_MODULE_UUIDS);
+  private static final Joiner COMA_JOINER = Joiner.on(",");
 
   private final UserSession userSession;
   private final IssueIndex issueIndex;
@@ -333,6 +337,13 @@ public class SearchAction implements IssuesWsAction {
       // This is a constraint from webapp UX.
       completeFacets(facets, request, wsRequest);
       collectFacets(collector, facets);
+
+      Set<String> facetsRequiringProjectOrOrganizationParameter = facets.getNames().stream()
+        .filter(FACETS_REQUIRING_PROJECT_OR_ORGANIZATION::contains)
+        .collect(MoreCollectors.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));
     }
     SearchResponseData data = searchResponseLoader.load(collector, facets);
 
index b00028310b778c5604c7ec577c13461c5c8fa617..ca0539ed339536f2d58c06909a30afd10646aa0e 100644 (file)
@@ -25,6 +25,7 @@ import java.util.Arrays;
 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;
@@ -82,6 +83,8 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_
 
 public class SearchActionComponentsTest {
 
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
@@ -322,8 +325,9 @@ public class SearchActionComponentsTest {
   }
 
   @Test
-  public void display_file_facet() throws Exception {
-    ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
+  public void display_file_facet_with_project() throws Exception {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
     ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
     ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "F2").setDbKey("FK2"));
     ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "F3").setDbKey("FK3"));
@@ -334,13 +338,52 @@ public class SearchActionComponentsTest {
     indexIssues();
 
     ws.newRequest()
-      .setParam(IssuesWsParameters.PARAM_COMPONENT_UUIDS, project.uuid())
+      .setParam(IssuesWsParameters.PARAM_COMPONENT_KEYS, project.getKey())
+      .setParam(IssuesWsParameters.PARAM_FILE_UUIDS, file1.uuid() + "," + file3.uuid())
+      .setParam(WebService.Param.FACETS, "fileUuids")
+      .execute()
+      .assertJson(this.getClass(), "display_file_facet.json");
+  }
+
+  @Test
+  public void display_file_facet_with_organization() throws Exception {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "F2").setDbKey("FK2"));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "F3").setDbKey("FK3"));
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
+    db.issues().insert(rule, project, file1, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
+    db.issues().insert(rule, project, file2, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    ws.newRequest()
+      .setParam(IssuesWsParameters.PARAM_ORGANIZATION, organization.getKey())
       .setParam(IssuesWsParameters.PARAM_FILE_UUIDS, file1.uuid() + "," + file3.uuid())
       .setParam(WebService.Param.FACETS, "fileUuids")
       .execute()
       .assertJson(this.getClass(), "display_file_facet.json");
   }
 
+  @Test
+  public void fail_to_display_file_facet_when_no_organization_or_project_is_set() {
+    ComponentDto project = db.components().insertPublicProject();
+    ComponentDto file = db.components().insertComponent(newFileDto(project));
+    RuleDefinitionDto rule = db.rules().insert();
+    db.issues().insert(rule, project, file);
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Facet(s) 'fileUuids' require to also filter by project or organization");
+
+    ws.newRequest()
+      .setParam(IssuesWsParameters.PARAM_FILE_UUIDS, file.uuid())
+      .setParam(WebService.Param.FACETS, "fileUuids")
+      .execute();
+  }
+
   @Test
   public void search_by_directory_path() throws Exception {
     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
@@ -420,7 +463,7 @@ public class SearchActionComponentsTest {
   }
 
   @Test
-  public void display_module_facet() throws Exception {
+  public void display_module_facet_using_project() throws Exception {
     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
     ComponentDto module = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
     ComponentDto subModule1 = db.components().insertComponent(newModuleDto("SUBM1", module).setDbKey("SUBMK1"));
@@ -435,6 +478,32 @@ public class SearchActionComponentsTest {
     indexIssues();
 
     ws.newRequest()
+      .setParam(IssuesWsParameters.PARAM_PROJECTS, project.getKey())
+      .setParam(IssuesWsParameters.PARAM_COMPONENT_UUIDS, module.uuid())
+      .setParam(IssuesWsParameters.PARAM_MODULE_UUIDS, subModule1.uuid() + "," + subModule3.uuid())
+      .setParam(WebService.Param.FACETS, "moduleUuids")
+      .execute()
+      .assertJson(this.getClass(), "display_module_facet.json");
+  }
+
+  @Test
+  public void display_module_facet_using_organization() throws Exception {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
+    ComponentDto module = db.components().insertComponent(newModuleDto("M1", project).setDbKey("MK1"));
+    ComponentDto subModule1 = db.components().insertComponent(newModuleDto("SUBM1", module).setDbKey("SUBMK1"));
+    ComponentDto subModule2 = db.components().insertComponent(newModuleDto("SUBM2", module).setDbKey("SUBMK2"));
+    ComponentDto subModule3 = db.components().insertComponent(newModuleDto("SUBM3", module).setDbKey("SUBMK3"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(subModule1, null, "F1").setDbKey("FK1"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(subModule2, null, "F2").setDbKey("FK2"));
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
+    IssueDto issue1 = db.issues().insert(rule, project, file1, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
+    IssueDto issue2 = db.issues().insert(rule, project, file2, i -> i.setKee("2bd4eac2-b650-4037-80bc-7b1182fd47d4"));
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    ws.newRequest()
+      .setParam(IssuesWsParameters.PARAM_ORGANIZATION, organization.getKey())
       .setParam(IssuesWsParameters.PARAM_COMPONENT_UUIDS, module.uuid())
       .setParam(IssuesWsParameters.PARAM_MODULE_UUIDS, subModule1.uuid() + "," + subModule3.uuid())
       .setParam(WebService.Param.FACETS, "moduleUuids")
@@ -443,7 +512,26 @@ public class SearchActionComponentsTest {
   }
 
   @Test
-  public void display_directory_facet() throws Exception {
+  public void fail_to_display_module_facet_when_no_organization_or_project_is_set() {
+    ComponentDto project = db.components().insertPublicProject();
+    ComponentDto module = db.components().insertComponent(newModuleDto(project));
+    ComponentDto file = db.components().insertComponent(newFileDto(module, null));
+    RuleDefinitionDto rule = db.rules().insert();
+    db.issues().insert(rule, project, file);
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Facet(s) 'moduleUuids' require to also filter by project or organization");
+
+    ws.newRequest()
+      .setParam(IssuesWsParameters.PARAM_COMPONENT_UUIDS, module.uuid())
+      .setParam(WebService.Param.FACETS, "moduleUuids")
+      .execute();
+  }
+
+  @Test
+  public void display_directory_facet_using_project() throws Exception {
     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
     ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
     ComponentDto file = db.components().insertComponent(newFileDto(project, directory, "F1").setDbKey("FK1").setPath(directory.path() + "/MyComponent.java"));
@@ -455,11 +543,50 @@ public class SearchActionComponentsTest {
     userSession.logIn("john");
     ws.newRequest()
       .setParam("resolved", "false")
+      .setParam(IssuesWsParameters.PARAM_COMPONENT_KEYS, project.getKey())
       .setParam(WebService.Param.FACETS, "directories")
       .execute()
       .assertJson(this.getClass(), "display_directory_facet.json");
   }
 
+  @Test
+  public void display_directory_facet_using_organization() throws Exception {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
+    ComponentDto directory = db.components().insertComponent(newDirectory(project, "D1", "src/main/java/dir"));
+    ComponentDto file = db.components().insertComponent(newFileDto(project, directory, "F1").setDbKey("FK1").setPath(directory.path() + "/MyComponent.java"));
+    RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
+    IssueDto issue = db.issues().insert(rule, project, file, i -> i.setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2"));
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    userSession.logIn("john");
+    ws.newRequest()
+      .setParam("resolved", "false")
+      .setParam(IssuesWsParameters.PARAM_ORGANIZATION, organization.getKey())
+      .setParam(WebService.Param.FACETS, "directories")
+      .execute()
+      .assertJson(this.getClass(), "display_directory_facet.json");
+  }
+
+  @Test
+  public void fail_to_display_directory_facet_when_no_organization_or_project_is_set() {
+    ComponentDto project = db.components().insertPublicProject();
+    ComponentDto directory = db.components().insertComponent(newDirectory(project, "src"));
+    ComponentDto file = db.components().insertComponent(newFileDto(project, directory));
+    RuleDefinitionDto rule = db.rules().insert();
+    db.issues().insert(rule, project, file);
+    allowAnyoneOnProjects(project);
+    indexIssues();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Facet(s) 'directories' require to also filter by project or organization");
+
+    ws.newRequest()
+      .setParam(WebService.Param.FACETS, "directories")
+      .execute();
+  }
+
   @Test
   public void search_by_view_uuid() throws Exception {
     ComponentDto project = db.components().insertPublicProject(p -> p.setDbKey("PK1"));
index 29bacc9551b5a827475d6fafded1c9b95f4bc434..14bea4cc667c86ec9c1a52516c126efcfc36f14f 100644 (file)
@@ -75,6 +75,7 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.DEPRECATED_FACET_
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.FACET_MODE_EFFORT;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_HIDE_COMMENTS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PAGE_INDEX;
@@ -381,6 +382,7 @@ public class SearchActionTest {
     userSessionRule.logIn("john");
     ws.newRequest()
       .setParam("resolved", "false")
+      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
       .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans,types")
       .execute()
       .assertJson(this.getClass(), "display_facets.json");
@@ -405,6 +407,7 @@ public class SearchActionTest {
     userSessionRule.logIn("john");
     ws.newRequest()
       .setParam("resolved", "false")
+      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
       .setParam(WebService.Param.FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
       .setParam("facetMode", FACET_MODE_EFFORT)
       .execute()
@@ -429,6 +432,7 @@ public class SearchActionTest {
 
     userSessionRule.logIn("john");
     ws.newRequest()
+      .setParam(PARAM_COMPONENT_KEYS, project.getKey())
       .setParam("resolved", "false")
       .setParam("severities", "MAJOR,MINOR")
       .setParam("languages", "xoo,polop,palap")