- Use component(Uuid|Key)s to fix top level context of search - Use (project|module|directory|file)Uuids to refine/facettags/latest-silver-master-#65
@@ -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); | |||
} | |||
} |
@@ -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; |
@@ -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) { |
@@ -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 |
@@ -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) |
@@ -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, |
@@ -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"); |
@@ -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 |
@@ -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; | |||
} | |||
} |
@@ -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")); |
@@ -0,0 +1,4 @@ | |||
{ | |||
"total": 0, | |||
"issues": [] | |||
} |
@@ -0,0 +1,12 @@ | |||
{ | |||
"total": 1, | |||
"p": 1, | |||
"issues": [ | |||
{ | |||
"key": "82fd47d4-b650-4037-80bc-7b112bd4eac2", | |||
"component": "module1:MyComponent", | |||
"project": "MyProject", | |||
"rule": "xoo:x1" | |||
} | |||
] | |||
} |
@@ -106,7 +106,7 @@ | |||
] | |||
}, | |||
{ | |||
"property": "componentUuids", | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", |
@@ -106,7 +106,7 @@ | |||
] | |||
}, | |||
{ | |||
"property": "componentUuids", | |||
"property": "fileUuids", | |||
"values": [ | |||
{ | |||
"val": "BCDE", |