Browse Source

SONAR-9052 Refactor IssueQueryFactory

- stop using ComponentService
- improve readability
- stop loading directories twice
- remove usage of Guava Predicate
- remove ComponentService from Compute Engine
tags/6.4-RC1
Simon Brandhof 7 years ago
parent
commit
22600d84f3

+ 0
- 2
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java View File

import org.sonar.process.logging.LogbackHelper; import org.sonar.process.logging.LogbackHelper;
import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentCleanerService;
import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.ComponentFinder;
import org.sonar.server.component.ComponentService;
import org.sonar.server.component.index.ComponentIndexer; import org.sonar.server.component.index.ComponentIndexer;
import org.sonar.server.computation.queue.PurgeCeActivities; import org.sonar.server.computation.queue.PurgeCeActivities;
import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule; import org.sonar.server.computation.task.projectanalysis.ProjectAnalysisTaskModule;


// components // components
ComponentFinder.class, // used in ComponentService ComponentFinder.class, // used in ComponentService
ComponentService.class, // used in ReportSubmitter
NewAlerts.class, NewAlerts.class,
NewAlerts.newMetadata(), NewAlerts.newMetadata(),
ComponentCleanerService.class, ComponentCleanerService.class,

+ 1
- 1
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java View File

assertThat(picoContainer.getComponentAdapters()) assertThat(picoContainer.getComponentAdapters())
.hasSize( .hasSize(
CONTAINER_ITSELF CONTAINER_ITSELF
+ 74 // level 4
+ 73 // level 4
+ 4 // content of CeConfigurationModule + 4 // content of CeConfigurationModule
+ 5 // content of CeQueueModule + 5 // content of CeQueueModule
+ 3 // content of CeHttpModule + 3 // content of CeHttpModule

+ 0
- 55
server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java View File

*/ */
package org.sonar.server.component; package org.sonar.server.component;


import com.google.common.base.Joiner;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.api.server.ServerSide; import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.server.es.ProjectIndexer; import org.sonar.server.es.ProjectIndexer;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;


import static com.google.common.collect.Lists.newArrayList;
import static org.sonar.core.component.ComponentKeys.isValidModuleKey; import static org.sonar.core.component.ComponentKeys.isValidModuleKey;
import static org.sonar.db.component.ComponentKeyUpdaterDao.checkIsProjectOrModule; import static org.sonar.db.component.ComponentKeyUpdaterDao.checkIsProjectOrModule;
import static org.sonar.server.ws.WsUtils.checkRequest; import static org.sonar.server.ws.WsUtils.checkRequest;


@ServerSide @ServerSide
@ComputeEngineSide
public class ComponentService { public class ComponentService {
private final DbClient dbClient; private final DbClient dbClient;
private final UserSession userSession; private final UserSession userSession;
} }
} }


public Collection<String> componentUuids(DbSession session, @Nullable Collection<String> componentKeys, boolean ignoreMissingComponents) {
Collection<String> componentUuids = newArrayList();
if (componentKeys != null && !componentKeys.isEmpty()) {
List<ComponentDto> components = dbClient.componentDao().selectByKeys(session, componentKeys);

if (!ignoreMissingComponents && components.size() < componentKeys.size()) {
Collection<String> foundKeys = Collections2.transform(components, ComponentDto::getKey);
Set<String> missingKeys = Sets.newHashSet(componentKeys);
missingKeys.removeAll(foundKeys);
throw new NotFoundException("The following component keys do not match any component:\n" +
Joiner.on('\n').join(missingKeys));
}

for (ComponentDto component : components) {
componentUuids.add(component.uuid());
}
}
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().selectByUuids(session, componentUuids);

for (ComponentDto component : components) {
componentQualifiers.add(component.qualifier());
}
}
return componentQualifiers;
}

public Collection<ComponentDto> getByUuids(DbSession session, @Nullable Collection<String> componentUuids) {
Set<ComponentDto> directoryPaths = Sets.newHashSet();
if (componentUuids != null && !componentUuids.isEmpty()) {
List<ComponentDto> components = dbClient.componentDao().selectByUuids(session, componentUuids);

for (ComponentDto component : components) {
directoryPaths.add(component);
}
}
return directoryPaths;
}

private static void checkProjectOrModuleKeyFormat(String key) { private static void checkProjectOrModuleKeyFormat(String key) {
checkRequest(isValidModuleKey(key), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", key); checkRequest(isValidModuleKey(key), "Malformed key for '%s'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.", key);
} }

+ 0
- 46
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQuery.java View File

private final Boolean onComponentOnly; private final Boolean onComponentOnly;
private final Boolean assigned; private final Boolean assigned;
private final Boolean resolved; private final Boolean resolved;
private final Boolean hideRules;
private final Boolean hideComments;
private final Date createdAt; private final Date createdAt;
private final Date createdAfter; private final Date createdAfter;
private final Date createdBefore; private final Date createdBefore;
this.onComponentOnly = builder.onComponentOnly; this.onComponentOnly = builder.onComponentOnly;
this.assigned = builder.assigned; this.assigned = builder.assigned;
this.resolved = builder.resolved; this.resolved = builder.resolved;
this.hideRules = builder.hideRules;
this.hideComments = builder.hideComments;
this.createdAt = builder.createdAt; this.createdAt = builder.createdAt;
this.createdAfter = builder.createdAfter; this.createdAfter = builder.createdAfter;
this.createdBefore = builder.createdBefore; this.createdBefore = builder.createdBefore;
return resolved; return resolved;
} }


/**
* @since 4.2
*/
@CheckForNull
public Boolean hideRules() {
return hideRules;
}

/**
* @since 5.1
*/
@CheckForNull
public Boolean hideComments() {
return hideComments;
}

@CheckForNull @CheckForNull
public Date createdAfter() { public Date createdAfter() {
return createdAfter == null ? null : new Date(createdAfter.getTime()); return createdAfter == null ? null : new Date(createdAfter.getTime());
private Boolean onComponentOnly = false; private Boolean onComponentOnly = false;
private Boolean assigned = null; private Boolean assigned = null;
private Boolean resolved = null; private Boolean resolved = null;
private Boolean hideRules = false;
private Boolean hideComments = false;
private Date createdAt; private Date createdAt;
private Date createdAfter; private Date createdAfter;
private Date createdBefore; private Date createdBefore;
return this; return this;
} }


/**
* If true, rules will not be loaded
* If false, rules will be loaded
*
* @since 4.2
*
*/
public Builder hideRules(@Nullable Boolean b) {
this.hideRules = b;
return this;
}

/**
* If true, comments will not be loaded
* If false, comments will be loaded
*
* @since 5.1
*
*/
public Builder hideComments(@Nullable Boolean b) {
this.hideComments = b;
return this;
}

public Builder createdAt(@Nullable Date d) { public Builder createdAt(@Nullable Date d) {
this.createdAt = d == null ? null : new Date(d.getTime()); this.createdAt = d == null ? null : new Date(d.getTime());
return this; return this;

+ 51
- 128
server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryFactory.java View File



import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ObjectUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.format.ISOPeriodFormat; import org.joda.time.format.ISOPeriodFormat;
import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Qualifiers;
import org.sonar.api.server.ServerSide; import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2; import org.sonar.api.utils.System2;
import org.sonar.api.web.UserRole; import org.sonar.api.web.UserRole;
import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
import org.sonar.db.DbSession; import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.SnapshotDto; import org.sonar.db.component.SnapshotDto;
import org.sonar.db.organization.OrganizationDto; import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.component.ComponentService;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;
import org.sonar.server.util.RubyUtils;
import org.sonarqube.ws.client.issue.IssuesWsParameters;
import org.sonarqube.ws.client.issue.SearchWsRequest; import org.sonarqube.ws.client.issue.SearchWsRequest;


import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.FluentIterable.from;
import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format; import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static org.sonar.api.utils.DateUtils.longToDate; import static org.sonar.api.utils.DateUtils.longToDate;
import static org.sonar.api.utils.DateUtils.parseDateOrDateTime; import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime;


private static final String UNKNOWN = "<UNKNOWN>"; private static final String UNKNOWN = "<UNKNOWN>";
private final DbClient dbClient; private final DbClient dbClient;
private final ComponentService componentService;
private final System2 system; private final System2 system;
private final UserSession userSession; private final UserSession userSession;


public IssueQueryFactory(DbClient dbClient, ComponentService componentService, System2 system, UserSession userSession) {
public IssueQueryFactory(DbClient dbClient, System2 system, UserSession userSession) {
this.dbClient = dbClient; this.dbClient = dbClient;
this.componentService = componentService;
this.system = system; this.system = system;
this.userSession = userSession; this.userSession = userSession;
} }


public IssueQuery createFromMap(Map<String, Object> params) {
try (DbSession dbSession = dbClient.openSession(false)) {
IssueQuery.Builder builder = IssueQuery.builder()
.issueKeys(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_ISSUES)))
.severities(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_SEVERITIES)))
.statuses(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_STATUSES)))
.resolutions(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_RESOLUTIONS)))
.resolved(RubyUtils.toBoolean(params.get(IssuesWsParameters.PARAM_RESOLVED)))
.rules(toRules(params.get(IssuesWsParameters.PARAM_RULES)))
.assignees(buildAssignees(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_ASSIGNEES))))
.languages(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_LANGUAGES)))
.tags(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_TAGS)))
.types(RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_TYPES)))
.assigned(RubyUtils.toBoolean(params.get(IssuesWsParameters.PARAM_ASSIGNED)))
.hideRules(RubyUtils.toBoolean(params.get(IssuesWsParameters.PARAM_HIDE_RULES)))
.createdAt(RubyUtils.toDate(params.get(IssuesWsParameters.PARAM_CREATED_AT)))
.createdAfter(buildCreatedAfterFromDates(RubyUtils.toDate(params.get(PARAM_CREATED_AFTER)), (String) params.get(PARAM_CREATED_IN_LAST)))
.createdBefore(RubyUtils.toDate(parseEndingDateOrDateTime((String) params.get(IssuesWsParameters.PARAM_CREATED_BEFORE))))
.organizationUuid(convertOrganizationKeyToUuid(dbSession, (String) params.get(IssuesWsParameters.PARAM_ORGANIZATION)));

Set<String> allComponentUuids = Sets.newHashSet();
boolean effectiveOnComponentOnly = mergeDeprecatedComponentParameters(dbSession,
RubyUtils.toBoolean(params.get(IssuesWsParameters.PARAM_ON_COMPONENT_ONLY)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_COMPONENTS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_COMPONENT_UUIDS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_COMPONENT_KEYS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_COMPONENT_ROOT_UUIDS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_COMPONENT_ROOTS)),
allComponentUuids);

addComponentParameters(builder, dbSession,
effectiveOnComponentOnly,
allComponentUuids,
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_PROJECT_UUIDS)),
RubyUtils.toStrings(
ObjectUtils.defaultIfNull(
params.get(IssuesWsParameters.PARAM_PROJECT_KEYS),
params.get(IssuesWsParameters.PARAM_PROJECTS))),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_MODULE_UUIDS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_DIRECTORIES)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_FILE_UUIDS)),
RubyUtils.toStrings(params.get(IssuesWsParameters.PARAM_AUTHORS)));

String sort = (String) params.get(IssuesWsParameters.PARAM_SORT);
if (!Strings.isNullOrEmpty(sort)) {
builder.sort(sort);
builder.asc(RubyUtils.toBoolean(params.get(IssuesWsParameters.PARAM_ASC)));
}
String facetMode = (String) params.get(IssuesWsParameters.FACET_MODE);
if (!Strings.isNullOrEmpty(facetMode)) {
builder.facetMode(facetMode);
} else {
builder.facetMode(IssuesWsParameters.FACET_MODE_COUNT);
}
return builder.build();
}
}

@CheckForNull
private Date buildCreatedAfterFromDates(@Nullable Date createdAfter, @Nullable String createdInLast) {
checkArgument(createdAfter == null || createdInLast == null, format("%s and %s cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_CREATED_IN_LAST));

Date actualCreatedAfter = createdAfter;
if (createdInLast != null) {
actualCreatedAfter = new DateTime(system.now()).minus(
ISOPeriodFormat.standard().parsePeriod("P" + createdInLast.toUpperCase(Locale.ENGLISH))).toDate();
}
return actualCreatedAfter;
}

public IssueQuery createFromRequest(SearchWsRequest request) {
public IssueQuery create(SearchWsRequest request) {
try (DbSession dbSession = dbClient.openSession(false)) { try (DbSession dbSession = dbClient.openSession(false)) {
IssueQuery.Builder builder = IssueQuery.builder() IssueQuery.Builder builder = IssueQuery.builder()
.issueKeys(request.getIssues()) .issueKeys(request.getIssues())
} }
} }


@CheckForNull
private Date buildCreatedAfterFromDates(@Nullable Date createdAfter, @Nullable String createdInLast) {
checkArgument(createdAfter == null || createdInLast == null, format("Parameters %s and %s cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_CREATED_IN_LAST));

Date actualCreatedAfter = createdAfter;
if (createdInLast != null) {
actualCreatedAfter = new DateTime(system.now()).minus(
ISOPeriodFormat.standard().parsePeriod("P" + createdInLast.toUpperCase(Locale.ENGLISH))).toDate();
}
return actualCreatedAfter;
}

@CheckForNull @CheckForNull
private String convertOrganizationKeyToUuid(DbSession dbSession, @Nullable String organizationKey) { private String convertOrganizationKeyToUuid(DbSession dbSession, @Nullable String organizationKey) {
if (organizationKey == null) { if (organizationKey == null) {
return buildCreatedAfterFromDates(createdAfter, createdInLast); return buildCreatedAfterFromDates(createdAfter, createdInLast);
} }


checkRequest(createdAfter == null, "'%s' and '%s' cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_SINCE_LEAK_PERIOD);
checkRequest(createdAfter == null, "Parameters '%s' and '%s' cannot be set simultaneously", PARAM_CREATED_AFTER, PARAM_SINCE_LEAK_PERIOD);


checkArgument(componentUuids.size() == 1, "One and only one component must be provided when searching since leak period"); checkArgument(componentUuids.size() == 1, "One and only one component must be provided when searching since leak period");
String uuid = componentUuids.iterator().next(); String uuid = componentUuids.iterator().next();
allComponentUuids.addAll(componentRootUuids); allComponentUuids.addAll(componentRootUuids);
effectiveOnComponentOnly = false; effectiveOnComponentOnly = false;
} else if (componentRoots != null) { } else if (componentRoots != null) {
allComponentUuids.addAll(componentUuids(session, componentRoots));
allComponentUuids.addAll(convertComponentKeysToUuids(session, componentRoots));
effectiveOnComponentOnly = false; effectiveOnComponentOnly = false;
} else if (components != null) { } else if (components != null) {
allComponentUuids.addAll(componentUuids(session, components));
allComponentUuids.addAll(convertComponentKeysToUuids(session, components));
effectiveOnComponentOnly = true; effectiveOnComponentOnly = true;
} else if (componentUuids != null) { } else if (componentUuids != null) {
allComponentUuids.addAll(componentUuids); allComponentUuids.addAll(componentUuids);
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
} else if (componentKeys != null) { } else if (componentKeys != null) {
allComponentUuids.addAll(componentUuids(session, componentKeys));
allComponentUuids.addAll(convertComponentKeysToUuids(session, componentKeys));
effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly); effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
} }
return effectiveOnComponentOnly; return effectiveOnComponentOnly;
} }


private static boolean atMostOneNonNullElement(Object... objects) { private static boolean atMostOneNonNullElement(Object... objects) {
return !from(Arrays.asList(objects))
.filter(notNull())
.anyMatch(new HasTwoOrMoreElements());
return Arrays.stream(objects)
.filter(Objects::nonNull)
.count() <= 1;
} }


private void addComponentParameters(IssueQuery.Builder builder, DbSession session, private void addComponentParameters(IssueQuery.Builder builder, DbSession session,
boolean onComponentOnly, boolean onComponentOnly,
Collection<String> componentUuids, Collection<String> componentUuids,
@Nullable Collection<String> projectUuids, @Nullable Collection<String> projects,
@Nullable Collection<String> projectUuids, @Nullable Collection<String> projectKeys,
@Nullable Collection<String> moduleUuids, @Nullable Collection<String> moduleUuids,
@Nullable Collection<String> directories, @Nullable Collection<String> directories,
@Nullable Collection<String> fileUuids, @Nullable Collection<String> fileUuids,
} }


builder.authors(authors); builder.authors(authors);
checkArgument(projectUuids == null || projects == null, "projects and projectUuids cannot be set simultaneously");
checkArgument(projectUuids == null || projectKeys == null, "Parameters projects and projectUuids cannot be set simultaneously");
if (projectUuids != null) { if (projectUuids != null) {
builder.projectUuids(projectUuids); builder.projectUuids(projectUuids);
} else {
builder.projectUuids(componentUuids(session, projects));
} else if (projectKeys != null) {
builder.projectUuids(convertComponentKeysToUuids(session, projectKeys));
} }
builder.moduleUuids(moduleUuids); builder.moduleUuids(moduleUuids);
builder.directories(directories); builder.directories(directories);
} }


private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) { private void addComponentsBasedOnQualifier(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
Set<String> qualifiers = componentService.getDistinctQualifiers(session, componentUuids);
if (qualifiers.isEmpty()) {
// Qualifier not found, defaulting to componentUuids (e.g <UNKNOWN>)
if (componentUuids.isEmpty()) {
builder.componentUuids(componentUuids); builder.componentUuids(componentUuids);
return; return;
} }

List<ComponentDto> components = dbClient.componentDao().selectByUuids(session, componentUuids);
if (components.isEmpty()) {
builder.componentUuids(componentUuids);
return;
}

Set<String> qualifiers = components.stream().map(ComponentDto::qualifier).collect(Collectors.toHashSet());
if (qualifiers.size() > 1) { if (qualifiers.size() > 1) {
throw new IllegalArgumentException("All components must have the same qualifier, found " + Joiner.on(',').join(qualifiers)); throw new IllegalArgumentException("All components must have the same qualifier, found " + Joiner.on(',').join(qualifiers));
} }


String uniqueQualifier = qualifiers.iterator().next();
switch (uniqueQualifier) {
String qualifier = qualifiers.iterator().next();
switch (qualifier) {
case Qualifiers.VIEW: case Qualifiers.VIEW:
case Qualifiers.SUBVIEW: case Qualifiers.SUBVIEW:
addViewsOrSubViews(builder, componentUuids, uniqueQualifier);
addViewsOrSubViews(builder, componentUuids);
break; break;
case Qualifiers.PROJECT: case Qualifiers.PROJECT:
builder.projectUuids(componentUuids); builder.projectUuids(componentUuids);
builder.moduleRootUuids(componentUuids); builder.moduleRootUuids(componentUuids);
break; break;
case Qualifiers.DIRECTORY: case Qualifiers.DIRECTORY:
addDirectories(builder, session, componentUuids);
addDirectories(builder, components);
break; break;
case Qualifiers.FILE: case Qualifiers.FILE:
case Qualifiers.UNIT_TEST_FILE: case Qualifiers.UNIT_TEST_FILE:
} }
} }


private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<String> componentUuids, String uniqueQualifier) {
List<String> filteredViewUuids = newArrayList();
for (String viewUuid : componentUuids) {
if ((Qualifiers.VIEW.equals(uniqueQualifier) && userSession.hasComponentUuidPermission(UserRole.USER, viewUuid))
|| (Qualifiers.SUBVIEW.equals(uniqueQualifier) && userSession.hasComponentUuidPermission(UserRole.USER, viewUuid))) {
private void addViewsOrSubViews(IssueQuery.Builder builder, Collection<String> viewOrSubViewUuids) {
List<String> filteredViewUuids = new ArrayList<>();
for (String viewUuid : viewOrSubViewUuids) {
if (userSession.hasComponentUuidPermission(UserRole.USER, viewUuid)) {
filteredViewUuids.add(viewUuid); filteredViewUuids.add(viewUuid);
} }
} }
builder.viewUuids(filteredViewUuids); builder.viewUuids(filteredViewUuids);
} }


private void addDirectories(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
private static void addDirectories(IssueQuery.Builder builder, List<ComponentDto> directories) {
Collection<String> directoryModuleUuids = Sets.newHashSet(); Collection<String> directoryModuleUuids = Sets.newHashSet();
Collection<String> directoryPaths = Sets.newHashSet(); Collection<String> directoryPaths = Sets.newHashSet();
for (ComponentDto directory : componentService.getByUuids(session, componentUuids)) {
for (ComponentDto directory : directories) {
directoryModuleUuids.add(directory.moduleUuid()); directoryModuleUuids.add(directory.moduleUuid());
directoryPaths.add(directory.path()); directoryPaths.add(directory.path());
} }
builder.directories(directoryPaths); builder.directories(directoryPaths);
} }


private Collection<String> componentUuids(DbSession session, @Nullable Collection<String> componentKeys) {
Collection<String> componentUuids = Lists.newArrayList();
componentUuids.addAll(componentService.componentUuids(session, componentKeys, true));
private Collection<String> convertComponentKeysToUuids(DbSession dbSession, Collection<String> componentKeys) {
List<String> componentUuids = dbClient.componentDao().selectByKeys(dbSession, componentKeys).stream().map(ComponentDto::uuid).collect(Collectors.toList());
// If unknown components are given, but no components are found, then all issues will be returned, // If unknown components are given, but no components are found, then all issues will be returned,
// so we add this hack in order to return no issue in this case. // so we add this hack in order to return no issue in this case.
if (componentKeys != null && !componentKeys.isEmpty() && componentUuids.isEmpty()) {
componentUuids.add(UNKNOWN);
if (!componentKeys.isEmpty() && componentUuids.isEmpty()) {
return singletonList(UNKNOWN);
} }
return componentUuids; return componentUuids;
} }
} }
return null; return null;
} }

private static class HasTwoOrMoreElements implements Predicate<Object> {
private AtomicInteger counter;

private HasTwoOrMoreElements() {
this.counter = new AtomicInteger();
}

@Override
public boolean apply(@Nonnull Object input) {
Objects.requireNonNull(input);
return counter.incrementAndGet() >= 2;
}
}
} }

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndexDefinition.java View File

type.stringFieldBuilder(FIELD_ISSUE_MESSAGE).disableNorms().build(); type.stringFieldBuilder(FIELD_ISSUE_MESSAGE).disableNorms().build();
type.stringFieldBuilder(FIELD_ISSUE_MODULE_UUID).disableNorms().build(); type.stringFieldBuilder(FIELD_ISSUE_MODULE_UUID).disableNorms().build();
type.createUuidPathField(FIELD_ISSUE_MODULE_PATH); type.createUuidPathField(FIELD_ISSUE_MODULE_PATH);
type.stringFieldBuilder(FIELD_ISSUE_ORGANIZATION_UUID).build();
type.stringFieldBuilder(FIELD_ISSUE_ORGANIZATION_UUID).disableNorms().build();
type.stringFieldBuilder(FIELD_ISSUE_PROJECT_UUID).disableNorms().addSubFields(SORTABLE_ANALYZER).build(); type.stringFieldBuilder(FIELD_ISSUE_PROJECT_UUID).disableNorms().addSubFields(SORTABLE_ANALYZER).build();
type.stringFieldBuilder(FIELD_ISSUE_DIRECTORY_PATH).disableNorms().build(); type.stringFieldBuilder(FIELD_ISSUE_DIRECTORY_PATH).disableNorms().build();
type.stringFieldBuilder(FIELD_ISSUE_RESOLUTION).disableNorms().build(); type.stringFieldBuilder(FIELD_ISSUE_RESOLUTION).disableNorms().build();

+ 8
- 11
server/sonar-server/src/main/java/org/sonar/server/issue/ws/ComponentTagsAction.java View File

*/ */
package org.sonar.server.issue.ws; package org.sonar.server.issue.ws;


import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import java.util.Map; import java.util.Map;
import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.IssueQueryFactory; import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.IssueService; import org.sonar.server.issue.IssueService;
import org.sonarqube.ws.client.issue.IssuesWsParameters;
import org.sonarqube.ws.client.issue.SearchWsRequest;


import static java.util.Collections.singletonList;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_COMPONENT_TAGS; import static org.sonarqube.ws.client.issue.IssuesWsParameters.ACTION_COMPONENT_TAGS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUID; import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUID;


/** /**
* List issue tags matching a given query. * List issue tags matching a given query.
* @since 5.1
*/ */
public class ComponentTagsAction implements IssuesWsAction { public class ComponentTagsAction implements IssuesWsAction {




@Override @Override
public void handle(Request request, Response response) throws Exception { public void handle(Request request, Response response) throws Exception {
Builder<String, Object> paramBuilder = ImmutableMap.<String, Object>builder()
.put(IssuesWsParameters.PARAM_COMPONENT_UUIDS, request.mandatoryParam(PARAM_COMPONENT_UUID))
.put(IssuesWsParameters.PARAM_RESOLVED, false);
if (request.hasParam(PARAM_CREATED_AFTER)) {
paramBuilder.put(PARAM_CREATED_AFTER, request.param(PARAM_CREATED_AFTER));
}
IssueQuery query = queryService.createFromMap(paramBuilder.build());
SearchWsRequest searchWsRequest = new SearchWsRequest()
.setComponentUuids(singletonList(request.mandatoryParam(PARAM_COMPONENT_UUID)))
.setResolved(false)
.setCreatedAfter(request.param(PARAM_CREATED_AFTER));

IssueQuery query = queryService.create(searchWsRequest);
int pageSize = request.mandatoryParamAsInt(PAGE_SIZE); int pageSize = request.mandatoryParamAsInt(PAGE_SIZE);
try (JsonWriter json = response.newJsonWriter()) { try (JsonWriter json = response.newJsonWriter()) {
json.beginObject().name("tags").beginArray(); json.beginObject().name("tags").beginArray();

+ 1
- 2
server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java View File

"If this parameter is set to a truthy value, createdAfter must not be set and one component id or key must be provided.") "If this parameter is set to a truthy value, createdAfter must not be set and one component id or key must be provided.")
.setBooleanPossibleValues() .setBooleanPossibleValues()
.setDefaultValue("false"); .setDefaultValue("false");

} }


private static void addComponentRelatedParams(WebService.NewAction action) { private static void addComponentRelatedParams(WebService.NewAction action) {
// prepare the Elasticsearch request // prepare the Elasticsearch request
SearchOptions options = createSearchOptionsFromRequest(request); SearchOptions options = createSearchOptionsFromRequest(request);
EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request); EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request);
IssueQuery query = issueQueryFactory.createFromRequest(request);
IssueQuery query = issueQueryFactory.create(request);


// execute request // execute request
SearchResult<IssueDoc> result = issueIndex.search(query, options); SearchResult<IssueDoc> result = issueIndex.search(query, options);

+ 0
- 10
server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceTest.java View File

*/ */
package org.sonar.server.component; package org.sonar.server.component;


import java.util.Arrays;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.sonar.server.es.ProjectIndexer; import org.sonar.server.es.ProjectIndexer;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;


import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.sonar.db.component.ComponentTesting.newFileDto; import static org.sonar.db.component.ComponentTesting.newFileDto;


private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexer); private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexer);


@Test
public void should_fail_silently_on_components_not_found_if_told_so() {
String moduleKey = "sample:root:module";
String fileKey = "sample:root:module:Foo.xoo";

assertThat(underTest.componentUuids(dbSession, Arrays.asList(moduleKey, fileKey), true)).isEmpty();
}

@Test @Test
public void bulk_update() { public void bulk_update() {
ComponentDto project = componentDb.insertComponent(newProjectDto(dbTester.organizations().insert()).setKey("my_project")); ComponentDto project = componentDb.insertComponent(newProjectDto(dbTester.organizations().insert()).setKey("my_project"));

+ 87
- 93
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryFactoryTest.java View File

package org.sonar.server.issue; package org.sonar.server.issue;


import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ComponentTesting;
import org.sonar.db.organization.OrganizationDto; import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.component.ComponentService;
import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;
import org.sonarqube.ws.client.issue.SearchWsRequest; import org.sonarqube.ws.client.issue.SearchWsRequest;
@Rule @Rule
public DbTester db = DbTester.create(); public DbTester db = DbTester.create();


private ComponentService componentService = new ComponentService(db.getDbClient(), userSession);
private System2 system = mock(System2.class); private System2 system = mock(System2.class);
private IssueQueryFactory underTest = new IssueQueryFactory(db.getDbClient(), componentService, system, userSession);
private IssueQueryFactory underTest = new IssueQueryFactory(db.getDbClient(), system, userSession);


@Test @Test
public void create_from_parameters() { public void create_from_parameters() {
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));


Map<String, Object> map = new HashMap<>();
map.put("issues", newArrayList("anIssueKey"));
map.put("severities", newArrayList("MAJOR", "MINOR"));
map.put("statuses", newArrayList("CLOSED"));
map.put("resolutions", newArrayList("FALSE-POSITIVE"));
map.put("resolved", true);
map.put("projectKeys", newArrayList(project.key()));
map.put("moduleUuids", newArrayList(module.uuid()));
map.put("directories", newArrayList("aDirPath"));
map.put("fileUuids", newArrayList(file.uuid()));
map.put("assignees", newArrayList("joanna"));
map.put("languages", newArrayList("xoo"));
map.put("tags", newArrayList("tag1", "tag2"));
map.put("organization", organization.getKey());
map.put("assigned", true);
map.put("planned", true);
map.put("hideRules", true);
map.put("createdAfter", "2013-04-16T09:08:24+0200");
map.put("createdBefore", "2013-04-17T09:08:24+0200");
map.put("rules", "squid:AvoidCycle,findbugs:NullReference");
map.put("sort", "CREATION_DATE");
map.put("asc", true);

IssueQuery query = underTest.createFromMap(map);
SearchWsRequest request = new SearchWsRequest()
.setIssues(asList("anIssueKey"))
.setSeverities(asList("MAJOR", "MINOR"))
.setStatuses(asList("CLOSED"))
.setResolutions(asList("FALSE-POSITIVE"))
.setResolved(true)
.setProjectKeys(asList(project.key()))
.setModuleUuids(asList(module.uuid()))
.setDirectories(asList("aDirPath"))
.setFileUuids(asList(file.uuid()))
.setAssignees(asList("joanna"))
.setLanguages(asList("xoo"))
.setTags(asList("tag1", "tag2"))
.setOrganization(organization.getKey())
.setAssigned(true)
.setCreatedAfter("2013-04-16T09:08:24+0200")
.setCreatedBefore("2013-04-17T09:08:24+0200")
.setRules(asList("squid:AvoidCycle", "findbugs:NullReference"))
.setSort("CREATION_DATE")
.setAsc(true);

IssueQuery query = underTest.create(request);


assertThat(query.issueKeys()).containsOnly("anIssueKey"); assertThat(query.issueKeys()).containsOnly("anIssueKey");
assertThat(query.severities()).containsOnly("MAJOR", "MINOR"); assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
assertThat(query.organizationUuid()).isEqualTo(organization.getUuid()); assertThat(query.organizationUuid()).isEqualTo(organization.getUuid());
assertThat(query.onComponentOnly()).isFalse(); assertThat(query.onComponentOnly()).isFalse();
assertThat(query.assigned()).isTrue(); assertThat(query.assigned()).isTrue();
assertThat(query.hideRules()).isTrue();
assertThat(query.rules()).hasSize(2); assertThat(query.rules()).hasSize(2);
assertThat(query.directories()).containsOnly("aDirPath"); assertThat(query.directories()).containsOnly("aDirPath");
assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200")); assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
.setCreatedAfter("2013-04-16") .setCreatedAfter("2013-04-16")
.setCreatedBefore("2013-04-17"); .setCreatedBefore("2013-04-17");


IssueQuery query = underTest.createFromRequest(request);
IssueQuery query = underTest.create(request);


assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDate("2013-04-16")); assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDate("2013-04-16"));
assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDate("2013-04-18")); assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDate("2013-04-18"));


@Test @Test
public void add_unknown_when_no_component_found() { public void add_unknown_when_no_component_found() {
Map<String, Object> map = new HashMap<>();
map.put("components", newArrayList("does_not_exist"));
SearchWsRequest request = new SearchWsRequest()
.setComponentKeys(asList("does_not_exist"));

IssueQuery query = underTest.create(request);


IssueQuery query = underTest.createFromMap(map);
assertThat(query.componentUuids()).containsOnly("<UNKNOWN>"); assertThat(query.componentUuids()).containsOnly("<UNKNOWN>");
} }




@Test @Test
public void fail_if_components_and_components_uuid_params_are_set_at_the_same_time() { public void fail_if_components_and_components_uuid_params_are_set_at_the_same_time() {
Map<String, Object> map = new HashMap<>();
map.put("components", newArrayList("foo"));
map.put("componentUuids", newArrayList("bar"));
SearchWsRequest request = new SearchWsRequest()
.setComponentKeys(asList("foo"))
.setComponentUuids(asList("bar"));


expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids"); expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");


underTest.createFromMap(map);
underTest.create(request);
} }


@Test @Test
public void fail_if_both_projects_and_projectUuids_params_are_set() { public void fail_if_both_projects_and_projectUuids_params_are_set() {
Map<String, Object> map = new HashMap<>();
map.put("projects", newArrayList("foo"));
map.put("projectUuids", newArrayList("bar"));
SearchWsRequest request = new SearchWsRequest()
.setProjectKeys(asList("foo"))
.setProjectUuids(asList("bar"));


expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("projects and projectUuids cannot be set simultaneously");
expectedException.expectMessage("Parameters projects and projectUuids cannot be set simultaneously");


underTest.createFromMap(map);
underTest.create(request);
} }


@Test @Test
public void fail_if_both_componentRoots_and_componentRootUuids_params_are_set() { public void fail_if_both_componentRoots_and_componentRootUuids_params_are_set() {
Map<String, Object> map = new HashMap<>();
map.put("componentRoots", newArrayList("foo"));
map.put("componentRootUuids", newArrayList("bar"));
SearchWsRequest request = new SearchWsRequest()
.setComponentRoots(asList("foo"))
.setComponentRootUuids(asList("bar"));


expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids"); expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");


underTest.createFromMap(map);
underTest.create(request);
} }


@Test @Test
public void fail_if_componentRoots_references_components_with_different_qualifier() { public void fail_if_componentRoots_references_components_with_different_qualifier() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
Map<String, Object> map = new HashMap<>();
map.put("componentRoots", newArrayList(project.key(), file.key()));
SearchWsRequest request = new SearchWsRequest()
.setComponentRoots(asList(project.key(), file.key()));


expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("All components must have the same qualifier, found FIL,TRK"); expectedException.expectMessage("All components must have the same qualifier, found FIL,TRK");


underTest.createFromMap(map);
underTest.create(request);
} }


@Test @Test
public void param_componentRootUuids_enables_search_in_view_tree_if_user_has_permission_on_view() { public void param_componentRootUuids_enables_search_in_view_tree_if_user_has_permission_on_view() {
ComponentDto view = db.components().insertView(); ComponentDto view = db.components().insertView();
Map<String, Object> map = new HashMap<>();
map.put("componentRootUuids", newArrayList(view.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentRootUuids(asList(view.uuid()));
userSession.addProjectUuidPermissions(UserRole.USER, view.uuid()); userSession.addProjectUuidPermissions(UserRole.USER, view.uuid());


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.viewUuids()).containsOnly(view.uuid()); assertThat(query.viewUuids()).containsOnly(view.uuid());
assertThat(query.onComponentOnly()).isFalse(); assertThat(query.onComponentOnly()).isFalse();
public void return_empty_results_if_not_allowed_to_search_for_subview() { public void return_empty_results_if_not_allowed_to_search_for_subview() {
ComponentDto view = db.components().insertView(); ComponentDto view = db.components().insertView();
ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view)); ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view));
Map<String, Object> map = new HashMap<>();
map.put("componentRootUuids", newArrayList(subView.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentRootUuids(asList(subView.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.viewUuids()).containsOnly("<UNKNOWN>"); assertThat(query.viewUuids()).containsOnly("<UNKNOWN>");
} }
@Test @Test
public void param_componentUuids_enables_search_on_project_tree_by_default() { public void param_componentUuids_enables_search_on_project_tree_by_default() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
Map<String, Object> map = new HashMap<>();
map.put("componentUuids", newArrayList(project.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentUuids(asList(project.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);
assertThat(query.projectUuids()).containsExactly(project.uuid()); assertThat(query.projectUuids()).containsExactly(project.uuid());
assertThat(query.onComponentOnly()).isFalse(); assertThat(query.onComponentOnly()).isFalse();
} }
@Test @Test
public void onComponentOnly_restricts_search_to_specified_componentKeys() { public void onComponentOnly_restricts_search_to_specified_componentKeys() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
Map<String, Object> map = new HashMap<>();
map.put("componentKeys", newArrayList(project.key()));
map.put("onComponentOnly", true);
SearchWsRequest request = new SearchWsRequest()
.setComponentKeys(asList(project.key()))
.setOnComponentOnly(true);


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.projectUuids()).isEmpty(); assertThat(query.projectUuids()).isEmpty();
assertThat(query.componentUuids()).containsExactly(project.uuid()); assertThat(query.componentUuids()).containsExactly(project.uuid());
public void should_search_in_tree_with_module_uuid() { public void should_search_in_tree_with_module_uuid() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project)); ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
Map<String, Object> map = new HashMap<>();
map.put("componentUuids", newArrayList(module.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentUuids(asList(module.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);
assertThat(query.moduleRootUuids()).containsExactly(module.uuid()); assertThat(query.moduleRootUuids()).containsExactly(module.uuid());
assertThat(query.onComponentOnly()).isFalse(); assertThat(query.onComponentOnly()).isFalse();
} }
public void param_componentUuids_enables_search_in_directory_tree() { public void param_componentUuids_enables_search_in_directory_tree() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo")); ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
Map<String, Object> map = new HashMap<>();
map.put("componentUuids", newArrayList(dir.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentUuids(asList(dir.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.moduleUuids()).containsOnly(dir.moduleUuid()); assertThat(query.moduleUuids()).containsOnly(dir.moduleUuid());
assertThat(query.directories()).containsOnly(dir.path()); assertThat(query.directories()).containsOnly(dir.path());
public void param_componentUuids_enables_search_by_file() { public void param_componentUuids_enables_search_by_file() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
Map<String, Object> map = new HashMap<>();
map.put("componentUuids", newArrayList(file.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentUuids(asList(file.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.fileUuids()).containsExactly(file.uuid()); assertThat(query.fileUuids()).containsExactly(file.uuid());
} }
public void param_componentUuids_enables_search_by_test_file() { public void param_componentUuids_enables_search_by_test_file() {
ComponentDto project = db.components().insertProject(); ComponentDto project = db.components().insertProject();
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project).setQualifier(Qualifiers.UNIT_TEST_FILE)); ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project).setQualifier(Qualifiers.UNIT_TEST_FILE));
Map<String, Object> map = new HashMap<>();
map.put("componentUuids", newArrayList(file.uuid()));
SearchWsRequest request = new SearchWsRequest()
.setComponentUuids(asList(file.uuid()));


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.fileUuids()).containsExactly(file.uuid()); assertThat(query.fileUuids()).containsExactly(file.uuid());
} }


@Test @Test
public void fail_if_created_after_and_created_since_are_both_set() { public void fail_if_created_after_and_created_since_are_both_set() {
Map<String, Object> map = new HashMap<>();
map.put("createdAfter", "2013-07-25T07:35:00+0100");
map.put("createdInLast", "palap");
SearchWsRequest request = new SearchWsRequest()
.setCreatedAfter("2013-07-25T07:35:00+0100")
.setCreatedInLast("palap");


try { try {
underTest.createFromMap(map);
underTest.create(request);
fail(); fail();
} catch (Exception e) { } catch (Exception e) {
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("createdAfter and createdInLast cannot be set simultaneously");
assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Parameters createdAfter and createdInLast cannot be set simultaneously");
} }
} }


public void set_created_after_from_created_since() { public void set_created_after_from_created_since() {
Date now = DateUtils.parseDateTime("2013-07-25T07:35:00+0100"); Date now = DateUtils.parseDateTime("2013-07-25T07:35:00+0100");
when(system.now()).thenReturn(now.getTime()); when(system.now()).thenReturn(now.getTime());
Map<String, Object> map = new HashMap<>();

map.put("createdInLast", "1y2m3w4d");
assertThat(underTest.createFromMap(map).createdAfter()).isEqualTo(DateUtils.parseDateTime("2012-04-30T07:35:00+0100"));
SearchWsRequest request = new SearchWsRequest()
.setCreatedInLast("1y2m3w4d");
assertThat(underTest.create(request).createdAfter()).isEqualTo(DateUtils.parseDateTime("2012-04-30T07:35:00+0100"));
} }


@Test @Test
public void fail_if_since_leak_period_and_created_after_set_at_the_same_time() { public void fail_if_since_leak_period_and_created_after_set_at_the_same_time() {
expectedException.expect(BadRequestException.class); expectedException.expect(BadRequestException.class);
expectedException.expectMessage("'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously");
expectedException.expectMessage("Parameters 'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously");


underTest.createFromRequest(new SearchWsRequest()
underTest.create(new SearchWsRequest()
.setSinceLeakPeriod(true) .setSinceLeakPeriod(true)
.setCreatedAfter("2013-07-25T07:35:00+0100")); .setCreatedAfter("2013-07-25T07:35:00+0100"));
} }
expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("One and only one component must be provided when searching since leak period"); expectedException.expectMessage("One and only one component must be provided when searching since leak period");


underTest.createFromRequest(new SearchWsRequest().setSinceLeakPeriod(true));
underTest.create(new SearchWsRequest().setSinceLeakPeriod(true));
} }


@Test @Test
expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("One and only one component must be provided when searching since leak period"); expectedException.expectMessage("One and only one component must be provided when searching since leak period");


underTest.createFromRequest(new SearchWsRequest()
underTest.create(new SearchWsRequest()
.setSinceLeakPeriod(true) .setSinceLeakPeriod(true)
.setComponentUuids(newArrayList("component-uuid", "project-uuid")));
.setComponentUuids(newArrayList("foo", "bar")));
} }


@Test @Test
expectedException.expect(IllegalArgumentException.class); expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("'unknown-date' cannot be parsed as either a date or date+time"); expectedException.expectMessage("'unknown-date' cannot be parsed as either a date or date+time");


underTest.createFromRequest(new SearchWsRequest()
underTest.create(new SearchWsRequest()
.setCreatedAfter("unknown-date")); .setCreatedAfter("unknown-date"));
} }


@Test @Test
public void return_empty_results_if_organization_with_specified_key_does_not_exist() { public void return_empty_results_if_organization_with_specified_key_does_not_exist() {
Map<String, Object> map = new HashMap<>();
map.put("organization", "does_not_exist");
SearchWsRequest request = new SearchWsRequest()
.setOrganization("does_not_exist");


IssueQuery query = underTest.createFromMap(map);
IssueQuery query = underTest.create(request);


assertThat(query.organizationUuid()).isEqualTo("<UNKNOWN>"); assertThat(query.organizationUuid()).isEqualTo("<UNKNOWN>");
} }

} }

+ 0
- 2
server/sonar-server/src/test/java/org/sonar/server/issue/IssueQueryTest.java View File

.tags(newArrayList("tag1", "tag2")) .tags(newArrayList("tag1", "tag2"))
.types(newArrayList("RELIABILITY", "SECURITY")) .types(newArrayList("RELIABILITY", "SECURITY"))
.assigned(true) .assigned(true)
.hideRules(true)
.createdAfter(new Date()) .createdAfter(new Date())
.createdBefore(new Date()) .createdBefore(new Date())
.createdAt(new Date()) .createdAt(new Date())
assertThat(query.tags()).containsOnly("tag1", "tag2"); assertThat(query.tags()).containsOnly("tag1", "tag2");
assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY"); assertThat(query.types()).containsOnly("RELIABILITY", "SECURITY");
assertThat(query.assigned()).isTrue(); assertThat(query.assigned()).isTrue();
assertThat(query.hideRules()).isTrue();
assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle")); assertThat(query.rules()).containsOnly(RuleKey.of("squid", "AvoidCycle"));
assertThat(query.createdAfter()).isNotNull(); assertThat(query.createdAfter()).isNotNull();
assertThat(query.createdBefore()).isNotNull(); assertThat(query.createdBefore()).isNotNull();

+ 38
- 47
server/sonar-server/src/test/java/org/sonar/server/issue/ws/ComponentTagsActionTest.java View File



import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.util.Map; import java.util.Map;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.Mockito;
import org.sonar.api.server.ws.WebService.Action; import org.sonar.api.server.ws.WebService.Action;
import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.server.ws.WebService.Param;
import org.sonar.server.issue.IssueQuery; import org.sonar.server.issue.IssueQuery;
import org.sonar.server.issue.IssueQueryFactory; import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.IssueService; import org.sonar.server.issue.IssueService;
import org.sonar.server.ws.WsTester;
import org.sonar.server.ws.TestResponse;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.client.issue.SearchWsRequest;


import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.sonar.test.JsonAssert.assertJson;


@RunWith(MockitoJUnitRunner.class)
public class ComponentTagsActionTest { public class ComponentTagsActionTest {


@Mock
private IssueService service;

@Mock
private IssueQueryFactory queryService;

private ComponentTagsAction componentTagsAction;

private WsTester tester;

@Before
public void setUp() {
componentTagsAction = new ComponentTagsAction(service, queryService);
tester = new WsTester(new IssuesWs(componentTagsAction));
}
private IssueService service = mock(IssueService.class);
private IssueQueryFactory issueQueryFactory = mock(IssueQueryFactory.class, Mockito.RETURNS_DEEP_STUBS);
private ComponentTagsAction underTest = new ComponentTagsAction(service, issueQueryFactory);
private WsActionTester tester = new WsActionTester(underTest);


@Test @Test
public void should_define() { public void should_define() {
Action action = tester.controller("api/issues").action("component_tags");
Action action = tester.getDef();
assertThat(action.description()).isNotEmpty(); assertThat(action.description()).isNotEmpty();
assertThat(action.responseExampleAsString()).isNotEmpty(); assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.isPost()).isFalse(); assertThat(action.isPost()).isFalse();
assertThat(action.isInternal()).isTrue(); assertThat(action.isInternal()).isTrue();
assertThat(action.handler()).isEqualTo(componentTagsAction);
assertThat(action.handler()).isEqualTo(underTest);
assertThat(action.params()).hasSize(3); assertThat(action.params()).hasSize(3);


Param query = action.param("componentUuid"); Param query = action.param("componentUuid");


@Test @Test
public void should_return_empty_list() throws Exception { public void should_return_empty_list() throws Exception {
tester.newGetRequest("api/issues", "component_tags").setParam("componentUuid", "polop").execute().assertJson("{\"tags\":[]}");
TestResponse response = tester.newRequest()
.setParam("componentUuid", "polop")
.execute();
assertJson(response.getInput()).isSimilarTo("{\"tags\":[]}");
} }


@Test @Test
.put("bug", 32L) .put("bug", 32L)
.put("cert", 2L) .put("cert", 2L)
.build(); .build();
IssueQuery query = mock(IssueQuery.class);
ArgumentCaptor<Map> captor = ArgumentCaptor.forClass(Map.class);
when(queryService.createFromMap(captor.capture())).thenReturn(query);
when(service.listTagsForComponent(query, 5)).thenReturn(tags);
ArgumentCaptor<SearchWsRequest> captor = ArgumentCaptor.forClass(SearchWsRequest.class);
when(issueQueryFactory.create(captor.capture())).thenReturn(mock(IssueQuery.class));
when(service.listTagsForComponent(any(IssueQuery.class), eq(5))).thenReturn(tags);

TestResponse response = tester.newRequest()
.setParam("componentUuid", "polop")
.setParam("ps", "5")
.execute();
assertJson(response.getInput()).isSimilarTo(getClass().getResource("ComponentTagsActionTest/component-tags.json"));


tester.newGetRequest("api/issues", "component_tags").setParam("componentUuid", "polop").setParam("ps", "5").execute()
.assertJson(getClass(), "component-tags.json");
assertThat(captor.getValue())
.containsEntry("componentUuids", "polop")
.containsEntry("resolved", false);
verify(service).listTagsForComponent(query, 5);
assertThat(captor.getValue().getComponentUuids()).containsOnly("polop");
assertThat(captor.getValue().getResolved()).isFalse();
assertThat(captor.getValue().getCreatedAfter()).isNull();
} }


@Test @Test
.put("bug", 32L) .put("bug", 32L)
.put("cert", 2L) .put("cert", 2L)
.build(); .build();
IssueQuery query = mock(IssueQuery.class);
ArgumentCaptor<Map> captor = ArgumentCaptor.forClass(Map.class);
when(queryService.createFromMap(captor.capture())).thenReturn(query);
when(service.listTagsForComponent(query, 5)).thenReturn(tags);
ArgumentCaptor<SearchWsRequest> captor = ArgumentCaptor.forClass(SearchWsRequest.class);
when(issueQueryFactory.create(captor.capture())).thenReturn(mock(IssueQuery.class));
when(service.listTagsForComponent(any(IssueQuery.class), eq(5))).thenReturn(tags);


String componentUuid = "polop"; String componentUuid = "polop";
String createdAfter = "2011-04-25"; String createdAfter = "2011-04-25";
tester.newGetRequest("api/issues", "component_tags")
TestResponse response = tester.newRequest()
.setParam("componentUuid", componentUuid) .setParam("componentUuid", componentUuid)
.setParam("createdAfter", createdAfter) .setParam("createdAfter", createdAfter)
.setParam("ps", "5") .setParam("ps", "5")
.execute()
.assertJson(getClass(), "component-tags.json");
assertThat(captor.getValue())
.containsEntry("componentUuids", componentUuid)
.containsEntry("resolved", false)
.containsEntry("createdAfter", createdAfter);
verify(service).listTagsForComponent(query, 5);
.execute();
assertJson(response.getInput()).isSimilarTo(getClass().getResource("ComponentTagsActionTest/component-tags.json"));
assertThat(captor.getValue().getComponentUuids()).containsOnly(componentUuid);
assertThat(captor.getValue().getResolved()).isFalse();
assertThat(captor.getValue().getCreatedAfter()).isEqualTo(createdAfter);
} }
} }

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java View File

assertThat(def.since()).isEqualTo("3.6"); assertThat(def.since()).isEqualTo("3.6");
assertThat(def.responseExampleAsString()).isNotEmpty(); assertThat(def.responseExampleAsString()).isNotEmpty();


assertThat(def.params()).extracting("key").containsOnly(
assertThat(def.params()).extracting("key").containsExactlyInAnyOrder(
"actionPlans", "additionalFields", "asc", "assigned", "assignees", "authors", "componentKeys", "componentRootUuids", "componentRoots", "componentUuids", "components", "actionPlans", "additionalFields", "asc", "assigned", "assignees", "authors", "componentKeys", "componentRootUuids", "componentRoots", "componentUuids", "components",
"createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly", "createdAfter", "createdAt", "createdBefore", "createdInLast", "directories", "facetMode", "facets", "fileUuids", "issues", "languages", "moduleUuids", "onComponentOnly",
"organization", "p", "planned", "projectKeys", "projectUuids", "projects", "ps", "reporters", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod", "organization", "p", "planned", "projectKeys", "projectUuids", "projects", "ps", "reporters", "resolutions", "resolved", "rules", "s", "severities", "sinceLeakPeriod",

Loading…
Cancel
Save