From 6d24aaa1516a0a1b5d92eceb2495b92ccbc7182c Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Mon, 3 Jul 2017 18:03:09 +0200 Subject: SONAR-9476 Add from and to params in api/project_analyses/search --- .../server/measure/ws/SearchHistoryAction.java | 6 +- .../server/projectanalysis/ws/SearchAction.java | 99 ++++++++-------- .../server/projectanalysis/ws/SearchData.java | 132 +++++++++++++++++++++ .../projectanalysis/ws/SearchResponseBuilder.java | 78 ++++++------ .../server/projectanalysis/ws/SearchResults.java | 132 --------------------- .../projectanalysis/ws/SearchActionTest.java | 99 +++++++++++++++- 6 files changed, 321 insertions(+), 225 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResults.java (limited to 'server') diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java index b916f287e68..3f5995a005d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java @@ -106,11 +106,11 @@ public class SearchHistoryAction implements MeasuresWsAction { action.createParam(PARAM_FROM) .setDescription("Filter measures created after the given date (inclusive). Format: date or datetime ISO formats") - .setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)"); + .setExampleValue("2013-05-01T13:00:00+0100"); action.createParam(PARAM_TO) - .setDescription("Filter issues created before the given date (inclusive). Format: date or datetime ISO formats") - .setExampleValue("2013-05-01 (or 2013-05-01T13:00:00+0100)"); + .setDescription("Filter measures created before the given date (inclusive). Format: date or datetime ISO formats") + .setExampleValue("2013-05-01"); action.addPagingParams(DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchAction.java index 5505546966d..1acead3883e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchAction.java @@ -21,9 +21,6 @@ package org.sonar.server.projectanalysis.ws; import java.util.EnumSet; import java.util.List; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Stream; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Scopes; import org.sonar.api.server.ws.Request; @@ -45,13 +42,17 @@ import org.sonarqube.ws.client.projectanalysis.EventCategory; import org.sonarqube.ws.client.projectanalysis.SearchRequest; import static com.google.common.base.Preconditions.checkArgument; -import static org.sonar.core.util.stream.MoreCollectors.toOneElement; +import static org.sonar.api.utils.DateUtils.parseEndingDateOrDateTime; +import static org.sonar.api.utils.DateUtils.parseStartingDateOrDateTime; +import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.db.component.SnapshotQuery.SORT_FIELD.BY_DATE; import static org.sonar.db.component.SnapshotQuery.SORT_ORDER.DESC; import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.client.projectanalysis.EventCategory.OTHER; import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_CATEGORY; +import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_FROM; import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_PROJECT; +import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_TO; import static org.sonarqube.ws.client.projectanalysis.SearchRequest.DEFAULT_PAGE_SIZE; public class SearchAction implements ProjectAnalysesWsAction { @@ -85,69 +86,71 @@ public class SearchAction implements ProjectAnalysesWsAction { .setDescription("Event category. Filter analyses that have at least one event of the category specified.") .setPossibleValues(EnumSet.allOf(EventCategory.class)) .setExampleValue(OTHER.name()); + + action.createParam(PARAM_FROM) + .setDescription("Filter analyses created after the given date (inclusive). Format: date or datetime ISO formats") + .setExampleValue("2013-05-01") + .setSince("6.5"); + + action.createParam(PARAM_TO) + .setDescription("Filter analyses created before the given date (inclusive). Format: date or datetime ISO formats") + .setExampleValue("2013-05-01T13:00:00+0100") + .setSince("6.5"); } @Override public void handle(Request request, Response response) throws Exception { - ProjectAnalyses.SearchResponse searchResponse = Stream.of(request) - .map(toWsRequest()) - .map(this::search) - .map(new SearchResponseBuilder().buildWsResponse()) - .collect(toOneElement()); + SearchData searchData = load(toWsRequest(request)); + ProjectAnalyses.SearchResponse searchResponse = new SearchResponseBuilder(searchData).build(); writeProtobuf(searchResponse, request, response); } - private static Function toWsRequest() { - return request -> { - String category = request.param(PARAM_CATEGORY); - return SearchRequest.builder() - .setProject(request.mandatoryParam(PARAM_PROJECT)) - .setCategory(category == null ? null : EventCategory.valueOf(category)) - .setPage(request.mandatoryParamAsInt(Param.PAGE)) - .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) - .build(); - }; + private static SearchRequest toWsRequest(Request request) { + String category = request.param(PARAM_CATEGORY); + return SearchRequest.builder() + .setProject(request.mandatoryParam(PARAM_PROJECT)) + .setCategory(category == null ? null : EventCategory.valueOf(category)) + .setPage(request.mandatoryParamAsInt(Param.PAGE)) + .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)) + .setFrom(request.param(PARAM_FROM)) + .setTo(request.param(PARAM_TO)) + .build(); } - private SearchResults search(SearchRequest request) { + private SearchData load(SearchRequest request) { try (DbSession dbSession = dbClient.openSession(false)) { - return Stream.of(SearchResults.builder(dbSession, request)) - .peek(addProject()) - .peek(checkPermission()) - .peek(addAnalyses()) - .peek(addEvents()) - .map(SearchResults.Builder::build) - .collect(toOneElement()); + SearchData.Builder searchResults = SearchData.builder(dbSession, request); + addProject(searchResults); + checkPermission(searchResults.getProject()); + addAnalyses(searchResults); + addEvents(searchResults); + return searchResults.build(); } } - private Consumer addAnalyses() { - return data -> { - SnapshotQuery dbQuery = new SnapshotQuery() - .setComponentUuid(data.getProject().uuid()) - .setStatus(SnapshotDto.STATUS_PROCESSED) - .setSort(BY_DATE, DESC); - data.setAnalyses(dbClient.snapshotDao().selectAnalysesByQuery(data.getDbSession(), dbQuery)); - }; + private void addAnalyses(SearchData.Builder data) { + SnapshotQuery dbQuery = new SnapshotQuery() + .setComponentUuid(data.getProject().uuid()) + .setStatus(SnapshotDto.STATUS_PROCESSED) + .setSort(BY_DATE, DESC); + setNullable(data.getRequest().getFrom(), from -> dbQuery.setCreatedAfter(parseStartingDateOrDateTime(from).getTime())); + setNullable(data.getRequest().getTo(), to -> dbQuery.setCreatedBefore(parseEndingDateOrDateTime(to).getTime() + 1_000L)); + data.setAnalyses(dbClient.snapshotDao().selectAnalysesByQuery(data.getDbSession(), dbQuery)); } - private Consumer addEvents() { - return data -> { - List analyses = data.getAnalyses().stream().map(SnapshotDto::getUuid).collect(MoreCollectors.toList()); - data.setEvents(dbClient.eventDao().selectByAnalysisUuids(data.getDbSession(), analyses)); - }; + private void addEvents(SearchData.Builder data) { + List analyses = data.getAnalyses().stream().map(SnapshotDto::getUuid).collect(MoreCollectors.toList()); + data.setEvents(dbClient.eventDao().selectByAnalysisUuids(data.getDbSession(), analyses)); } - private Consumer checkPermission() { - return data -> userSession.checkComponentPermission(UserRole.USER, data.getProject()); + private void checkPermission(ComponentDto project) { + userSession.checkComponentPermission(UserRole.USER, project); } - private Consumer addProject() { - return data -> { - ComponentDto project = componentFinder.getByKey(data.getDbSession(), data.getRequest().getProject()); - checkArgument(Scopes.PROJECT.equals(project.scope()) && Qualifiers.PROJECT.equals(project.qualifier()), "A project is required"); - data.setProject(project); - }; + private void addProject(SearchData.Builder data) { + ComponentDto project = componentFinder.getByKey(data.getDbSession(), data.getRequest().getProject()); + checkArgument(Scopes.PROJECT.equals(project.scope()) && Qualifiers.PROJECT.equals(project.qualifier()), "A project is required"); + data.setProject(project); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java new file mode 100644 index 00000000000..56ad72053a7 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java @@ -0,0 +1,132 @@ +/* + * 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.projectanalysis.ws; + +import com.google.common.collect.ListMultimap; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; +import org.sonar.api.utils.Paging; +import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.db.DbSession; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.SnapshotDto; +import org.sonar.db.event.EventDto; +import org.sonarqube.ws.client.projectanalysis.SearchRequest; + +import static java.util.Objects.requireNonNull; + +class SearchData { + final List analyses; + final ListMultimap eventsByAnalysis; + final Paging paging; + + private SearchData(Builder builder) { + this.analyses = builder.analyses; + this.eventsByAnalysis = buildEvents(builder.events); + this.paging = Paging + .forPageIndex(builder.getRequest().getPage()) + .withPageSize(builder.getRequest().getPageSize()) + .andTotal(builder.countAnalyses); + } + + private ListMultimap buildEvents(List events) { + return events.stream().collect(MoreCollectors.index(EventDto::getAnalysisUuid)); + } + + static Builder builder(DbSession dbSession, SearchRequest request) { + return new Builder(dbSession, request); + } + + static class Builder { + private final DbSession dbSession; + private final SearchRequest request; + private ComponentDto project; + private List analyses; + private int countAnalyses; + private List events; + + private Builder(DbSession dbSession, SearchRequest request) { + this.dbSession = dbSession; + this.request = request; + } + + Builder setProject(ComponentDto project) { + this.project = project; + return this; + } + + Builder setAnalyses(List analyses) { + Stream stream = analyses.stream(); + // no filter by category, the pagination can be applied + if (request.getCategory() == null) { + stream = stream + .skip(Paging.offset(request.getPage(), request.getPageSize())) + .limit(request.getPageSize()); + } + + this.analyses = stream.collect(MoreCollectors.toList()); + this.countAnalyses = analyses.size(); + return this; + } + + Builder setEvents(List events) { + this.events = events; + return this; + } + + DbSession getDbSession() { + return dbSession; + } + + SearchRequest getRequest() { + return request; + } + + ComponentDto getProject() { + return project; + } + + List getAnalyses() { + return analyses; + } + + private void filterByCategory() { + ListMultimap eventCategoriesByAnalysisUuid = events.stream() + .collect(MoreCollectors.index(EventDto::getAnalysisUuid, EventDto::getCategory)); + Predicate byCategory = a -> eventCategoriesByAnalysisUuid.get(a.getUuid()).contains(request.getCategory().getLabel()); + this.countAnalyses = (int) analyses.stream().filter(byCategory).count(); + this.analyses = analyses.stream() + .filter(byCategory) + .skip(Paging.offset(request.getPage(), request.getPageSize())) + .limit(request.getPageSize()) + .collect(MoreCollectors.toList()); + } + + SearchData build() { + requireNonNull(analyses); + requireNonNull(events); + if (request.getCategory() != null) { + filterByCategory(); + } + return new SearchData(this); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResponseBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResponseBuilder.java index 07152e97f19..41c0a746b3e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResponseBuilder.java +++ b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResponseBuilder.java @@ -19,10 +19,6 @@ */ package org.sonar.server.projectanalysis.ws; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Stream; -import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.component.SnapshotDto; import org.sonar.db.event.EventDto; import org.sonarqube.ws.ProjectAnalyses.Analysis; @@ -34,57 +30,59 @@ import static org.sonar.core.util.Protobuf.setNullable; import static org.sonarqube.ws.client.projectanalysis.EventCategory.fromLabel; class SearchResponseBuilder { - private final Analysis.Builder analysisBuilder; - private final Event.Builder eventBuilder; + private final Analysis.Builder wsAnalysis; + private final Event.Builder wsEvent; + private final SearchData searchData; - SearchResponseBuilder() { - this.analysisBuilder = Analysis.newBuilder(); - this.eventBuilder = Event.newBuilder(); + SearchResponseBuilder(SearchData searchData) { + this.wsAnalysis = Analysis.newBuilder(); + this.wsEvent = Event.newBuilder(); + this.searchData = searchData; } - Function buildWsResponse() { - return searchResults -> Stream.of(SearchResponse.newBuilder()) - .peek(addAnalyses(searchResults)) - .peek(addPagination(searchResults)) - .map(SearchResponse.Builder::build) - .collect(MoreCollectors.toOneElement()); + SearchResponse build() { + SearchResponse.Builder wsResponse = SearchResponse.newBuilder(); + addAnalyses(wsResponse); + addPagination(wsResponse); + return wsResponse.build(); } - private Consumer addAnalyses(SearchResults searchResults) { - return response -> searchResults.analyses.stream() - .map(dbToWsAnalysis()) - .peek(addEvents(searchResults)) - .forEach(response::addAnalyses); + private void addAnalyses(SearchResponse.Builder wsResponse) { + searchData.analyses.stream() + .map(this::dbToWsAnalysis) + .map(this::attachEvents) + .forEach(wsResponse::addAnalyses); } - private Function dbToWsAnalysis() { - return dbAnalysis -> analysisBuilder.clear() + private Analysis.Builder dbToWsAnalysis(SnapshotDto dbAnalysis) { + return wsAnalysis.clear() .setKey(dbAnalysis.getUuid()) .setDate(formatDateTime(dbAnalysis.getCreatedAt())); } - private Consumer addEvents(SearchResults searchResults) { - return wsAnalysis -> searchResults.eventsByAnalysis.get(wsAnalysis.getKey()).stream() - .map(dbToWsEvent()) - .forEach(wsAnalysis::addEvents); + private Analysis.Builder attachEvents(Analysis.Builder analysis) { + searchData.eventsByAnalysis.get(analysis.getKey()) + .stream() + .map(this::dbToWsEvent) + .forEach(analysis::addEvents); + return analysis; + } - private Function dbToWsEvent() { - return dbEvent -> { - Event.Builder wsEvent = eventBuilder.clear() - .setKey(dbEvent.getUuid()); - setNullable(dbEvent.getName(), wsEvent::setName); - setNullable(dbEvent.getDescription(), wsEvent::setDescription); - setNullable(dbEvent.getCategory(), cat -> wsEvent.setCategory(fromLabel(cat).name())); - return wsEvent; - }; + private Event.Builder dbToWsEvent(EventDto dbEvent) { + wsEvent.clear().setKey(dbEvent.getUuid()); + setNullable(dbEvent.getName(), wsEvent::setName); + setNullable(dbEvent.getDescription(), wsEvent::setDescription); + setNullable(dbEvent.getCategory(), cat -> wsEvent.setCategory(fromLabel(cat).name())); + + return wsEvent; } - private static Consumer addPagination(SearchResults searchResults) { - return response -> response.getPagingBuilder() - .setPageIndex(searchResults.paging.pageIndex()) - .setPageSize(searchResults.paging.pageSize()) - .setTotal(searchResults.paging.total()) + private void addPagination(SearchResponse.Builder wsResponse) { + wsResponse.getPagingBuilder() + .setPageIndex(searchData.paging.pageIndex()) + .setPageSize(searchData.paging.pageSize()) + .setTotal(searchData.paging.total()) .build(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResults.java b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResults.java deleted file mode 100644 index 8e725ccc6ae..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResults.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.projectanalysis.ws; - -import com.google.common.collect.ListMultimap; -import java.util.List; -import java.util.function.Predicate; -import java.util.stream.Stream; -import org.sonar.api.utils.Paging; -import org.sonar.core.util.stream.MoreCollectors; -import org.sonar.db.DbSession; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.component.SnapshotDto; -import org.sonar.db.event.EventDto; -import org.sonarqube.ws.client.projectanalysis.SearchRequest; - -import static java.util.Objects.requireNonNull; - -class SearchResults { - final List analyses; - final ListMultimap eventsByAnalysis; - final Paging paging; - - private SearchResults(Builder builder) { - this.analyses = builder.analyses; - this.eventsByAnalysis = buildEvents(builder.events); - this.paging = Paging - .forPageIndex(builder.getRequest().getPage()) - .withPageSize(builder.getRequest().getPageSize()) - .andTotal(builder.countAnalyses); - } - - private ListMultimap buildEvents(List events) { - return events.stream().collect(MoreCollectors.index(EventDto::getAnalysisUuid)); - } - - static Builder builder(DbSession dbSession, SearchRequest request) { - return new Builder(dbSession, request); - } - - static class Builder { - private final DbSession dbSession; - private final SearchRequest request; - private ComponentDto project; - private List analyses; - private int countAnalyses; - private List events; - - private Builder(DbSession dbSession, SearchRequest request) { - this.dbSession = dbSession; - this.request = request; - } - - Builder setProject(ComponentDto project) { - this.project = project; - return this; - } - - Builder setAnalyses(List analyses) { - Stream stream = analyses.stream(); - // no filter by category, the pagination can be applied - if (request.getCategory() == null) { - stream = stream - .skip(Paging.offset(request.getPage(), request.getPageSize())) - .limit(request.getPageSize()); - } - - this.analyses = stream.collect(MoreCollectors.toList()); - this.countAnalyses = analyses.size(); - return this; - } - - Builder setEvents(List events) { - this.events = events; - return this; - } - - DbSession getDbSession() { - return dbSession; - } - - SearchRequest getRequest() { - return request; - } - - ComponentDto getProject() { - return project; - } - - List getAnalyses() { - return analyses; - } - - private void filterByCategory() { - ListMultimap eventCategoriesByAnalysisUuid = events.stream() - .collect(MoreCollectors.index(EventDto::getAnalysisUuid, EventDto::getCategory)); - Predicate byCategory = a -> eventCategoriesByAnalysisUuid.get(a.getUuid()).contains(request.getCategory().getLabel()); - this.countAnalyses = (int) analyses.stream().filter(byCategory).count(); - this.analyses = analyses.stream() - .filter(byCategory) - .skip(Paging.offset(request.getPage(), request.getPageSize())) - .limit(request.getPageSize()) - .collect(MoreCollectors.toList()); - } - - SearchResults build() { - requireNonNull(analyses); - requireNonNull(events); - if (request.getCategory() != null) { - filterByCategory(); - } - return new SearchResults(this); - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/projectanalysis/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/projectanalysis/ws/SearchActionTest.java index 5189afc99f9..b40b4209ba4 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/projectanalysis/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/projectanalysis/ws/SearchActionTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.projectanalysis.ws; +import java.util.Date; import java.util.List; import java.util.function.Function; import java.util.stream.IntStream; @@ -51,6 +52,8 @@ import org.sonarqube.ws.client.projectanalysis.SearchRequest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; +import static org.sonar.api.utils.DateUtils.formatDate; +import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.api.utils.DateUtils.parseDateTime; import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.db.component.SnapshotTesting.newAnalysis; @@ -62,7 +65,9 @@ import static org.sonarqube.ws.client.projectanalysis.EventCategory.OTHER; import static org.sonarqube.ws.client.projectanalysis.EventCategory.QUALITY_GATE; import static org.sonarqube.ws.client.projectanalysis.EventCategory.VERSION; import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_CATEGORY; +import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_FROM; import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_PROJECT; +import static org.sonarqube.ws.client.projectanalysis.ProjectAnalysesWsParameters.PARAM_TO; public class SearchActionTest { @@ -218,6 +223,88 @@ public class SearchActionTest { .containsExactly(2, 1, 3); } + @Test + public void filter_from_date() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.addProjectPermission(UserRole.USER, project); + SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L)); + SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L)); + SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L)); + SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L)); + + SearchResponse result = call(SearchRequest.builder() + .setProject(project.key()) + .setFrom(formatDateTime(2_000_000_000L)) + .build()); + + assertThat(result.getAnalysesList()) + .extracting(Analysis::getKey) + .containsOnly(a2.getUuid(), a3.getUuid(), a4.getUuid()) + .doesNotContain(a1.getUuid()); + } + + @Test + public void filter_to_date() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.addProjectPermission(UserRole.USER, project); + SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L)); + SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L)); + SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L)); + SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L)); + + SearchResponse result = call(SearchRequest.builder() + .setProject(project.key()) + .setTo(formatDateTime(2_000_000_000L)) + .build()); + + assertThat(result.getAnalysesList()) + .extracting(Analysis::getKey) + .containsOnly(a1.getUuid(), a2.getUuid()) + .doesNotContain(a3.getUuid(), a4.getUuid()); + } + + @Test + public void filter_by_dates_using_datetime_format() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.addProjectPermission(UserRole.USER, project); + SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L)); + SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L)); + SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L)); + SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L)); + + SearchResponse result = call(SearchRequest.builder() + .setProject(project.key()) + .setFrom(formatDateTime(2_000_000_000L)) + .setTo(formatDateTime(3_000_000_000L)) + .build()); + + assertThat(result.getAnalysesList()) + .extracting(Analysis::getKey) + .containsOnly(a2.getUuid(), a3.getUuid()) + .doesNotContain(a1.getUuid(), a4.getUuid()); + } + + @Test + public void filter_by_dates_using_date_format() { + ComponentDto project = db.components().insertPrivateProject(); + userSession.addProjectPermission(UserRole.USER, project); + SnapshotDto a1 = db.components().insertSnapshot(newAnalysis(project).setUuid("a1").setCreatedAt(1_000_000_000L)); + SnapshotDto a2 = db.components().insertSnapshot(newAnalysis(project).setUuid("a2").setCreatedAt(2_000_000_000L)); + SnapshotDto a3 = db.components().insertSnapshot(newAnalysis(project).setUuid("a3").setCreatedAt(3_000_000_000L)); + SnapshotDto a4 = db.components().insertSnapshot(newAnalysis(project).setUuid("a4").setCreatedAt(4_000_000_000L)); + + SearchResponse result = call(SearchRequest.builder() + .setProject(project.key()) + .setFrom(formatDate(new Date(2_000_000_000L))) + .setTo(formatDate(new Date(3_000_000_000L))) + .build()); + + assertThat(result.getAnalysesList()) + .extracting(Analysis::getKey) + .containsOnly(a2.getUuid(), a3.getUuid()) + .doesNotContain(a1.getUuid(), a4.getUuid()); + } + @Test public void definition() { WebService.Action definition = ws.getDef(); @@ -225,8 +312,14 @@ public class SearchActionTest { assertThat(definition.key()).isEqualTo("search"); assertThat(definition.since()).isEqualTo("6.3"); assertThat(definition.responseExampleAsString()).isNotEmpty(); - assertThat(definition.param(PARAM_PROJECT).isRequired()).isTrue(); - assertThat(definition.param(PARAM_CATEGORY)).isNotNull(); + assertThat(definition.param("project").isRequired()).isTrue(); + assertThat(definition.param("category")).isNotNull(); + + Param from = definition.param("from"); + assertThat(from.since()).isEqualTo("6.5"); + + Param to = definition.param("to"); + assertThat(to.since()).isEqualTo("6.5"); } @Test @@ -263,6 +356,8 @@ public class SearchActionTest { setNullable(wsRequest.getCategory(), category -> request.setParam(PARAM_CATEGORY, category.name())); setNullable(wsRequest.getPage(), page -> request.setParam(Param.PAGE, String.valueOf(page))); setNullable(wsRequest.getPageSize(), pageSize -> request.setParam(Param.PAGE_SIZE, String.valueOf(pageSize))); + setNullable(wsRequest.getFrom(), from -> request.setParam(PARAM_FROM, from)); + setNullable(wsRequest.getTo(), to -> request.setParam(PARAM_TO, to)); return request.executeProtobuf(SearchResponse.class); } -- cgit v1.2.3