]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5953 Update (again) issue search WS API
authorJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Fri, 23 Jan 2015 16:49:13 +0000 (17:49 +0100)
committerJean-Baptiste Lievremont <jean-baptiste.lievremont@sonarsource.com>
Tue, 27 Jan 2015 17:31:35 +0000 (18:31 +0100)
- Use component(Uuid|Key)s to fix top level context of search
- Use (project|module|directory|file)Uuids to refine/facet

22 files changed:
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java
server/sonar-server/src/main/java/org/sonar/server/issue/filter/IssueFilterParameters.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/display_directory_facet.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/issues_on_different_projects.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/no_issue.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_directory_uuid.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_file_uuid.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_project_uuid.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_facets.json
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_zero_facets.json
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issues_on_different_projects.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_file_uuid.json [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_project_uuid.json [deleted file]

index a5a36f8bab2284bf46e4b862c294075ea1bc958d..37b8baa1961d2d697ac2f1d81ed79e4fb3f762c7 100644 (file)
@@ -23,6 +23,7 @@ package org.sonar.server.component;
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.collect.Collections2;
+import com.google.common.collect.Sets;
 import org.apache.commons.collections.CollectionUtils;
 import org.sonar.api.ServerComponent;
 import org.sonar.api.i18n.I18n;
@@ -44,11 +45,7 @@ import org.sonar.server.user.UserSession;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 
 import static com.google.common.collect.Lists.newArrayList;
 
@@ -219,6 +216,30 @@ public class ComponentService implements ServerComponent {
     return componentUuids;
   }
 
+  public Set<String> getDistinctQualifiers(DbSession session, @Nullable Collection<String> componentUuids) {
+    Set<String> componentQualifiers = Sets.newHashSet();
+    if (componentUuids != null && !componentUuids.isEmpty()) {
+      List<ComponentDto> components = dbClient.componentDao().getByUuids(session, componentUuids);
+
+      for (ComponentDto component : components) {
+        componentQualifiers.add(component.qualifier());
+      }
+    }
+    return componentQualifiers;
+  }
+
+  public Collection<ComponentDto> getByUuids(DbSession session, Collection<String> componentUuids) {
+    Set<ComponentDto> directoryPaths = Sets.newHashSet();
+    if (componentUuids != null && !componentUuids.isEmpty()) {
+      List<ComponentDto> components = dbClient.componentDao().getByUuids(session, componentUuids);
+
+      for (ComponentDto component : components) {
+        directoryPaths.add(component);
+      }
+    }
+    return directoryPaths;
+  }
+
   private void checkKeyFormat(String qualifier, String kee) {
     if (!ComponentKeys.isValidModuleKey(kee)) {
       throw new BadRequestException(formatMessage("Malformed key for %s: %s. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.",
@@ -245,5 +266,4 @@ public class ComponentService implements ServerComponent {
   private ComponentDto getByKey(DbSession session, String key) {
     return dbClient.componentDao().getByKey(session, key);
   }
-
 }
index a2b3a4a12c776e3895a3efb5aa4c4de62815e72d..1e8f18d2c07360d3e2101194fd9656064d7ccc24 100644 (file)
@@ -59,8 +59,10 @@ public class IssueQuery {
   private final Collection<String> resolutions;
   private final Collection<String> components;
   private final Collection<String> modules;
+  private final Collection<String> moduleRoots;
   private final Collection<String> projects;
   private final Collection<String> directories;
+  private final Collection<String> files;
   private final Collection<RuleKey> rules;
   private final Collection<String> actionPlans;
   private final Collection<String> reporters;
@@ -86,8 +88,10 @@ public class IssueQuery {
     this.resolutions = defaultCollection(builder.resolutions);
     this.components = defaultCollection(builder.components);
     this.modules = defaultCollection(builder.modules);
+    this.moduleRoots = defaultCollection(builder.moduleRoots);
     this.projects = defaultCollection(builder.projects);
     this.directories = defaultCollection(builder.directories);
+    this.files = defaultCollection(builder.files);
     this.rules = defaultCollection(builder.rules);
     this.actionPlans = defaultCollection(builder.actionPlans);
     this.reporters = defaultCollection(builder.reporters);
@@ -131,6 +135,10 @@ public class IssueQuery {
     return modules;
   }
 
+  public Collection<String> moduleRootUuids() {
+    return moduleRoots;
+  }
+
   public Collection<String> projectUuids() {
     return projects;
   }
@@ -139,6 +147,10 @@ public class IssueQuery {
     return directories;
   }
 
+  public Collection<String> fileUuids() {
+    return files;
+  }
+
   public Collection<RuleKey> rules() {
     return rules;
   }
@@ -237,8 +249,10 @@ public class IssueQuery {
     private Collection<String> resolutions;
     private Collection<String> components;
     private Collection<String> modules;
+    private Collection<String> moduleRoots;
     private Collection<String> projects;
     private Collection<String> directories;
+    private Collection<String> files;
     private Collection<RuleKey> rules;
     private Collection<String> actionPlans;
     private Collection<String> reporters;
@@ -290,6 +304,11 @@ public class IssueQuery {
       return this;
     }
 
+    public Builder moduleRootUuids(@Nullable Collection<String> l) {
+      this.moduleRoots = l;
+      return this;
+    }
+
     public Builder projectUuids(@Nullable Collection<String> l) {
       this.projects = l;
       return this;
@@ -300,6 +319,11 @@ public class IssueQuery {
       return this;
     }
 
+    public Builder fileUuids(@Nullable Collection<String> l) {
+      this.files = l;
+      return this;
+    }
+
     public Builder rules(@Nullable Collection<RuleKey> rules) {
       this.rules = rules;
       return this;
index f4022a34b019f6befdb7ac1b1af2f2a21240e6ff..bf187e33e9a7fe550cdfc21442dbd1de67145c64 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.server.issue;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.collect.Iterables;
@@ -29,11 +30,14 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import org.apache.commons.lang.ObjectUtils;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.server.ws.Request;
+import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.component.ComponentService;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.IssueQuery.Builder;
 import org.sonar.server.issue.filter.IssueFilterParameters;
 import org.sonar.server.search.ws.SearchRequestHandler;
 import org.sonar.server.util.RubyUtils;
@@ -64,6 +68,7 @@ public class IssueQueryService implements ServerComponent {
   public IssueQuery createFromMap(Map<String, Object> params) {
     DbSession session = dbClient.openSession(false);
     try {
+
       IssueQuery.Builder builder = IssueQuery.builder()
         .issueKeys(RubyUtils.toStrings(params.get(IssueFilterParameters.ISSUES)))
         .severities(RubyUtils.toStrings(params.get(IssueFilterParameters.SEVERITIES)))
@@ -79,19 +84,11 @@ public class IssueQueryService implements ServerComponent {
         .onComponentOnly(RubyUtils.toBoolean(params.get(IssueFilterParameters.ON_COMPONENT_ONLY)))
         .assigned(RubyUtils.toBoolean(params.get(IssueFilterParameters.ASSIGNED)))
         .planned(RubyUtils.toBoolean(params.get(IssueFilterParameters.PLANNED)))
-        .directories(RubyUtils.toStrings(params.get(IssueFilterParameters.DIRECTORIES)))
         .hideRules(RubyUtils.toBoolean(params.get(IssueFilterParameters.HIDE_RULES)))
         .createdAt(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_AT)))
         .createdAfter(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_AFTER)))
         .createdBefore(RubyUtils.toDate(params.get(IssueFilterParameters.CREATED_BEFORE)));
-      addProjectUuids(builder, session,
-        RubyUtils.toStrings(params.get(IssueFilterParameters.PROJECT_UUIDS)),
-        RubyUtils.toStrings(
-          ObjectUtils.defaultIfNull(
-            params.get(IssueFilterParameters.PROJECT_KEYS),
-            params.get(IssueFilterParameters.PROJECTS)
-            )
-          ));
+
       addComponentUuids(builder, session,
         RubyUtils.toStrings(params.get(IssueFilterParameters.COMPONENT_UUIDS)),
         RubyUtils.toStrings(
@@ -101,10 +98,18 @@ public class IssueQueryService implements ServerComponent {
             )
           ),
         RubyUtils.toStrings(params.get(IssueFilterParameters.COMPONENT_ROOT_UUIDS)),
-        RubyUtils.toStrings(params.get(IssueFilterParameters.COMPONENT_ROOTS)));
-      addModuleUuids(builder, session,
+        RubyUtils.toStrings(params.get(IssueFilterParameters.COMPONENT_ROOTS)),
+        RubyUtils.toStrings(params.get(IssueFilterParameters.PROJECT_UUIDS)),
+        RubyUtils.toStrings(
+          ObjectUtils.defaultIfNull(
+            params.get(IssueFilterParameters.PROJECT_KEYS),
+            params.get(IssueFilterParameters.PROJECTS)
+            )
+          ),
         RubyUtils.toStrings(params.get(IssueFilterParameters.MODULE_UUIDS)),
-        RubyUtils.toStrings(params.get(IssueFilterParameters.MODULE_KEYS)));
+        RubyUtils.toStrings(params.get(IssueFilterParameters.DIRECTORIES)),
+        RubyUtils.toStrings(params.get(IssueFilterParameters.FILE_UUIDS)));
+
       String sort = (String) params.get(IssueFilterParameters.SORT);
       if (!Strings.isNullOrEmpty(sort)) {
         builder.sort(sort);
@@ -139,18 +144,19 @@ public class IssueQueryService implements ServerComponent {
         .onComponentOnly(request.paramAsBoolean(IssueFilterParameters.ON_COMPONENT_ONLY))
         .assigned(request.paramAsBoolean(IssueFilterParameters.ASSIGNED))
         .planned(request.paramAsBoolean(IssueFilterParameters.PLANNED))
-        .directories(request.paramAsStrings(IssueFilterParameters.DIRECTORIES))
         .createdAt(request.paramAsDateTime(IssueFilterParameters.CREATED_AT))
         .createdAfter(request.paramAsDateTime(IssueFilterParameters.CREATED_AFTER))
         .createdBefore(request.paramAsDateTime(IssueFilterParameters.CREATED_BEFORE))
         .ignorePaging(request.paramAsBoolean(IssueFilterParameters.IGNORE_PAGING));
-      addProjectUuids(builder, session,
-        request.paramAsStrings(IssueFilterParameters.PROJECT_UUIDS), request.paramAsStrings(IssueFilterParameters.PROJECT_KEYS));
+
       addComponentUuids(builder, session,
         request.paramAsStrings(IssueFilterParameters.COMPONENT_UUIDS), request.paramAsStrings(IssueFilterParameters.COMPONENT_KEYS),
-        request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOT_UUIDS), request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOTS));
-      addModuleUuids(builder, session,
-        request.paramAsStrings(IssueFilterParameters.MODULE_UUIDS), request.paramAsStrings(IssueFilterParameters.MODULE_KEYS));
+        request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOT_UUIDS), request.paramAsStrings(IssueFilterParameters.COMPONENT_ROOTS),
+        request.paramAsStrings(IssueFilterParameters.PROJECT_UUIDS), request.paramAsStrings(IssueFilterParameters.PROJECT_KEYS),
+        request.paramAsStrings(IssueFilterParameters.MODULE_UUIDS),
+        request.paramAsStrings(IssueFilterParameters.DIRECTORIES),
+        request.paramAsStrings(IssueFilterParameters.FILE_UUIDS));
+
       String sort = request.param(SearchRequestHandler.PARAM_SORT);
       if (!Strings.isNullOrEmpty(sort)) {
         builder.sort(sort);
@@ -163,17 +169,6 @@ public class IssueQueryService implements ServerComponent {
     }
   }
 
-  private void addProjectUuids(IssueQuery.Builder builder, DbSession session, @Nullable Collection<String> projectUuids, @Nullable Collection<String> projects) {
-    if (projectUuids != null) {
-      if (projects != null) {
-        throw new IllegalArgumentException("projects and projectUuids cannot be set simultaneously");
-      }
-      builder.projectUuids(projectUuids);
-    } else {
-      builder.projectUuids(componentUuids(session, projects));
-    }
-  }
-
   private void addComponentUuids(IssueQuery.Builder builder, DbSession session,
     @Nullable Collection<String> componentUuids, @Nullable Collection<String> components,
     /*
@@ -181,32 +176,101 @@ public class IssueQueryService implements ServerComponent {
      * but "componentKeys" parameter already deprecates "components" parameter,
      * so queries specifying "componentRoots" must be handled manually
      */
-    @Nullable Collection<String> componentRootUuids, @Nullable Collection<String> componentRoots) {
+    @Nullable Collection<String> componentRootUuids, @Nullable Collection<String> componentRoots,
+    @Nullable Collection<String> projectUuids, @Nullable Collection<String> projects,
+    @Nullable Collection<String> moduleUuids,
+    @Nullable Collection<String> directories,
+    @Nullable Collection<String> fileUuids) {
+
+    Set<String> allComponentUuids = Sets.newHashSet();
+
     if (componentUuids != null || componentRootUuids != null) {
       if (components != null || componentRoots != null) {
         throw new IllegalArgumentException("components and componentUuids cannot be set simultaneously");
       }
-      Set<String> allComponentUuids = Sets.newHashSet();
       allComponentUuids.addAll((Collection<String>) ObjectUtils.defaultIfNull(componentUuids, Sets.newHashSet()));
       allComponentUuids.addAll((Collection<String>) ObjectUtils.defaultIfNull(componentRootUuids, Sets.newHashSet()));
-      builder.componentUuids(allComponentUuids);
     } else {
       Set<String> allComponents = Sets.newHashSet();
       allComponents.addAll((Collection<String>) ObjectUtils.defaultIfNull(components, Sets.newHashSet()));
       allComponents.addAll((Collection<String>) ObjectUtils.defaultIfNull(componentRoots, Sets.newHashSet()));
-      builder.componentUuids(componentUuids(session, allComponents));
+      allComponentUuids.addAll(componentUuids(session, allComponents));
+    }
+
+    if (allComponentUuids.isEmpty()) {
+      addComponentsBelowView(builder, session, projects, projectUuids, moduleUuids, directories, fileUuids);
+    } else {
+
+      Set<String> qualifiers = componentService.getDistinctQualifiers(session, allComponentUuids);
+      if (qualifiers.isEmpty()) {
+        // Qualifier not found, defaulting to componentUuids (e.g <UNKNOWN>)
+        builder.componentUuids(allComponentUuids);
+        return;
+      }
+      if (qualifiers.size() > 1) {
+        throw new IllegalArgumentException("All components must have the same qualifier, found " + Joiner.on(',').join(qualifiers));
+      }
+
+      String uniqueQualifier = qualifiers.iterator().next();
+      if (Qualifiers.VIEW.equals(uniqueQualifier)) {
+        // TODO Handle views
+        addComponentsBelowView(builder, session, projects, projectUuids, moduleUuids, directories, fileUuids);
+      } else if ("DEV".equals(uniqueQualifier)) { // XXX No constant !!!
+        // TODO Get SCM accounts from dev, then search by author
+        // TODO addComponentsBelowView(projects, projectUuids, moduleUuids, directories, fileUuids);
+      } else if (Qualifiers.PROJECT.equals(uniqueQualifier)) {
+        builder.projectUuids(allComponentUuids);
+        addComponentsBelowModule(builder, moduleUuids, directories, fileUuids);
+      } else if (Qualifiers.MODULE.equals(uniqueQualifier)) {
+        builder.moduleRootUuids(allComponentUuids);
+        addComponentsBelowModule(builder, moduleUuids, directories, fileUuids);
+      } else if (Qualifiers.DIRECTORY.equals(uniqueQualifier)) {
+        Collection<String> directoryModuleUuids = Sets.newHashSet();
+        Collection<String> directoryPaths = Sets.newHashSet();
+        for (ComponentDto directory : componentService.getByUuids(session, allComponentUuids)) {
+          directoryModuleUuids.add(directory.moduleUuid());
+          directoryPaths.add(directory.path());
+        }
+        builder.moduleUuids(directoryModuleUuids);
+        builder.directories(directoryPaths);
+        addComponentsBelowDirectory(builder, fileUuids);
+      } else if (Qualifiers.FILE.equals(uniqueQualifier)) {
+        builder.fileUuids(allComponentUuids);
+      } else {
+        throw new IllegalArgumentException("Unable to set search root context for components " + Joiner.on(',').join(allComponentUuids));
+      }
     }
   }
 
-  private void addModuleUuids(IssueQuery.Builder builder, DbSession session, @Nullable Collection<String> componentRootUuids, @Nullable Collection<String> componentRoots) {
-    if (componentRootUuids != null) {
-      if (componentRoots != null) {
-        throw new IllegalArgumentException("componentRoots and componentRootUuids cannot be set simultaneously");
+  private void addComponentsBelowView(Builder builder, DbSession session,
+    @Nullable Collection<String> projects, @Nullable Collection<String> projectUuids,
+    @Nullable Collection<String> moduleUuids, Collection<String> directories, Collection<String> fileUuids) {
+    if (projectUuids != null) {
+      if (projects != null) {
+        throw new IllegalArgumentException("projects and projectUuids cannot be set simultaneously");
       }
-      builder.moduleUuids(componentRootUuids);
+      builder.projectUuids(projectUuids);
     } else {
-      builder.moduleUuids(componentUuids(session, componentRoots));
+      builder.projectUuids(componentUuids(session, projects));
     }
+    addComponentsBelowModule(builder, moduleUuids, directories, fileUuids);
+  }
+
+  private void addComponentsBelowModule(Builder builder,
+    @Nullable Collection<String> moduleUuids, @Nullable Collection<String> directories, @Nullable Collection<String> fileUuids) {
+    builder.moduleUuids(moduleUuids);
+    addComponentsBelowModule(builder, directories, fileUuids);
+  }
+
+  private void addComponentsBelowModule(Builder builder,
+    @Nullable Collection<String> directories, @Nullable Collection<String> fileUuids) {
+    builder.directories(directories);
+    addComponentsBelowDirectory(builder, fileUuids);
+  }
+
+  private void addComponentsBelowDirectory(Builder builder,
+    @Nullable Collection<String> fileUuids) {
+    builder.fileUuids(fileUuids);
   }
 
   private Collection<String> componentUuids(DbSession session, @Nullable Collection<String> componentKeys) {
index fd4666a26817daf742b244fed2d0235c06ae98bd..bef2e2c85c85fc97d6f75f02e839e9830aacf5eb 100644 (file)
@@ -43,12 +43,12 @@ public class IssueFilterParameters {
   public static final String COMPONENT_UUIDS = "componentUuids";
   public static final String COMPONENT_ROOTS = "componentRoots";
   public static final String COMPONENT_ROOT_UUIDS = "componentRootUuids";
-  public static final String MODULE_KEYS = "moduleKeys";
   public static final String MODULE_UUIDS = "moduleUuids";
   public static final String PROJECTS = "projects";
   public static final String PROJECT_KEYS = "projectKeys";
   public static final String PROJECT_UUIDS = "projectUuids";
   public static final String DIRECTORIES = "directories";
+  public static final String FILE_UUIDS = "fileUuids";
   public static final String ON_COMPONENT_ONLY = "onComponentOnly";
   public static final String RULES = "rules";
   public static final String ACTION_PLANS = "actionPlans";
@@ -70,7 +70,7 @@ public class IssueFilterParameters {
 
   public static final List<String> ALL = ImmutableList.of(ISSUES, SEVERITIES, STATUSES, RESOLUTIONS, RESOLVED, COMPONENTS, COMPONENT_ROOTS, RULES, ACTION_PLANS, REPORTERS, TAGS,
     ASSIGNEES, LANGUAGES, ASSIGNED, PLANNED, HIDE_RULES, CREATED_AT, CREATED_AFTER, CREATED_BEFORE, PAGE_SIZE, PAGE_INDEX, SORT, ASC, COMPONENT_UUIDS, COMPONENT_ROOT_UUIDS,
-    PROJECTS, PROJECT_UUIDS, IGNORE_PAGING, PROJECT_KEYS, COMPONENT_KEYS, MODULE_KEYS, MODULE_UUIDS, DIRECTORIES);
+    PROJECTS, PROJECT_UUIDS, IGNORE_PAGING, PROJECT_KEYS, COMPONENT_KEYS, MODULE_UUIDS, DIRECTORIES, FILE_UUIDS);
 
   public static final List<String> ALL_WITHOUT_PAGINATION = newArrayList(Iterables.filter(ALL, new Predicate<String>() {
     @Override
index 4ee92aac528ba3e0624a1be5573f1c2d27a3bcc5..20c12ea6c97d98ebf227f1f614591c2554daa3a6 100644 (file)
@@ -24,7 +24,6 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.apache.commons.lang.BooleanUtils;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
@@ -257,25 +256,41 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
   }
 
   private void addComponentRelatedFilters(IssueQuery query, Map<String, FilterBuilder> filters) {
-    Collection<String> componentUuids = query.componentUuids();
-    if (BooleanUtils.isTrue(query.onComponentOnly())) {
-      Set<String> allComponents = Sets.newHashSet();
-      allComponents.addAll(query.projectUuids());
-      allComponents.addAll(query.moduleUuids());
-      allComponents.addAll(componentUuids);
-      filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, allComponents));
-    } else {
-      filters.put(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids()));
-      filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids()));
-
-      FilterBuilder compositeFilter = componentFilter(componentUuids);
-      filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, compositeFilter);
 
-      filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories()));
+    FilterBuilder projectFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids());
+    FilterBuilder moduleRootFilter = moduleRootFilter(query.moduleRootUuids());
+    FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids());
+    FilterBuilder directoryRootFilter = directoryFilter(query.moduleUuids(), query.directories());
+    FilterBuilder directoryFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories());
+    FilterBuilder fileFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids());
+    FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids());
+
+    if (projectFilter != null) {
+      filters.put("__componentRoot", projectFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter);
+    } else if (moduleRootFilter != null) {
+      filters.put("__componentRoot", moduleRootFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter);
+    } else if (directoryRootFilter != null) {
+      filters.put("__componentRoot", directoryRootFilter);
+      filters.put(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, fileFilter);
+    } else if (fileFilter != null) {
+      filters.put("__componentRoot", fileFilter);
+    } else if (componentFilter != null) {
+      // Last resort, when component type is unknown
+      filters.put("__componentRoot", componentFilter);
     }
   }
 
-  private FilterBuilder componentFilter(Collection<String> componentUuids) {
+  private FilterBuilder moduleRootFilter(Collection<String> componentUuids) {
+    if (componentUuids == null || componentUuids.isEmpty()) {
+      return null;
+    }
+
     FilterBuilder componentFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, componentUuids);
     FilterBuilder modulePathFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_PATH, componentUuids);
     FilterBuilder compositeFilter = null;
@@ -291,6 +306,23 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
     return compositeFilter;
   }
 
+  private FilterBuilder directoryFilter(Collection<String> moduleUuids, Collection<String> directoryPaths) {
+    BoolFilterBuilder directoryTop = null;
+    FilterBuilder moduleFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, moduleUuids);
+    FilterBuilder directoryFilter = matchFilter(IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, directoryPaths);
+    if (moduleFilter != null) {
+      directoryTop = FilterBuilders.boolFilter();
+      directoryTop.must(moduleFilter);
+    }
+    if (directoryFilter != null) {
+      if (directoryTop == null) {
+        directoryTop = FilterBuilders.boolFilter();
+      }
+      directoryTop.must(directoryFilter);
+    }
+    return directoryTop;
+  }
+
   private FilterBuilder getAuthorizationFilter(QueryContext options) {
     String user = options.getUserLogin();
     Set<String> groups = options.getUserGroups();
@@ -337,12 +369,14 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
         IssueFilterParameters.SEVERITIES, IssueIndexDefinition.FIELD_ISSUE_SEVERITY, Severity.ALL.toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
         IssueFilterParameters.STATUSES, IssueIndexDefinition.FIELD_ISSUE_STATUS, Issue.STATUSES.toArray());
-      addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
-        IssueFilterParameters.COMPONENT_UUIDS, IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.componentUuids().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
         IssueFilterParameters.PROJECT_UUIDS, IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID, query.projectUuids().toArray());
+      addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
+        IssueFilterParameters.MODULE_UUIDS, IssueIndexDefinition.FIELD_ISSUE_MODULE_UUID, query.moduleUuids().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
         IssueFilterParameters.DIRECTORIES, IssueIndexDefinition.FIELD_ISSUE_DIRECTORY_PATH, query.directories().toArray());
+      addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
+        IssueFilterParameters.FILE_UUIDS, IssueIndexDefinition.FIELD_ISSUE_COMPONENT_UUID, query.fileUuids().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
         IssueFilterParameters.LANGUAGES, IssueIndexDefinition.FIELD_ISSUE_LANGUAGE, query.languages().toArray());
       addSimpleStickyFacetIfNeeded(options, stickyFacetBuilder, esSearch,
@@ -507,7 +541,7 @@ public class IssueIndex extends BaseIndex<Issue, FakeIssueDto, String> {
         FilterBuilders.boolFilter()
           .must(getAuthorizationFilter(new QueryContext()))
           .must(FilterBuilders.missingFilter(IssueIndexDefinition.FIELD_ISSUE_RESOLUTION))
-          .must(componentFilter(Arrays.asList(componentUuid)))));
+          .must(moduleRootFilter(Arrays.asList(componentUuid)))));
     TermsBuilder aggreg = AggregationBuilders.terms("_ref")
       .field(IssueIndexDefinition.FIELD_ISSUE_TAGS)
       .size(pageSize)
index 58138a592c616c5fd61f97bdd38e78ae08a13ad4..80fd859f6a5ea77f79b3dd92871f9553cc6feab7 100644 (file)
@@ -229,11 +229,6 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
       .setDescription("Deprecated since 5.1. Use componentKeys instead, with onComponentOnly=false.");
     action.createParam(IssueFilterParameters.COMPONENT_ROOT_UUIDS)
       .setDescription("Deprecated since 5.1. Use componentUuids instead, with onComponentOnly=false.");
-    action.createParam(IssueFilterParameters.MODULE_KEYS)
-      .setDescription("To retrieve issues associated to a specific list of modules (comma-separated list of module keys). " +
-        INTERNAL_PARAMETER_DISCLAIMER +
-        "Views are not supported. If this parameter is set, moduleUuids must not be set.")
-      .setExampleValue("org.apache.struts:struts");
     action.createParam(IssueFilterParameters.MODULE_UUIDS)
       .setDescription("To retrieve issues associated to a specific list of modules (comma-separated list of module UUIDs). " +
         INTERNAL_PARAMETER_DISCLAIMER +
@@ -241,8 +236,15 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
       .setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92");
 
     action.createParam(IssueFilterParameters.DIRECTORIES)
-      .setDescription("Since 5.1. To retrieve issues associated to a specific list of directories (comma-separated list of directory paths). ")
-      .setExampleValue("7d8749e8-3070-4903-9188-bdd82933bb92");
+      .setDescription("Since 5.1. To retrieve issues associated to a specific list of directories (comma-separated list of directory paths). " +
+        "This parameter is only meaningful when a module is selected. " +
+        INTERNAL_PARAMETER_DISCLAIMER)
+      .setExampleValue("src/main/java/org/sonar/server/");
+
+    action.createParam(IssueFilterParameters.FILE_UUIDS)
+      .setDescription("To retrieve issues associated to a specific list of files (comma-separated list of file UUIDs). " +
+        INTERNAL_PARAMETER_DISCLAIMER)
+      .setExampleValue("bdd82933-3070-4903-9188-7d8749e8bb92");
 
     action.createParam(IssueFilterParameters.ON_COMPONENT_ONLY)
       .setDescription("Return only issues at the component's level, not on its descendants (modules, directories, files, etc.)")
@@ -257,7 +259,7 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
 
   @Override
   protected Result<Issue> doSearch(IssueQuery query, QueryContext context) {
-    Collection<String> components = query.componentUuids();
+    Collection<String> components = query.fileUuids();
     if (components != null && components.size() == 1 && BooleanUtils.isTrue(query.ignorePaging())) {
       context.setShowFullResult(true);
     }
@@ -282,7 +284,8 @@ public class SearchAction extends SearchRequestHandler<IssueQuery, Issue> {
       IssueFilterParameters.RULES,
       IssueFilterParameters.ASSIGNEES,
       IssueFilterParameters.REPORTERS,
-      IssueFilterParameters.COMPONENT_UUIDS,
+      IssueFilterParameters.MODULE_UUIDS,
+      IssueFilterParameters.FILE_UUIDS,
       IssueFilterParameters.DIRECTORIES,
       IssueFilterParameters.LANGUAGES,
       IssueFilterParameters.TAGS,
index 9d5ac839b70298efc600bc90426aa3ab4ac6727f..b2b811575c2ebb59f1554e1ac9e240a4787e057f 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.server.issue;
 
+import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -28,6 +29,7 @@ import org.mockito.Mock;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.DateUtils;
 import org.sonar.core.persistence.DbSession;
@@ -92,9 +94,11 @@ public class IssueQueryServiceTest {
     map.put("resolved", true);
     ArrayList<String> componentKeys = newArrayList("org.apache");
     map.put("components", componentKeys);
-    ArrayList<String> moduleKeys = newArrayList("org.sonar");
-    map.put("moduleKeys", moduleKeys);
+    ArrayList<String> moduleUuids = newArrayList("BCDE");
+    map.put("moduleUuids", moduleUuids);
     map.put("directories", newArrayList("/src/main/java/example"));
+    ArrayList<String> fileUuids = newArrayList("CDEF");
+    map.put("fileUuids", fileUuids);
     map.put("reporters", newArrayList("marilyn"));
     map.put("assignees", newArrayList("joanna"));
     map.put("languages", newArrayList("xoo"));
@@ -118,21 +122,22 @@ public class IssueQueryServiceTest {
         }
         if (components.contains("org.apache")) {
           return newArrayList("ABCD");
-        } else if (components.contains("org.sonar")) {
-          return newArrayList("BCDE");
         }
         return newArrayList();
       }
     });
 
+    when(componentService.getDistinctQualifiers(eq(session), Matchers.anyCollection())).thenReturn(Sets.newHashSet(Qualifiers.PROJECT));
+
     IssueQuery query = issueQueryService.createFromMap(map);
     assertThat(query.issueKeys()).containsOnly("ABCDE1234");
     assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
     assertThat(query.statuses()).containsOnly("CLOSED");
     assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
     assertThat(query.resolved()).isTrue();
-    assertThat(query.componentUuids()).containsOnly("ABCD");
+    assertThat(query.projectUuids()).containsOnly("ABCD");
     assertThat(query.moduleUuids()).containsOnly("BCDE");
+    assertThat(query.fileUuids()).containsOnly("CDEF");
     assertThat(query.reporters()).containsOnly("marilyn");
     assertThat(query.assignees()).containsOnly("joanna");
     assertThat(query.languages()).containsOnly("xoo");
index af05cb67c1a3643b6424c7732643eb700b52e81a..42d26c9717fbe37c719473e8ab1172a79f388e1c 100644 (file)
@@ -143,7 +143,6 @@ public class IssueIndexMediumTest {
       IssueTesting.newDoc("ISSUE6", ComponentTesting.newFileDto(subModule)));
 
     assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(6);
-    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).onComponentOnly(true).build(), new QueryContext()).getHits()).hasSize(1);
     assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
@@ -174,11 +173,16 @@ public class IssueIndexMediumTest {
       IssueTesting.newDoc("ISSUE5", subModule),
       IssueTesting.newDoc("ISSUE2", file));
 
-    assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(file.uuid())).build(), new QueryContext()).getHits()).isEmpty();
-    assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().moduleUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
+      .moduleUuids(newArrayList(file.uuid())).build(), new QueryContext()).getHits()).isEmpty();
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
+      .moduleUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
+      .moduleUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
+      .moduleUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid()))
+      .moduleUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
   @Test
@@ -198,15 +202,12 @@ public class IssueIndexMediumTest {
       IssueTesting.newDoc("ISSUE5", subModule),
       IssueTesting.newDoc("ISSUE6", file3));
 
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new QueryContext()).getHits()).hasSize(3);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(file1.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(2);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(subModule.uuid())).onComponentOnly(true).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(4);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(module.uuid())).onComponentOnly(true).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(6);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList(project.uuid())).onComponentOnly(true).build(), new QueryContext()).getHits()).hasSize(1);
-    assertThat(index.search(IssueQuery.builder().componentUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
+    assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid(), file2.uuid(), file3.uuid())).build(), new QueryContext()).getHits()).hasSize(3);
+    assertThat(index.search(IssueQuery.builder().fileUuids(newArrayList(file1.uuid())).build(), new QueryContext()).getHits()).hasSize(1);
+    assertThat(index.search(IssueQuery.builder().moduleRootUuids(newArrayList(subModule.uuid())).build(), new QueryContext()).getHits()).hasSize(2);
+    assertThat(index.search(IssueQuery.builder().moduleRootUuids(newArrayList(module.uuid())).build(), new QueryContext()).getHits()).hasSize(4);
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList(project.uuid())).build(), new QueryContext()).getHits()).hasSize(6);
+    assertThat(index.search(IssueQuery.builder().projectUuids(newArrayList("unknown")).build(), new QueryContext()).getHits()).isEmpty();
   }
 
   @Test
@@ -223,9 +224,9 @@ public class IssueIndexMediumTest {
       IssueTesting.newDoc("ISSUE4", file2),
       IssueTesting.newDoc("ISSUE5", file3));
 
-    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("componentUuids")));
-    assertThat(result.getFacets()).containsOnlyKeys("componentUuids");
-    assertThat(result.getFacets().get("componentUuids")).containsOnly(new FacetValue("A", 1), new FacetValue("ABCD", 1), new FacetValue("BCDE", 2), new FacetValue("CDEF", 1));
+    Result<Issue> result = index.search(IssueQuery.builder().build(), new QueryContext().addFacets(newArrayList("fileUuids")));
+    assertThat(result.getFacets()).containsOnlyKeys("fileUuids");
+    assertThat(result.getFacets().get("fileUuids")).containsOnly(new FacetValue("A", 1), new FacetValue("ABCD", 1), new FacetValue("BCDE", 2), new FacetValue("CDEF", 1));
   }
 
   @Test
@@ -781,7 +782,7 @@ public class IssueIndexMediumTest {
     indexIssue(IssueTesting.newDoc("ISSUE1", file1), "sonar-users", null);
     // project2 can be seen by sonar-admins
     indexIssue(IssueTesting.newDoc("ISSUE2", file2), "sonar-admins", null);
-    // project3 cannot be seen by anyone
+    // project3 can be seen by nobody
     indexIssue(IssueTesting.newDoc("ISSUE3", file3), null, null);
 
     IssueQuery.Builder query = IssueQuery.builder();
@@ -796,10 +797,10 @@ public class IssueIndexMediumTest {
     assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(2);
 
     MockUserSession.set().setUserGroups("another group");
-    assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(0);
+    assertThat(index.search(query.build(), new QueryContext()).getHits()).isEmpty();
 
     MockUserSession.set().setUserGroups("sonar-users", "sonar-admins");
-    assertThat(index.search(query.moduleUuids(newArrayList(project3.key())).build(), new QueryContext()).getHits()).hasSize(0);
+    assertThat(index.search(query.projectUuids(newArrayList(project3.uuid())).build(), new QueryContext()).getHits()).isEmpty();
   }
 
   @Test
@@ -829,7 +830,7 @@ public class IssueIndexMediumTest {
     assertThat(index.search(query.build(), new QueryContext()).getHits()).hasSize(0);
 
     MockUserSession.set().setLogin("john");
-    assertThat(index.search(query.moduleUuids(newArrayList(project3.key())).build(), new QueryContext()).getHits()).hasSize(0);
+    assertThat(index.search(query.projectUuids(newArrayList(project3.key())).build(), new QueryContext()).getHits()).hasSize(0);
   }
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsMediumTest.java
new file mode 100644 (file)
index 0000000..5c9d99d
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.issue.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.IssueTesting;
+import org.sonar.server.issue.filter.IssueFilterParameters;
+import org.sonar.server.issue.index.IssueIndexer;
+import org.sonar.server.permission.InternalPermissionService;
+import org.sonar.server.permission.PermissionChange;
+import org.sonar.server.rule.RuleTesting;
+import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.tester.ServerTester;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+public class SearchActionComponentsMediumTest {
+
+  @ClassRule
+  public static ServerTester tester = new ServerTester();
+
+  DbClient db;
+  DbSession session;
+  WsTester wsTester;
+
+  @Before
+  public void setUp() throws Exception {
+    tester.clearDbAndIndexes();
+    db = tester.get(DbClient.class);
+    wsTester = tester.get(WsTester.class);
+    session = db.openSession(false);
+  }
+
+  @After
+  public void after() {
+    session.close();
+  }
+
+  @Test
+  public void issues_on_different_projects() throws Exception {
+    RuleDto rule = newRule();
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
+    IssueDto issue = IssueTesting.newDto(rule, file, project)
+      .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
+      .setStatus("OPEN").setResolution("OPEN")
+      .setSeverity("MAJOR")
+      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
+      .setIssueUpdateDate(DateUtils.parseDate("2017-12-04"));
+    db.issueDao().insert(session, issue);
+
+    ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("DBCA").setKey("MyProject2"));
+    setDefaultProjectPermission(project2);
+    ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "EDCB").setKey("MyComponent2"));
+    IssueDto issue2 = IssueTesting.newDto(rule, file2, project2)
+      .setKee("92fd47d4-b650-4037-80bc-7b112bd4eac2")
+      .setStatus("OPEN").setResolution("OPEN")
+      .setSeverity("MAJOR")
+      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
+      .setIssueUpdateDate(DateUtils.parseDate("2017-12-04"));
+    db.issueDao().insert(session, issue2);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute();
+    result.assertJson(this.getClass(), "issues_on_different_projects.json", false);
+  }
+
+  @Test
+  public void search_by_project_uuid() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
+    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.PROJECT_UUIDS, project.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_project_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.PROJECT_UUIDS, "unknown")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, project.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_project_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+  }
+
+  @Test
+  public void search_by_file_uuid() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
+    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.FILE_UUIDS, file.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.FILE_UUIDS, "unknown")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, file.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+  }
+
+  @Test
+  public void search_by_directory_path() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir"));
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java"));
+    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, directory.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir")
+      .execute()
+      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+  }
+
+  @Test
+  public void search_by_directory_path_in_different_modules() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto module1 = insertComponent(ComponentTesting.newModuleDto(project).setKey("module1"));
+    ComponentDto module2 = insertComponent(ComponentTesting.newModuleDto(project).setKey("module2"));
+    ComponentDto directory1 = insertComponent(ComponentTesting.newDirectory(module1, "src/main/java/dir"));
+    ComponentDto directory2 = insertComponent(ComponentTesting.newDirectory(module2, "src/main/java/dir"));
+    ComponentDto file1 = insertComponent(ComponentTesting.newFileDto(module1, "BCDE").setKey("module1:MyComponent").setPath(directory1.path() + "/MyComponent.java"));
+    insertComponent(ComponentTesting.newFileDto(module2, "CDEF").setKey("module2:MyComponent").setPath(directory2.path() + "/MyComponent.java"));
+    RuleDto rule = newRule();
+    IssueDto issue1 = IssueTesting.newDto(rule, file1, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue1);
+    session.commit();
+
+    tester.get(IssueIndexer.class).indexAll();
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, directory1.uuid())
+      .execute()
+      .assertJson(this.getClass(), "search_by_directory_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.COMPONENT_UUIDS, directory2.uuid())
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.MODULE_UUIDS, module1.uuid())
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir")
+      .execute()
+      .assertJson(this.getClass(), "search_by_directory_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.MODULE_UUIDS, module2.uuid())
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir")
+      .execute()
+      .assertJson(this.getClass(), "search_by_directory_uuid.json", false);
+
+    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java")
+      .execute()
+      .assertJson(this.getClass(), "no_issue.json", false);
+  }
+
+  @Test
+  public void display_directory_facet() throws Exception {
+    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
+    setDefaultProjectPermission(project);
+    ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir"));
+    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java"));
+    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
+    db.issueDao().insert(session, issue);
+    session.commit();
+    tester.get(IssueIndexer.class).indexAll();
+
+    MockUserSession.set().setLogin("john");
+    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+      .setParam("resolved", "false")
+      .setParam(SearchAction.PARAM_FACETS, "directories")
+      .execute();
+    result.assertJson(this.getClass(), "display_directory_facet.json", false);
+  }
+
+  private RuleDto newRule() {
+    RuleDto rule = RuleTesting.newXooX1()
+      .setName("Rule name")
+      .setDescription("Rule desc")
+      .setStatus(RuleStatus.READY);
+    tester.get(RuleDao.class).insert(session, rule);
+    session.commit();
+    return rule;
+  }
+
+  private void setDefaultProjectPermission(ComponentDto project) {
+    // project can be seen by anyone and by code viewer
+    MockUserSession.set().setLogin("admin").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+    tester.get(InternalPermissionService.class).addPermission(new PermissionChange().setComponentKey(project.getKey()).setGroup(DefaultGroups.ANYONE).setPermission(UserRole.USER));
+    MockUserSession.set();
+  }
+
+  private ComponentDto insertComponent(ComponentDto component) {
+    db.componentDao().insert(session, component);
+    session.commit();
+    return component;
+  }
+
+}
index 8945a6132f78f03c96c7e3446231c40eb1b3b917..c6db9ae80a3de8f77dc364563eba13ce42724e83 100644 (file)
@@ -128,37 +128,6 @@ public class SearchActionMediumTest {
     result.assertJson(this.getClass(), "issue.json", false);
   }
 
-  @Test
-  public void issues_on_different_projects() throws Exception {
-    RuleDto rule = newRule();
-    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
-    setDefaultProjectPermission(project);
-    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
-    IssueDto issue = IssueTesting.newDto(rule, file, project)
-      .setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2")
-      .setStatus("OPEN").setResolution("OPEN")
-      .setSeverity("MAJOR")
-      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
-      .setIssueUpdateDate(DateUtils.parseDate("2017-12-04"));
-    db.issueDao().insert(session, issue);
-
-    ComponentDto project2 = insertComponent(ComponentTesting.newProjectDto("DBCA").setKey("MyProject2"));
-    setDefaultProjectPermission(project2);
-    ComponentDto file2 = insertComponent(ComponentTesting.newFileDto(project2, "EDCB").setKey("MyComponent2"));
-    IssueDto issue2 = IssueTesting.newDto(rule, file2, project2)
-      .setKee("92fd47d4-b650-4037-80bc-7b112bd4eac2")
-      .setStatus("OPEN").setResolution("OPEN")
-      .setSeverity("MAJOR")
-      .setIssueCreationDate(DateUtils.parseDate("2014-09-04"))
-      .setIssueUpdateDate(DateUtils.parseDate("2017-12-04"));
-    db.issueDao().insert(session, issue2);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-
-    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).execute();
-    result.assertJson(this.getClass(), "issues_on_different_projects.json", false);
-  }
-
   @Test
   public void issue_with_comment() throws Exception {
     db.userDao().insert(session, new UserDto().setLogin("john").setName("John").setEmail("john@email.com"));
@@ -305,70 +274,6 @@ public class SearchActionMediumTest {
     assertThat(result.outputAsString()).contains("\"componentId\":" + file.getId() + ",");
   }
 
-  @Test
-  public void search_by_project_uuid() throws Exception {
-    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
-    setDefaultProjectPermission(project);
-    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
-    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
-    db.issueDao().insert(session, issue);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.PROJECT_UUIDS, project.uuid())
-      .execute()
-      .assertJson(this.getClass(), "search_by_project_uuid.json", false);
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.PROJECT_UUIDS, "unknown")
-      .execute()
-      .assertJson(this.getClass(), "no_issue.json", false);
-  }
-
-  @Test
-  public void search_by_component_uuid() throws Exception {
-    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
-    setDefaultProjectPermission(project);
-    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent"));
-    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
-    db.issueDao().insert(session, issue);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.COMPONENT_UUIDS, file.uuid())
-      .execute()
-      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.COMPONENT_UUIDS, "unknown")
-      .execute()
-      .assertJson(this.getClass(), "no_issue.json", false);
-  }
-
-  @Test
-  public void search_by_directory_path() throws Exception {
-    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
-    setDefaultProjectPermission(project);
-    ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir"));
-    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java"));
-    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
-    db.issueDao().insert(session, issue);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java/dir")
-      .execute()
-      .assertJson(this.getClass(), "search_by_file_uuid.json", false);
-
-    wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam(IssueFilterParameters.DIRECTORIES, "src/main/java")
-      .execute()
-      .assertJson(this.getClass(), "no_issue.json", false);
-  }
-
   @Test
   public void ignore_paging_with_one_component() throws Exception {
     RuleDto rule = newRule();
@@ -462,7 +367,7 @@ public class SearchActionMediumTest {
     MockUserSession.set().setLogin("john");
     WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
       .setParam("resolved", "false")
-      .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,componentUuids,assignees,languages,actionPlans")
+      .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
       .execute();
     result.assertJson(this.getClass(), "display_facets.json", false);
   }
@@ -488,30 +393,11 @@ public class SearchActionMediumTest {
       .setParam("resolved", "false")
       .setParam("severities", "MAJOR,MINOR")
       .setParam("languages", "xoo,polop,palap")
-      .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,componentUuids,assignees,languages,actionPlans")
+      .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,projectUuids,rules,fileUuids,assignees,languages,actionPlans")
       .execute();
     result.assertJson(this.getClass(), "display_zero_facets.json", false);
   }
 
-  @Test
-  public void display_directory_facet() throws Exception {
-    ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
-    setDefaultProjectPermission(project);
-    ComponentDto directory = insertComponent(ComponentTesting.newDirectory(project, "src/main/java/dir"));
-    ComponentDto file = insertComponent(ComponentTesting.newFileDto(project, "BCDE").setKey("MyComponent").setPath(directory.path() + "/MyComponent.java"));
-    IssueDto issue = IssueTesting.newDto(newRule(), file, project).setKee("82fd47d4-b650-4037-80bc-7b112bd4eac2");
-    db.issueDao().insert(session, issue);
-    session.commit();
-    tester.get(IssueIndexer.class).indexAll();
-
-    MockUserSession.set().setLogin("john");
-    WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
-      .setParam("resolved", "false")
-      .setParam(SearchAction.PARAM_FACETS, "directories")
-      .execute();
-    result.assertJson(this.getClass(), "display_directory_facet.json", false);
-  }
-
   @Test
   public void hide_rules() throws Exception {
     ComponentDto project = insertComponent(ComponentTesting.newProjectDto("ABCD").setKey("MyProject"));
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/display_directory_facet.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/display_directory_facet.json
new file mode 100644 (file)
index 0000000..1df736c
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "facets": [
+    {
+      "property": "directories",
+      "values": [
+        {
+          "val": "src/main/java/dir",
+          "count": 1
+        }
+      ]
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/issues_on_different_projects.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/issues_on_different_projects.json
new file mode 100644 (file)
index 0000000..59e9bd7
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "issues": [
+    {
+      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
+      "component": "MyComponent",
+      "project": "MyProject",
+      "rule": "xoo:x1",
+      "status": "OPEN",
+      "resolution": "OPEN",
+      "severity": "MAJOR",
+      "updateDate": "2017-12-04T00:00:00+0100",
+      "fUpdateAge": "less than a minute"
+    },
+    {
+      "key": "92fd47d4-b650-4037-80bc-7b112bd4eac2",
+      "component": "MyComponent2",
+      "project": "MyProject2",
+      "rule": "xoo:x1",
+      "status": "OPEN",
+      "resolution": "OPEN",
+      "severity": "MAJOR",
+      "updateDate": "2017-12-04T00:00:00+0100",
+      "fUpdateAge": "less than a minute"
+    }
+  ],
+  "components": [
+    {
+      "uuid": "BCDE",
+      "key": "MyComponent",
+      "enabled" : true
+    },
+    {
+      "uuid": "ABCD",
+      "key": "MyProject",
+      "enabled" : true
+    },
+    {
+      "uuid": "EDCB",
+      "key": "MyComponent2",
+      "enabled" : true
+    },
+    {
+      "uuid": "DBCA",
+      "key": "MyProject2",
+      "enabled" : true
+    }
+  ],
+  "projects": [
+    {
+      "uuid": "ABCD",
+      "key": "MyProject"
+    },
+    {
+      "uuid": "DBCA",
+      "key": "MyProject2"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/no_issue.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/no_issue.json
new file mode 100644 (file)
index 0000000..ce8bbfb
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "total": 0,
+  "issues": []
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_directory_uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_directory_uuid.json
new file mode 100644 (file)
index 0000000..d74af4f
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "total": 1,
+  "p": 1,
+  "issues": [
+    {
+      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
+      "component": "module1:MyComponent",
+      "project": "MyProject",
+      "rule": "xoo:x1"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_file_uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_file_uuid.json
new file mode 100644 (file)
index 0000000..f13cd2e
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "total": 1,
+  "p": 1,
+  "issues": [
+    {
+      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
+      "component": "MyComponent",
+      "project": "MyProject",
+      "rule": "xoo:x1"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_project_uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionComponentsMediumTest/search_by_project_uuid.json
new file mode 100644 (file)
index 0000000..5df3549
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "total": 1,
+  "p": 1,
+  "ps": 100,
+  "issues": [
+    {
+      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
+      "component": "MyComponent",
+      "project": "MyProject",
+      "rule": "xoo:x1"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/display_directory_facet.json
deleted file mode 100644 (file)
index 1df736c..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "facets": [
-    {
-      "property": "directories",
-      "values": [
-        {
-          "val": "src/main/java/dir",
-          "count": 1
-        }
-      ]
-    }
-  ]
-}
index cce233e23e7f91b2170dfa469fcf77ba92b454db..c6f088839e61f23a6b8bbe5d2b4c4104f1214669 100644 (file)
       ]
     },
     {
-      "property": "componentUuids",
+      "property": "fileUuids",
       "values": [
         {
           "val": "BCDE",
index 693bbe898bfedb1cd747bcd3694d3097cb744fc4..5869e5b15c7bf96ff14206bc200d390891e1b862 100644 (file)
       ]
     },
     {
-      "property": "componentUuids",
+      "property": "fileUuids",
       "values": [
         {
           "val": "BCDE",
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issues_on_different_projects.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/issues_on_different_projects.json
deleted file mode 100644 (file)
index 59e9bd7..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-{
-  "issues": [
-    {
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
-      "component": "MyComponent",
-      "project": "MyProject",
-      "rule": "xoo:x1",
-      "status": "OPEN",
-      "resolution": "OPEN",
-      "severity": "MAJOR",
-      "updateDate": "2017-12-04T00:00:00+0100",
-      "fUpdateAge": "less than a minute"
-    },
-    {
-      "key": "92fd47d4-b650-4037-80bc-7b112bd4eac2",
-      "component": "MyComponent2",
-      "project": "MyProject2",
-      "rule": "xoo:x1",
-      "status": "OPEN",
-      "resolution": "OPEN",
-      "severity": "MAJOR",
-      "updateDate": "2017-12-04T00:00:00+0100",
-      "fUpdateAge": "less than a minute"
-    }
-  ],
-  "components": [
-    {
-      "uuid": "BCDE",
-      "key": "MyComponent",
-      "enabled" : true
-    },
-    {
-      "uuid": "ABCD",
-      "key": "MyProject",
-      "enabled" : true
-    },
-    {
-      "uuid": "EDCB",
-      "key": "MyComponent2",
-      "enabled" : true
-    },
-    {
-      "uuid": "DBCA",
-      "key": "MyProject2",
-      "enabled" : true
-    }
-  ],
-  "projects": [
-    {
-      "uuid": "ABCD",
-      "key": "MyProject"
-    },
-    {
-      "uuid": "DBCA",
-      "key": "MyProject2"
-    }
-  ]
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_file_uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_file_uuid.json
deleted file mode 100644 (file)
index f13cd2e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "total": 1,
-  "p": 1,
-  "issues": [
-    {
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
-      "component": "MyComponent",
-      "project": "MyProject",
-      "rule": "xoo:x1"
-    }
-  ]
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_project_uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/issue/ws/SearchActionMediumTest/search_by_project_uuid.json
deleted file mode 100644 (file)
index 5df3549..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "total": 1,
-  "p": 1,
-  "ps": 100,
-  "issues": [
-    {
-      "key": "82fd47d4-b650-4037-80bc-7b112bd4eac2",
-      "component": "MyComponent",
-      "project": "MyProject",
-      "rule": "xoo:x1"
-    }
-  ]
-}