--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.issue;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.BooleanUtils;
+import org.apache.commons.lang.ObjectUtils;
+import org.joda.time.DateTime;
+import org.joda.time.format.ISOPeriodFormat;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.SnapshotDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.component.ComponentService;
+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 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 java.lang.String.format;
+import static org.sonar.api.utils.DateUtils.longToDate;
+import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
+import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime;
+import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
+import static org.sonar.server.ws.WsUtils.checkRequest;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_ROOTS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_LAST;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
+
+/**
+ * This component is used to create an IssueQuery, in order to transform the component and component roots keys into uuid.
+ */
+@ServerSide
+public class IssueQueryFactory {
+
+ public static final String LOGIN_MYSELF = "__me__";
+
+ private static final String UNKNOWN = "<UNKNOWN>";
+ private final DbClient dbClient;
+ private final ComponentService componentService;
+ private final System2 system;
+ private final UserSession userSession;
+
+ public IssueQueryFactory(DbClient dbClient, ComponentService componentService, System2 system, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.componentService = componentService;
+ this.system = system;
+ 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) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ IssueQuery.Builder builder = IssueQuery.builder()
+ .issueKeys(request.getIssues())
+ .severities(request.getSeverities())
+ .statuses(request.getStatuses())
+ .resolutions(request.getResolutions())
+ .resolved(request.getResolved())
+ .rules(stringsToRules(request.getRules()))
+ .assignees(buildAssignees(request.getAssignees()))
+ .languages(request.getLanguages())
+ .tags(request.getTags())
+ .types(request.getTypes())
+ .assigned(request.getAssigned())
+ .createdAt(parseDateOrDateTime(request.getCreatedAt()))
+ .createdBefore(parseEndingDateOrDateTime(request.getCreatedBefore()))
+ .facetMode(request.getFacetMode())
+ .organizationUuid(convertOrganizationKeyToUuid(dbSession, request.getOrganization()));
+
+ Set<String> allComponentUuids = Sets.newHashSet();
+ boolean effectiveOnComponentOnly = mergeDeprecatedComponentParameters(dbSession,
+ request.getOnComponentOnly(),
+ request.getComponents(),
+ request.getComponentUuids(),
+ request.getComponentKeys(),
+ request.getComponentRootUuids(),
+ request.getComponentRoots(),
+ allComponentUuids);
+
+ addComponentParameters(builder, dbSession,
+ effectiveOnComponentOnly,
+ allComponentUuids,
+ request.getProjectUuids(),
+ request.getProjectKeys(),
+ request.getModuleUuids(),
+ request.getDirectories(),
+ request.getFileUuids(),
+ request.getAuthors());
+
+ builder.createdAfter(buildCreatedAfterFromRequest(dbSession, request, allComponentUuids));
+
+ String sort = request.getSort();
+ if (!Strings.isNullOrEmpty(sort)) {
+ builder.sort(sort);
+ builder.asc(request.getAsc());
+ }
+ return builder.build();
+
+ }
+ }
+
+ @CheckForNull
+ private String convertOrganizationKeyToUuid(DbSession dbSession, @Nullable String organizationKey) {
+ if (organizationKey == null) {
+ return null;
+ }
+ Optional<OrganizationDto> organization = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
+ return organization.map(OrganizationDto::getUuid).orElse(UNKNOWN);
+ }
+
+ private Date buildCreatedAfterFromRequest(DbSession dbSession, SearchWsRequest request, Set<String> componentUuids) {
+ Date createdAfter = parseStartingDateOrDateTime(request.getCreatedAfter());
+ String createdInLast = request.getCreatedInLast();
+
+ if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod()) {
+ return buildCreatedAfterFromDates(createdAfter, createdInLast);
+ }
+
+ checkRequest(createdAfter == null, "'%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");
+ String uuid = componentUuids.iterator().next();
+ Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(dbSession, uuid);
+ return buildCreatedAfterFromDates(createdAfterFromSnapshot, createdInLast);
+ }
+
+ @CheckForNull
+ private Date findCreatedAfterFromComponentUuid(DbSession dbSession, String uuid) {
+ ComponentDto component = checkFoundWithOptional(dbClient.componentDao().selectByUuid(dbSession, uuid), "Component with id '%s' not found", uuid);
+ Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.uuid());
+ return snapshot.map(s -> longToDate(s.getPeriodDate())).orElse(null);
+ }
+
+ private List<String> buildAssignees(@Nullable List<String> assigneesFromParams) {
+ List<String> assignees = Lists.newArrayList();
+ if (assigneesFromParams != null) {
+ assignees.addAll(assigneesFromParams);
+ }
+ if (assignees.contains(LOGIN_MYSELF)) {
+ String login = userSession.getLogin();
+ if (login == null) {
+ assignees.add(UNKNOWN);
+ } else {
+ assignees.add(login);
+ }
+ }
+ return assignees;
+ }
+
+ private boolean mergeDeprecatedComponentParameters(DbSession session, @Nullable Boolean onComponentOnly,
+ @Nullable Collection<String> components,
+ @Nullable Collection<String> componentUuids,
+ @Nullable Collection<String> componentKeys,
+ @Nullable Collection<String> componentRootUuids,
+ @Nullable Collection<String> componentRoots,
+ Set<String> allComponentUuids) {
+ boolean effectiveOnComponentOnly = false;
+
+ checkArgument(atMostOneNonNullElement(components, componentUuids, componentKeys, componentRootUuids, componentRoots),
+ "At most one of the following parameters can be provided: %s, %s, %s, %s, %s",
+ PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS, PARAM_COMPONENTS, PARAM_COMPONENT_ROOTS, PARAM_COMPONENT_UUIDS);
+
+ if (componentRootUuids != null) {
+ allComponentUuids.addAll(componentRootUuids);
+ effectiveOnComponentOnly = false;
+ } else if (componentRoots != null) {
+ allComponentUuids.addAll(componentUuids(session, componentRoots));
+ effectiveOnComponentOnly = false;
+ } else if (components != null) {
+ allComponentUuids.addAll(componentUuids(session, components));
+ effectiveOnComponentOnly = true;
+ } else if (componentUuids != null) {
+ allComponentUuids.addAll(componentUuids);
+ effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
+ } else if (componentKeys != null) {
+ allComponentUuids.addAll(componentUuids(session, componentKeys));
+ effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
+ }
+ return effectiveOnComponentOnly;
+ }
+
+ private static boolean atMostOneNonNullElement(Object... objects) {
+ return !from(Arrays.asList(objects))
+ .filter(notNull())
+ .anyMatch(new HasTwoOrMoreElements());
+ }
+
+ private void addComponentParameters(IssueQuery.Builder builder, DbSession session,
+ boolean onComponentOnly,
+ Collection<String> componentUuids,
+ @Nullable Collection<String> projectUuids, @Nullable Collection<String> projects,
+ @Nullable Collection<String> moduleUuids,
+ @Nullable Collection<String> directories,
+ @Nullable Collection<String> fileUuids,
+ @Nullable Collection<String> authors) {
+
+ builder.onComponentOnly(onComponentOnly);
+ if (onComponentOnly) {
+ builder.componentUuids(componentUuids);
+ return;
+ }
+
+ builder.authors(authors);
+ checkArgument(projectUuids == null || projects == null, "projects and projectUuids cannot be set simultaneously");
+ if (projectUuids != null) {
+ builder.projectUuids(projectUuids);
+ } else {
+ builder.projectUuids(componentUuids(session, projects));
+ }
+ builder.moduleUuids(moduleUuids);
+ builder.directories(directories);
+ builder.fileUuids(fileUuids);
+
+ if (!componentUuids.isEmpty()) {
+ addComponentsBasedOnQualifier(builder, session, 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>)
+ builder.componentUuids(componentUuids);
+ 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();
+ switch (uniqueQualifier) {
+ case Qualifiers.VIEW:
+ case Qualifiers.SUBVIEW:
+ addViewsOrSubViews(builder, componentUuids, uniqueQualifier);
+ break;
+ case Qualifiers.PROJECT:
+ builder.projectUuids(componentUuids);
+ break;
+ case Qualifiers.MODULE:
+ builder.moduleRootUuids(componentUuids);
+ break;
+ case Qualifiers.DIRECTORY:
+ addDirectories(builder, session, componentUuids);
+ break;
+ case Qualifiers.FILE:
+ case Qualifiers.UNIT_TEST_FILE:
+ builder.fileUuids(componentUuids);
+ break;
+ default:
+ throw new IllegalArgumentException("Unable to set search root context for components " + Joiner.on(',').join(componentUuids));
+ }
+ }
+
+ 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))) {
+ filteredViewUuids.add(viewUuid);
+ }
+ }
+ if (filteredViewUuids.isEmpty()) {
+ filteredViewUuids.add(UNKNOWN);
+ }
+ builder.viewUuids(filteredViewUuids);
+ }
+
+ private void addDirectories(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
+ Collection<String> directoryModuleUuids = Sets.newHashSet();
+ Collection<String> directoryPaths = Sets.newHashSet();
+ for (ComponentDto directory : componentService.getByUuids(session, componentUuids)) {
+ directoryModuleUuids.add(directory.moduleUuid());
+ directoryPaths.add(directory.path());
+ }
+ builder.moduleUuids(directoryModuleUuids);
+ 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));
+ // 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.
+ if (componentKeys != null && !componentKeys.isEmpty() && componentUuids.isEmpty()) {
+ componentUuids.add(UNKNOWN);
+ }
+ return componentUuids;
+ }
+
+ @VisibleForTesting
+ static Collection<RuleKey> toRules(@Nullable Object o) {
+ Collection<RuleKey> result = null;
+ if (o != null) {
+ if (o instanceof List) {
+ // assume that it contains only strings
+ result = stringsToRules((List<String>) o);
+ } else if (o instanceof String) {
+ result = stringsToRules(newArrayList(Splitter.on(',').omitEmptyStrings().split((String) o)));
+ }
+ }
+ return result;
+ }
+
+ @CheckForNull
+ private static Collection<RuleKey> stringsToRules(@Nullable Collection<String> rules) {
+ if (rules != null) {
+ return Collections2.transform(rules, RuleKey::parse);
+ }
+ 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;
+ }
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.issue;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.BooleanUtils;
-import org.apache.commons.lang.ObjectUtils;
-import org.joda.time.DateTime;
-import org.joda.time.format.ISOPeriodFormat;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.SnapshotDto;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.component.ComponentService;
-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 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 java.lang.String.format;
-import static org.sonar.api.utils.DateUtils.longToDate;
-import static org.sonar.api.utils.DateUtils.parseDateOrDateTime;
-import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime;
-import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime;
-import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
-import static org.sonar.server.ws.WsUtils.checkRequest;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENTS;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_ROOTS;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_UUIDS;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_AFTER;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_CREATED_IN_LAST;
-import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
-
-/**
- * This component is used to create an IssueQuery, in order to transform the component and component roots keys into uuid.
- */
-@ServerSide
-public class IssueQueryService {
-
- public static final String LOGIN_MYSELF = "__me__";
-
- private static final String UNKNOWN = "<UNKNOWN>";
- private final DbClient dbClient;
- private final ComponentService componentService;
- private final System2 system;
- private final UserSession userSession;
-
- public IssueQueryService(DbClient dbClient, ComponentService componentService, System2 system, UserSession userSession) {
- this.dbClient = dbClient;
- this.componentService = componentService;
- this.system = system;
- 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) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- IssueQuery.Builder builder = IssueQuery.builder()
- .issueKeys(request.getIssues())
- .severities(request.getSeverities())
- .statuses(request.getStatuses())
- .resolutions(request.getResolutions())
- .resolved(request.getResolved())
- .rules(stringsToRules(request.getRules()))
- .assignees(buildAssignees(request.getAssignees()))
- .languages(request.getLanguages())
- .tags(request.getTags())
- .types(request.getTypes())
- .assigned(request.getAssigned())
- .createdAt(parseDateOrDateTime(request.getCreatedAt()))
- .createdBefore(parseEndingDateOrDateTime(request.getCreatedBefore()))
- .facetMode(request.getFacetMode())
- .organizationUuid(convertOrganizationKeyToUuid(dbSession, request.getOrganization()));
-
- Set<String> allComponentUuids = Sets.newHashSet();
- boolean effectiveOnComponentOnly = mergeDeprecatedComponentParameters(dbSession,
- request.getOnComponentOnly(),
- request.getComponents(),
- request.getComponentUuids(),
- request.getComponentKeys(),
- request.getComponentRootUuids(),
- request.getComponentRoots(),
- allComponentUuids);
-
- addComponentParameters(builder, dbSession,
- effectiveOnComponentOnly,
- allComponentUuids,
- request.getProjectUuids(),
- request.getProjectKeys(),
- request.getModuleUuids(),
- request.getDirectories(),
- request.getFileUuids(),
- request.getAuthors());
-
- builder.createdAfter(buildCreatedAfterFromRequest(dbSession, request, allComponentUuids));
-
- String sort = request.getSort();
- if (!Strings.isNullOrEmpty(sort)) {
- builder.sort(sort);
- builder.asc(request.getAsc());
- }
- return builder.build();
-
- }
- }
-
- @CheckForNull
- private String convertOrganizationKeyToUuid(DbSession dbSession, @Nullable String organizationKey) {
- if (organizationKey == null) {
- return null;
- }
- Optional<OrganizationDto> organization = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
- return organization.map(OrganizationDto::getUuid).orElse(UNKNOWN);
- }
-
- private Date buildCreatedAfterFromRequest(DbSession dbSession, SearchWsRequest request, Set<String> componentUuids) {
- Date createdAfter = parseStartingDateOrDateTime(request.getCreatedAfter());
- String createdInLast = request.getCreatedInLast();
-
- if (request.getSinceLeakPeriod() == null || !request.getSinceLeakPeriod()) {
- return buildCreatedAfterFromDates(createdAfter, createdInLast);
- }
-
- checkRequest(createdAfter == null, "'%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");
- String uuid = componentUuids.iterator().next();
- Date createdAfterFromSnapshot = findCreatedAfterFromComponentUuid(dbSession, uuid);
- return buildCreatedAfterFromDates(createdAfterFromSnapshot, createdInLast);
- }
-
- @CheckForNull
- private Date findCreatedAfterFromComponentUuid(DbSession dbSession, String uuid) {
- ComponentDto component = checkFoundWithOptional(dbClient.componentDao().selectByUuid(dbSession, uuid), "Component with id '%s' not found", uuid);
- Optional<SnapshotDto> snapshot = dbClient.snapshotDao().selectLastAnalysisByComponentUuid(dbSession, component.uuid());
- return snapshot.map(s -> longToDate(s.getPeriodDate())).orElse(null);
- }
-
- private List<String> buildAssignees(@Nullable List<String> assigneesFromParams) {
- List<String> assignees = Lists.newArrayList();
- if (assigneesFromParams != null) {
- assignees.addAll(assigneesFromParams);
- }
- if (assignees.contains(LOGIN_MYSELF)) {
- String login = userSession.getLogin();
- if (login == null) {
- assignees.add(UNKNOWN);
- } else {
- assignees.add(login);
- }
- }
- return assignees;
- }
-
- private boolean mergeDeprecatedComponentParameters(DbSession session, @Nullable Boolean onComponentOnly,
- @Nullable Collection<String> components,
- @Nullable Collection<String> componentUuids,
- @Nullable Collection<String> componentKeys,
- @Nullable Collection<String> componentRootUuids,
- @Nullable Collection<String> componentRoots,
- Set<String> allComponentUuids) {
- boolean effectiveOnComponentOnly = false;
-
- checkArgument(atMostOneNonNullElement(components, componentUuids, componentKeys, componentRootUuids, componentRoots),
- "At most one of the following parameters can be provided: %s, %s, %s, %s, %s",
- PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS, PARAM_COMPONENTS, PARAM_COMPONENT_ROOTS, PARAM_COMPONENT_UUIDS);
-
- if (componentRootUuids != null) {
- allComponentUuids.addAll(componentRootUuids);
- effectiveOnComponentOnly = false;
- } else if (componentRoots != null) {
- allComponentUuids.addAll(componentUuids(session, componentRoots));
- effectiveOnComponentOnly = false;
- } else if (components != null) {
- allComponentUuids.addAll(componentUuids(session, components));
- effectiveOnComponentOnly = true;
- } else if (componentUuids != null) {
- allComponentUuids.addAll(componentUuids);
- effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
- } else if (componentKeys != null) {
- allComponentUuids.addAll(componentUuids(session, componentKeys));
- effectiveOnComponentOnly = BooleanUtils.isTrue(onComponentOnly);
- }
- return effectiveOnComponentOnly;
- }
-
- private static boolean atMostOneNonNullElement(Object... objects) {
- return !from(Arrays.asList(objects))
- .filter(notNull())
- .anyMatch(new HasTwoOrMoreElements());
- }
-
- private void addComponentParameters(IssueQuery.Builder builder, DbSession session,
- boolean onComponentOnly,
- Collection<String> componentUuids,
- @Nullable Collection<String> projectUuids, @Nullable Collection<String> projects,
- @Nullable Collection<String> moduleUuids,
- @Nullable Collection<String> directories,
- @Nullable Collection<String> fileUuids,
- @Nullable Collection<String> authors) {
-
- builder.onComponentOnly(onComponentOnly);
- if (onComponentOnly) {
- builder.componentUuids(componentUuids);
- return;
- }
-
- builder.authors(authors);
- checkArgument(projectUuids == null || projects == null, "projects and projectUuids cannot be set simultaneously");
- if (projectUuids != null) {
- builder.projectUuids(projectUuids);
- } else {
- builder.projectUuids(componentUuids(session, projects));
- }
- builder.moduleUuids(moduleUuids);
- builder.directories(directories);
- builder.fileUuids(fileUuids);
-
- if (!componentUuids.isEmpty()) {
- addComponentsBasedOnQualifier(builder, session, 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>)
- builder.componentUuids(componentUuids);
- 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();
- switch (uniqueQualifier) {
- case Qualifiers.VIEW:
- case Qualifiers.SUBVIEW:
- addViewsOrSubViews(builder, componentUuids, uniqueQualifier);
- break;
- case Qualifiers.PROJECT:
- builder.projectUuids(componentUuids);
- break;
- case Qualifiers.MODULE:
- builder.moduleRootUuids(componentUuids);
- break;
- case Qualifiers.DIRECTORY:
- addDirectories(builder, session, componentUuids);
- break;
- case Qualifiers.FILE:
- case Qualifiers.UNIT_TEST_FILE:
- builder.fileUuids(componentUuids);
- break;
- default:
- throw new IllegalArgumentException("Unable to set search root context for components " + Joiner.on(',').join(componentUuids));
- }
- }
-
- 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))) {
- filteredViewUuids.add(viewUuid);
- }
- }
- if (filteredViewUuids.isEmpty()) {
- filteredViewUuids.add(UNKNOWN);
- }
- builder.viewUuids(filteredViewUuids);
- }
-
- private void addDirectories(IssueQuery.Builder builder, DbSession session, Collection<String> componentUuids) {
- Collection<String> directoryModuleUuids = Sets.newHashSet();
- Collection<String> directoryPaths = Sets.newHashSet();
- for (ComponentDto directory : componentService.getByUuids(session, componentUuids)) {
- directoryModuleUuids.add(directory.moduleUuid());
- directoryPaths.add(directory.path());
- }
- builder.moduleUuids(directoryModuleUuids);
- 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));
- // 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.
- if (componentKeys != null && !componentKeys.isEmpty() && componentUuids.isEmpty()) {
- componentUuids.add(UNKNOWN);
- }
- return componentUuids;
- }
-
- @VisibleForTesting
- static Collection<RuleKey> toRules(@Nullable Object o) {
- Collection<RuleKey> result = null;
- if (o != null) {
- if (o instanceof List) {
- // assume that it contains only strings
- result = stringsToRules((List<String>) o);
- } else if (o instanceof String) {
- result = stringsToRules(newArrayList(Splitter.on(',').omitEmptyStrings().split((String) o)));
- }
- }
- return result;
- }
-
- @CheckForNull
- private static Collection<RuleKey> stringsToRules(@Nullable Collection<String> rules) {
- if (rules != null) {
- return Collections2.transform(rules, RuleKey::parse);
- }
- 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;
- }
- }
-}
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.server.issue.IssueQuery;
-import org.sonar.server.issue.IssueQueryService;
+import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.IssueService;
import org.sonarqube.ws.client.issue.IssuesWsParameters;
public class ComponentTagsAction implements IssuesWsAction {
private final IssueService service;
- private final IssueQueryService queryService;
+ private final IssueQueryFactory queryService;
- public ComponentTagsAction(IssueService service, IssueQueryService queryService) {
+ public ComponentTagsAction(IssueService service, IssueQueryFactory queryService) {
this.service = service;
this.queryService = queryService;
}
import org.sonar.server.issue.ActionFinder;
import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.IssueFinder;
-import org.sonar.server.issue.IssueQueryService;
+import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.IssueService;
import org.sonar.server.issue.IssueUpdater;
import org.sonar.server.issue.ServerIssueStorage;
FunctionExecutor.class,
IssueWorkflow.class,
IssueService.class,
- IssueQueryService.class,
+ IssueQueryFactory.class,
IssuesWs.class,
AvatarFactoryImpl.class,
SearchResponseLoader.class,
import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.SearchResult;
import org.sonar.server.issue.IssueQuery;
-import org.sonar.server.issue.IssueQueryService;
+import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.index.IssueDoc;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.user.UserSession;
private final UserSession userSession;
private final IssueIndex issueIndex;
- private final IssueQueryService issueQueryService;
+ private final IssueQueryFactory issueQueryFactory;
private final SearchResponseLoader searchResponseLoader;
private final SearchResponseFormat searchResponseFormat;
- public SearchAction(UserSession userSession, IssueIndex issueIndex, IssueQueryService issueQueryService,
+ public SearchAction(UserSession userSession, IssueIndex issueIndex, IssueQueryFactory issueQueryFactory,
SearchResponseLoader searchResponseLoader, SearchResponseFormat searchResponseFormat) {
this.userSession = userSession;
this.issueIndex = issueIndex;
- this.issueQueryService = issueQueryService;
+ this.issueQueryFactory = issueQueryFactory;
this.searchResponseLoader = searchResponseLoader;
this.searchResponseFormat = searchResponseFormat;
}
// prepare the Elasticsearch request
SearchOptions options = createSearchOptionsFromRequest(request);
EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request);
- IssueQuery query = issueQueryService.createFromRequest(request);
+ IssueQuery query = issueQueryFactory.createFromRequest(request);
// execute request
SearchResult<IssueDoc> result = issueIndex.search(query, options);
List<String> assigneesFromRequest = request.getAssignees();
if (assigneesFromRequest != null) {
assignees.addAll(assigneesFromRequest);
- assignees.remove(IssueQueryService.LOGIN_MYSELF);
+ assignees.remove(IssueQueryFactory.LOGIN_MYSELF);
}
addMandatoryValuesToFacet(facets, PARAM_ASSIGNEES, assignees);
addMandatoryValuesToFacet(facets, FACET_ASSIGNED_TO_ME, singletonList(userSession.getLogin()));
return;
}
requestParams.stream()
- .filter(param -> !buckets.containsKey(param) && !IssueQueryService.LOGIN_MYSELF.equals(param))
+ .filter(param -> !buckets.containsKey(param) && !IssueQueryFactory.LOGIN_MYSELF.equals(param))
// Prevent appearance of a glitch value due to dedicated parameter for this facet
.forEach(param -> buckets.put(param, 0L));
});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.issue;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.api.web.UserRole;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.component.ComponentService;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonarqube.ws.client.issue.SearchWsRequest;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class IssueQueryFactoryTest {
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public DbTester db = DbTester.create();
+
+ private ComponentService componentService = new ComponentService(db.getDbClient(), userSession);
+ private System2 system = mock(System2.class);
+ private IssueQueryFactory underTest = new IssueQueryFactory(db.getDbClient(), componentService, system, userSession);
+
+ @Test
+ public void create_from_parameters() {
+ OrganizationDto organization = db.organizations().insert();
+ ComponentDto project = db.components().insertProject(organization);
+ ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(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);
+
+ assertThat(query.issueKeys()).containsOnly("anIssueKey");
+ assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
+ assertThat(query.statuses()).containsOnly("CLOSED");
+ assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
+ assertThat(query.resolved()).isTrue();
+ assertThat(query.projectUuids()).containsOnly(project.uuid());
+ assertThat(query.moduleUuids()).containsOnly(module.uuid());
+ assertThat(query.fileUuids()).containsOnly(file.uuid());
+ assertThat(query.assignees()).containsOnly("joanna");
+ assertThat(query.languages()).containsOnly("xoo");
+ assertThat(query.tags()).containsOnly("tag1", "tag2");
+ assertThat(query.organizationUuid()).isEqualTo(organization.getUuid());
+ assertThat(query.onComponentOnly()).isFalse();
+ assertThat(query.assigned()).isTrue();
+ assertThat(query.hideRules()).isTrue();
+ assertThat(query.rules()).hasSize(2);
+ assertThat(query.directories()).containsOnly("aDirPath");
+ assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
+ assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
+ assertThat(query.sort()).isEqualTo(IssueQuery.SORT_BY_CREATION_DATE);
+ assertThat(query.asc()).isTrue();
+ }
+
+ @Test
+ public void dates_are_inclusive() {
+ SearchWsRequest request = new SearchWsRequest()
+ .setCreatedAfter("2013-04-16")
+ .setCreatedBefore("2013-04-17");
+
+ IssueQuery query = underTest.createFromRequest(request);
+
+ assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDate("2013-04-16"));
+ assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDate("2013-04-18"));
+ }
+
+ @Test
+ public void add_unknown_when_no_component_found() {
+ Map<String, Object> map = new HashMap<>();
+ map.put("components", newArrayList("does_not_exist"));
+
+ IssueQuery query = underTest.createFromMap(map);
+ assertThat(query.componentUuids()).containsOnly("<UNKNOWN>");
+ }
+
+ @Test
+ public void parse_list_of_rules() {
+ assertThat(IssueQueryFactory.toRules(null)).isNull();
+ assertThat(IssueQueryFactory.toRules("")).isEmpty();
+ assertThat(IssueQueryFactory.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
+ assertThat(IssueQueryFactory.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+ assertThat(IssueQueryFactory.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
+ }
+
+ @Test
+ 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"));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");
+
+ underTest.createFromMap(map);
+ }
+
+ @Test
+ 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"));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("projects and projectUuids cannot be set simultaneously");
+
+ underTest.createFromMap(map);
+ }
+
+ @Test
+ 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"));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");
+
+ underTest.createFromMap(map);
+ }
+
+ @Test
+ public void fail_if_componentRoots_references_components_with_different_qualifier() {
+ ComponentDto project = db.components().insertProject();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentRoots", newArrayList(project.key(), file.key()));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("All components must have the same qualifier, found FIL,TRK");
+
+ underTest.createFromMap(map);
+ }
+
+ @Test
+ public void param_componentRootUuids_enables_search_in_view_tree_if_user_has_permission_on_view() {
+ ComponentDto view = db.components().insertView();
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentRootUuids", newArrayList(view.uuid()));
+ userSession.addProjectUuidPermissions(UserRole.USER, view.uuid());
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.viewUuids()).containsOnly(view.uuid());
+ assertThat(query.onComponentOnly()).isFalse();
+ }
+
+ @Test
+ public void return_empty_results_if_not_allowed_to_search_for_subview() {
+ ComponentDto view = db.components().insertView();
+ ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view));
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentRootUuids", newArrayList(subView.uuid()));
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.viewUuids()).containsOnly("<UNKNOWN>");
+ }
+
+ @Test
+ public void param_componentUuids_enables_search_on_project_tree_by_default() {
+ ComponentDto project = db.components().insertProject();
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentUuids", newArrayList(project.uuid()));
+
+ IssueQuery query = underTest.createFromMap(map);
+ assertThat(query.projectUuids()).containsExactly(project.uuid());
+ assertThat(query.onComponentOnly()).isFalse();
+ }
+
+ @Test
+ public void onComponentOnly_restricts_search_to_specified_componentKeys() {
+ ComponentDto project = db.components().insertProject();
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentKeys", newArrayList(project.key()));
+ map.put("onComponentOnly", true);
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.projectUuids()).isEmpty();
+ assertThat(query.componentUuids()).containsExactly(project.uuid());
+ assertThat(query.onComponentOnly()).isTrue();
+ }
+
+ @Test
+ public void should_search_in_tree_with_module_uuid() {
+ ComponentDto project = db.components().insertProject();
+ ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentUuids", newArrayList(module.uuid()));
+
+ IssueQuery query = underTest.createFromMap(map);
+ assertThat(query.moduleRootUuids()).containsExactly(module.uuid());
+ assertThat(query.onComponentOnly()).isFalse();
+ }
+
+ @Test
+ public void param_componentUuids_enables_search_in_directory_tree() {
+ ComponentDto project = db.components().insertProject();
+ ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentUuids", newArrayList(dir.uuid()));
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.moduleUuids()).containsOnly(dir.moduleUuid());
+ assertThat(query.directories()).containsOnly(dir.path());
+ assertThat(query.onComponentOnly()).isFalse();
+ }
+
+ @Test
+ public void param_componentUuids_enables_search_by_file() {
+ ComponentDto project = db.components().insertProject();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ Map<String, Object> map = new HashMap<>();
+ map.put("componentUuids", newArrayList(file.uuid()));
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.fileUuids()).containsExactly(file.uuid());
+ }
+
+ @Test
+ public void param_componentUuids_enables_search_by_test_file() {
+ ComponentDto project = db.components().insertProject();
+ 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()));
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.fileUuids()).containsExactly(file.uuid());
+ }
+
+ @Test
+ 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");
+
+ try {
+ underTest.createFromMap(map);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("createdAfter and createdInLast cannot be set simultaneously");
+ }
+ }
+
+ @Test
+ public void set_created_after_from_created_since() {
+ Date now = DateUtils.parseDateTime("2013-07-25T07:35:00+0100");
+ 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"));
+ }
+
+ @Test
+ public void fail_if_since_leak_period_and_created_after_set_at_the_same_time() {
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously");
+
+ underTest.createFromRequest(new SearchWsRequest()
+ .setSinceLeakPeriod(true)
+ .setCreatedAfter("2013-07-25T07:35:00+0100"));
+ }
+
+ @Test
+ public void fail_if_no_component_provided_with_since_leak_period() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("One and only one component must be provided when searching since leak period");
+
+ underTest.createFromRequest(new SearchWsRequest().setSinceLeakPeriod(true));
+ }
+
+ @Test
+ public void fail_if_several_components_provided_with_since_leak_period() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("One and only one component must be provided when searching since leak period");
+
+ underTest.createFromRequest(new SearchWsRequest()
+ .setSinceLeakPeriod(true)
+ .setComponentUuids(newArrayList("component-uuid", "project-uuid")));
+ }
+
+ @Test
+ public void fail_if_date_is_not_formatted_correctly() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("'unknown-date' cannot be parsed as either a date or date+time");
+
+ underTest.createFromRequest(new SearchWsRequest()
+ .setCreatedAfter("unknown-date"));
+ }
+
+ @Test
+ 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");
+
+ IssueQuery query = underTest.createFromMap(map);
+
+ assertThat(query.organizationUuid()).isEqualTo("<UNKNOWN>");
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.issue;
-
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
-import org.sonar.db.organization.OrganizationDto;
-import org.sonar.server.component.ComponentService;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonarqube.ws.client.issue.SearchWsRequest;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class IssueQueryServiceTest {
-
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
- @Rule
- public DbTester db = DbTester.create();
-
- private ComponentService componentService = new ComponentService(db.getDbClient(), userSession);
- private System2 system = mock(System2.class);
- private IssueQueryService underTest = new IssueQueryService(db.getDbClient(), componentService, system, userSession);
-
- @Test
- public void create_from_parameters() {
- OrganizationDto organization = db.organizations().insert();
- ComponentDto project = db.components().insertProject(organization);
- ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(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);
-
- assertThat(query.issueKeys()).containsOnly("anIssueKey");
- assertThat(query.severities()).containsOnly("MAJOR", "MINOR");
- assertThat(query.statuses()).containsOnly("CLOSED");
- assertThat(query.resolutions()).containsOnly("FALSE-POSITIVE");
- assertThat(query.resolved()).isTrue();
- assertThat(query.projectUuids()).containsOnly(project.uuid());
- assertThat(query.moduleUuids()).containsOnly(module.uuid());
- assertThat(query.fileUuids()).containsOnly(file.uuid());
- assertThat(query.assignees()).containsOnly("joanna");
- assertThat(query.languages()).containsOnly("xoo");
- assertThat(query.tags()).containsOnly("tag1", "tag2");
- assertThat(query.organizationUuid()).isEqualTo(organization.getUuid());
- assertThat(query.onComponentOnly()).isFalse();
- assertThat(query.assigned()).isTrue();
- assertThat(query.hideRules()).isTrue();
- assertThat(query.rules()).hasSize(2);
- assertThat(query.directories()).containsOnly("aDirPath");
- assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDateTime("2013-04-16T09:08:24+0200"));
- assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDateTime("2013-04-17T09:08:24+0200"));
- assertThat(query.sort()).isEqualTo(IssueQuery.SORT_BY_CREATION_DATE);
- assertThat(query.asc()).isTrue();
- }
-
- @Test
- public void dates_are_inclusive() {
- SearchWsRequest request = new SearchWsRequest()
- .setCreatedAfter("2013-04-16")
- .setCreatedBefore("2013-04-17");
-
- IssueQuery query = underTest.createFromRequest(request);
-
- assertThat(query.createdAfter()).isEqualTo(DateUtils.parseDate("2013-04-16"));
- assertThat(query.createdBefore()).isEqualTo(DateUtils.parseDate("2013-04-18"));
- }
-
- @Test
- public void add_unknown_when_no_component_found() {
- Map<String, Object> map = new HashMap<>();
- map.put("components", newArrayList("does_not_exist"));
-
- IssueQuery query = underTest.createFromMap(map);
- assertThat(query.componentUuids()).containsOnly("<UNKNOWN>");
- }
-
- @Test
- public void parse_list_of_rules() {
- assertThat(IssueQueryService.toRules(null)).isNull();
- assertThat(IssueQueryService.toRules("")).isEmpty();
- assertThat(IssueQueryService.toRules("squid:AvoidCycle")).containsOnly(RuleKey.of("squid", "AvoidCycle"));
- assertThat(IssueQueryService.toRules("squid:AvoidCycle,findbugs:NullRef")).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
- assertThat(IssueQueryService.toRules(asList("squid:AvoidCycle", "findbugs:NullRef"))).containsOnly(RuleKey.of("squid", "AvoidCycle"), RuleKey.of("findbugs", "NullRef"));
- }
-
- @Test
- 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"));
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");
-
- underTest.createFromMap(map);
- }
-
- @Test
- 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"));
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("projects and projectUuids cannot be set simultaneously");
-
- underTest.createFromMap(map);
- }
-
- @Test
- 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"));
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("At most one of the following parameters can be provided: componentKeys, componentUuids, components, componentRoots, componentUuids");
-
- underTest.createFromMap(map);
- }
-
- @Test
- public void fail_if_componentRoots_references_components_with_different_qualifier() {
- ComponentDto project = db.components().insertProject();
- ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
- Map<String, Object> map = new HashMap<>();
- map.put("componentRoots", newArrayList(project.key(), file.key()));
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("All components must have the same qualifier, found FIL,TRK");
-
- underTest.createFromMap(map);
- }
-
- @Test
- public void param_componentRootUuids_enables_search_in_view_tree_if_user_has_permission_on_view() {
- ComponentDto view = db.components().insertView();
- Map<String, Object> map = new HashMap<>();
- map.put("componentRootUuids", newArrayList(view.uuid()));
- userSession.addProjectUuidPermissions(UserRole.USER, view.uuid());
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.viewUuids()).containsOnly(view.uuid());
- assertThat(query.onComponentOnly()).isFalse();
- }
-
- @Test
- public void return_empty_results_if_not_allowed_to_search_for_subview() {
- ComponentDto view = db.components().insertView();
- ComponentDto subView = db.components().insertComponent(ComponentTesting.newSubView(view));
- Map<String, Object> map = new HashMap<>();
- map.put("componentRootUuids", newArrayList(subView.uuid()));
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.viewUuids()).containsOnly("<UNKNOWN>");
- }
-
- @Test
- public void param_componentUuids_enables_search_on_project_tree_by_default() {
- ComponentDto project = db.components().insertProject();
- Map<String, Object> map = new HashMap<>();
- map.put("componentUuids", newArrayList(project.uuid()));
-
- IssueQuery query = underTest.createFromMap(map);
- assertThat(query.projectUuids()).containsExactly(project.uuid());
- assertThat(query.onComponentOnly()).isFalse();
- }
-
- @Test
- public void onComponentOnly_restricts_search_to_specified_componentKeys() {
- ComponentDto project = db.components().insertProject();
- Map<String, Object> map = new HashMap<>();
- map.put("componentKeys", newArrayList(project.key()));
- map.put("onComponentOnly", true);
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.projectUuids()).isEmpty();
- assertThat(query.componentUuids()).containsExactly(project.uuid());
- assertThat(query.onComponentOnly()).isTrue();
- }
-
- @Test
- public void should_search_in_tree_with_module_uuid() {
- ComponentDto project = db.components().insertProject();
- ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
- Map<String, Object> map = new HashMap<>();
- map.put("componentUuids", newArrayList(module.uuid()));
-
- IssueQuery query = underTest.createFromMap(map);
- assertThat(query.moduleRootUuids()).containsExactly(module.uuid());
- assertThat(query.onComponentOnly()).isFalse();
- }
-
- @Test
- public void param_componentUuids_enables_search_in_directory_tree() {
- ComponentDto project = db.components().insertProject();
- ComponentDto dir = db.components().insertComponent(ComponentTesting.newDirectory(project, "src/main/java/foo"));
- Map<String, Object> map = new HashMap<>();
- map.put("componentUuids", newArrayList(dir.uuid()));
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.moduleUuids()).containsOnly(dir.moduleUuid());
- assertThat(query.directories()).containsOnly(dir.path());
- assertThat(query.onComponentOnly()).isFalse();
- }
-
- @Test
- public void param_componentUuids_enables_search_by_file() {
- ComponentDto project = db.components().insertProject();
- ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
- Map<String, Object> map = new HashMap<>();
- map.put("componentUuids", newArrayList(file.uuid()));
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.fileUuids()).containsExactly(file.uuid());
- }
-
- @Test
- public void param_componentUuids_enables_search_by_test_file() {
- ComponentDto project = db.components().insertProject();
- 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()));
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.fileUuids()).containsExactly(file.uuid());
- }
-
- @Test
- 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");
-
- try {
- underTest.createFromMap(map);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("createdAfter and createdInLast cannot be set simultaneously");
- }
- }
-
- @Test
- public void set_created_after_from_created_since() {
- Date now = DateUtils.parseDateTime("2013-07-25T07:35:00+0100");
- 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"));
- }
-
- @Test
- public void fail_if_since_leak_period_and_created_after_set_at_the_same_time() {
- expectedException.expect(BadRequestException.class);
- expectedException.expectMessage("'createdAfter' and 'sinceLeakPeriod' cannot be set simultaneously");
-
- underTest.createFromRequest(new SearchWsRequest()
- .setSinceLeakPeriod(true)
- .setCreatedAfter("2013-07-25T07:35:00+0100"));
- }
-
- @Test
- public void fail_if_no_component_provided_with_since_leak_period() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("One and only one component must be provided when searching since leak period");
-
- underTest.createFromRequest(new SearchWsRequest().setSinceLeakPeriod(true));
- }
-
- @Test
- public void fail_if_several_components_provided_with_since_leak_period() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("One and only one component must be provided when searching since leak period");
-
- underTest.createFromRequest(new SearchWsRequest()
- .setSinceLeakPeriod(true)
- .setComponentUuids(newArrayList("component-uuid", "project-uuid")));
- }
-
- @Test
- public void fail_if_date_is_not_formatted_correctly() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("'unknown-date' cannot be parsed as either a date or date+time");
-
- underTest.createFromRequest(new SearchWsRequest()
- .setCreatedAfter("unknown-date"));
- }
-
- @Test
- 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");
-
- IssueQuery query = underTest.createFromMap(map);
-
- assertThat(query.organizationUuid()).isEqualTo("<UNKNOWN>");
- }
-}
import org.sonar.api.server.ws.WebService.Action;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.server.issue.IssueQuery;
-import org.sonar.server.issue.IssueQueryService;
+import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.IssueService;
import org.sonar.server.ws.WsTester;
private IssueService service;
@Mock
- private IssueQueryService queryService;
+ private IssueQueryFactory queryService;
private ComponentTagsAction componentTagsAction;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
-import org.sonar.server.issue.IssueQueryService;
+import org.sonar.server.issue.IssueQueryFactory;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
public UserSessionRule userSession = UserSessionRule.standalone();
private IssueIndex index = mock(IssueIndex.class);
- private IssueQueryService issueQueryService = mock(IssueQueryService.class);
+ private IssueQueryFactory issueQueryFactory = mock(IssueQueryFactory.class);
private SearchResponseLoader searchResponseLoader = mock(SearchResponseLoader.class);
private SearchResponseFormat searchResponseFormat = mock(SearchResponseFormat.class);
- private SearchAction underTest = new SearchAction(userSession, index, issueQueryService, searchResponseLoader, searchResponseFormat);
+ private SearchAction underTest = new SearchAction(userSession, index, issueQueryFactory, searchResponseLoader, searchResponseFormat);
private WsActionTester wsTester = new WsActionTester(underTest);
@Test