diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2017-07-03 18:03:09 +0200 |
---|---|---|
committer | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2017-07-13 14:34:17 +0200 |
commit | 6d24aaa1516a0a1b5d92eceb2495b92ccbc7182c (patch) | |
tree | bc7a956f8105dc51af9605c55838d6a29c7ba9a3 /server | |
parent | ba96a0fbd5d10c0923be4760cf8aae251f43bb7c (diff) | |
download | sonarqube-6d24aaa1516a0a1b5d92eceb2495b92ccbc7182c.tar.gz sonarqube-6d24aaa1516a0a1b5d92eceb2495b92ccbc7182c.zip |
SONAR-9476 Add from and to params in api/project_analyses/search
Diffstat (limited to 'server')
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/measure/ws/SearchHistoryAction.java | 6 | ||||
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchAction.java | 99 | ||||
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java (renamed from server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResults.java) | 8 | ||||
-rw-r--r-- | server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchResponseBuilder.java | 78 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/projectanalysis/ws/SearchActionTest.java | 99 |
5 files changed, 193 insertions, 97 deletions
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<Request, SearchRequest> 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<SearchResults.Builder> 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<SearchResults.Builder> addEvents() { - return data -> { - List<String> 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<String> analyses = data.getAnalyses().stream().map(SnapshotDto::getUuid).collect(MoreCollectors.toList()); + data.setEvents(dbClient.eventDao().selectByAnalysisUuids(data.getDbSession(), analyses)); } - private Consumer<SearchResults.Builder> checkPermission() { - return data -> userSession.checkComponentPermission(UserRole.USER, data.getProject()); + private void checkPermission(ComponentDto project) { + userSession.checkComponentPermission(UserRole.USER, project); } - private Consumer<SearchResults.Builder> 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/SearchResults.java b/server/sonar-server/src/main/java/org/sonar/server/projectanalysis/ws/SearchData.java index 8e725ccc6ae..56ad72053a7 100644 --- 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/SearchData.java @@ -33,12 +33,12 @@ import org.sonarqube.ws.client.projectanalysis.SearchRequest; import static java.util.Objects.requireNonNull; -class SearchResults { +class SearchData { final List<SnapshotDto> analyses; final ListMultimap<String, EventDto> eventsByAnalysis; final Paging paging; - private SearchResults(Builder builder) { + private SearchData(Builder builder) { this.analyses = builder.analyses; this.eventsByAnalysis = buildEvents(builder.events); this.paging = Paging @@ -120,13 +120,13 @@ class SearchResults { .collect(MoreCollectors.toList()); } - SearchResults build() { + SearchData build() { requireNonNull(analyses); requireNonNull(events); if (request.getCategory() != null) { filterByCategory(); } - return new SearchResults(this); + 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<SearchResults, SearchResponse> 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<SearchResponse.Builder> 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<SnapshotDto, Analysis.Builder> dbToWsAnalysis() { - return dbAnalysis -> analysisBuilder.clear() + private Analysis.Builder dbToWsAnalysis(SnapshotDto dbAnalysis) { + return wsAnalysis.clear() .setKey(dbAnalysis.getUuid()) .setDate(formatDateTime(dbAnalysis.getCreatedAt())); } - private Consumer<Analysis.Builder> 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<EventDto, Event.Builder> 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<SearchResponse.Builder> 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/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 { @@ -219,14 +224,102 @@ public class SearchActionTest { } @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(); 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); } |