diff --git a/e2e-test/java/org/alfresco/rest/search/StatsSearchTest.java b/e2e-test/java/org/alfresco/rest/search/StatsSearchTest.java
new file mode 100644
index 000000000..ac5932750
--- /dev/null
+++ b/e2e-test/java/org/alfresco/rest/search/StatsSearchTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2017 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco 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.
+ *
+ * Alfresco 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 Alfresco. If not, see .
+ */
+package org.alfresco.rest.search;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import org.alfresco.rest.model.RestErrorModel;
+import org.alfresco.utility.model.TestGroup;
+import org.alfresco.utility.testrail.ExecutionType;
+import org.alfresco.utility.testrail.annotation.TestRail;
+import org.springframework.http.HttpStatus;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Stats search test.
+ * @author Gethin James
+ *
+ */
+public class StatsSearchTest extends AbstractSearchTest
+{
+
+ @Test(groups = { TestGroup.REST_API, TestGroup.SEARCH })
+ @TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH }, executionType = ExecutionType.REGRESSION,
+ description = "Checks errors with stats using Search api")
+ public void searchWithBasicStats() throws Exception
+ {
+ SearchRequest query = carsQuery();
+ Pagination pagination = new Pagination();
+ pagination.setMaxItems(2);
+ List statsModels = new ArrayList<>();
+ RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
+ statsModels.add(statsModel1);
+ query.setStats(statsModels);
+ query.setPaging(pagination);
+
+ SearchResponse response = query(query);
+ restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
+ .containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "stats field"));
+
+ statsModel1.setField("DBID");
+ response = query(query);
+ //8 metrics by default for a numeric field
+ Set metricTypes = assertStatsFacetedResponse(response, "DBID", 8);
+ assertTrue(metricTypes.containsAll(Arrays.asList("missing", "count", "sum","min","max", "sumOfSquares", "mean", "stddev")));
+
+ statsModel1.setField("creator");
+ response = query(query);
+ //4 metrics by default for a string field
+ metricTypes = assertStatsFacetedResponse(response, "creator", 4);
+ assertTrue(metricTypes.containsAll(Arrays.asList("missing", "count", "min","max")));
+
+ statsModel1.setField("modified");
+ response = query(query);
+ //8 metrics by default for a date field
+ metricTypes = assertStatsFacetedResponse(response, "modified", 8);
+ assertTrue(metricTypes.containsAll(Arrays.asList("missing", "count", "sum","min","max", "sumOfSquares", "mean", "stddev")));
+
+ statsModel1.setField("modifier");
+ statsModel1.setMin(false);
+ statsModel1.setMax(false);
+ statsModel1.setMissing(false);
+ response = query(query);
+ metricTypes = assertStatsFacetedResponse(response, "modifier", 1);
+ assertFalse(metricTypes.containsAll(Arrays.asList("missing", "min","max")));
+
+ statsModel1.setField("DBID");
+ statsModel1.setMin(true);
+ statsModel1.setMax(true);
+ statsModel1.setCount(false);
+ statsModel1.setMissing(false);
+ statsModel1.setSum(false);
+ statsModel1.setSumOfSquares(false);
+ statsModel1.setMean(false);
+ statsModel1.setStddev(false);
+ response = query(query);
+ metricTypes = assertStatsFacetedResponse(response, "DBID", 2);
+ assertTrue(metricTypes.containsAll(Arrays.asList("min","max")));
+ assertFalse(metricTypes.containsAll(Arrays.asList("missing", "count", "sum","sumOfSquares", "mean", "stddev")));
+
+ statsModel1.setField("modifier");
+ statsModel1.setMin(false);
+ statsModel1.setMax(false);
+ statsModel1.setCountDistinct(true);
+ statsModel1.setDistinctValues(true);
+ statsModel1.setCardinality(true);
+ response = query(query);
+ metricTypes = assertStatsFacetedResponse(response, "modifier", 3);
+ assertTrue(metricTypes.containsAll(Arrays.asList("countDistinct", "distinctValues", "cardinality")));
+
+ statsModel1.setField("DBID");
+ statsModel1.setPercentiles(Arrays.asList(1,75,99,99.9));
+ statsModel1.setCountDistinct(false);
+ statsModel1.setDistinctValues(false);
+ statsModel1.setCardinality(false);
+ response = query(query);
+ assertStatsFacetedResponse(response, "DBID", 1);
+ RestGenericMetricModel percMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
+ assertEquals(percMetric.getType(),"percentiles");
+ Map percVal = (Map) percMetric.getValue();
+ Map percentiles = (Map) percVal.get("percentiles");
+ assertEquals(percentiles.size(),4);
+ assertTrue(percentiles.keySet().containsAll(Arrays.asList("1.0","75.0","99.0","99.9")));
+ }
+
+ @Test(groups = { TestGroup.REST_API, TestGroup.SEARCH })
+ @TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH }, executionType = ExecutionType.REGRESSION,
+ description = "Checks errors with stats labels using Search api")
+ public void searchWithStatsLabel() throws Exception
+ {
+ SearchRequest query = carsQuery();
+ Pagination pagination = new Pagination();
+ pagination.setMaxItems(2);
+ List statsModels = new ArrayList<>();
+ RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
+ statsModel1.setField("modified");
+ statsModel1.setLabel("DateChanged");
+ statsModels.add(statsModel1);
+ query.setStats(statsModels);
+ query.setPaging(pagination);
+ SearchResponse response = query(query);
+ assertStatsFacetedResponse(response, "DateChanged", 8);
+ }
+
+ @Test(groups = { TestGroup.REST_API, TestGroup.SEARCH })
+ @TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH }, executionType = ExecutionType.REGRESSION,
+ description = "Checks errors with stats fitlers using Search api")
+ public void searchWithStatsFilters() throws Exception
+ {
+ SearchRequest query = new SearchRequest();
+ RestRequestQueryModel queryReq = new RestRequestQueryModel();
+ queryReq.setQuery("content.mimetype:text/plain");
+ query.setQuery(queryReq);
+ List statsModels = new ArrayList<>();
+ RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
+ statsModel1.setField("creator");
+ statsModel1.setMin(false);
+ statsModel1.setMax(false);
+ statsModel1.setMissing(false);
+ statsModels.add(statsModel1);
+ query.setFilterQueries(new RestRequestFilterQueryModel("cars", Arrays.asList("justCars")));
+ query.setStats(statsModels);
+ SearchResponse response = query(query);
+ assertStatsFacetedResponse(response, "creator", 1);
+ RestGenericMetricModel countMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
+ Integer count = response.getEntries().size();
+ Map metricCount = (Map) countMetric.getValue();
+ assertEquals(count, metricCount.get("count"));
+
+ statsModel1.setExcludeFilters(Arrays.asList("justCars"));
+ response = query(query);
+ assertStatsFacetedResponse(response, "creator", 1);
+ countMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
+ count = response.getEntries().size();
+ metricCount = (Map) countMetric.getValue();
+ assertTrue((Integer)metricCount.get("count") > count, "With the exclude filter there will be more documents than returned");
+ }
+
+ @Test(groups = { TestGroup.REST_API, TestGroup.SEARCH })
+ @TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH }, executionType = ExecutionType.REGRESSION,
+ description = "Checks errors with stats with Pivot using Search api")
+ public void searchWithStatsAndMutlilevelPivot() throws Exception
+ {
+ SearchRequest query = carsQuery();
+
+ Pagination pagination = new Pagination();
+ pagination.setMaxItems(1);
+ query.setPaging(pagination);
+ RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
+ List list = new ArrayList<>();
+ RestRequestFacetFieldModel b0 = new RestRequestFacetFieldModel("SITE");
+ b0.setLabel("b0");
+ list.add(b0);
+ list.add(new RestRequestFacetFieldModel("created"));
+ RestRequestFacetFieldModel b2 = new RestRequestFacetFieldModel("modifier");
+ b2.setLabel("b2");
+ list.add(b2);
+ facetFields.setFacets(list);
+ query.setFacetFields(facetFields);
+ query.setIncludeRequest(false);
+
+
+ List pivotModelList = new ArrayList<>();
+ RestRequestPivotModel pivots = new RestRequestPivotModel();
+ pivots.setKey("b0");
+ RestRequestPivotModel pivotn = new RestRequestPivotModel();
+ pivotn.setKey("created");
+ RestRequestPivotModel pivot2 = new RestRequestPivotModel();
+ pivot2.setKey("aNumber");
+ pivotModelList.add(pivots);
+ pivotModelList.add(pivotn);
+ pivotModelList.add(pivot2);
+ query.setPivots(pivotModelList);
+
+ List statsModels = new ArrayList<>();
+ RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
+ statsModels.add(statsModel1);
+ query.setStats(statsModels);
+ statsModel1.setField("DBID");
+ statsModel1.setLabel("aNumber");
+
+ SearchResponse response = query(query);
+ response.getContext().assertThat().field("facetsFields").isNotNull();
+ response.getContext().assertThat().field("facets").isNotEmpty();
+ assertEquals(response.getContext().getFacetsFields().size(), 1, "There should be 1 facet field for modifier");
+ assertEquals(response.getContext().getFacets().size(), 2, "There should be 1 pivot facet with stats on the end and a high level stats facet");
+
+ RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
+ facetResponseModel.assertThat().field("type").is("pivot");
+ facetResponseModel.assertThat().field("label").is("b0");
+ assertEquals(facetResponseModel.getBuckets().get(0).getMetrics().size(), 8, "Metrics on the pivot bucket");
+
+ //Another nested stats
+ assertEquals(facetResponseModel.getBuckets().get(0).getFacets().get(0).getBuckets().get(0).getMetrics().size(), 8, "Metrics are on the end of a pivot bucket");
+
+ RestGenericFacetResponseModel statsFacet = response.getContext().getFacets().get(1);
+ statsFacet.assertThat().field("type").is("stats");
+ statsFacet.assertThat().field("label").is("aNumber");
+
+ }
+
+
+ @Test(groups = { TestGroup.REST_API, TestGroup.SEARCH })
+ @TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH }, executionType = ExecutionType.REGRESSION,
+ description = "Checks errors with stats with Pivot using Search api")
+ public void searchWithStatsAndPivot() throws Exception
+ {
+ SearchRequest query = carsQuery();
+
+ Pagination pagination = new Pagination();
+ pagination.setMaxItems(2);
+ query.setPaging(pagination);
+ RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
+ List list = new ArrayList<>();
+ list.add(new RestRequestFacetFieldModel("creator"));
+ facetFields.setFacets(list);
+ query.setFacetFields(facetFields);
+ query.setIncludeRequest(false);
+
+ SearchResponse response = query(query);
+ response.getContext().assertThat().field("facetsFields").isNotNull();
+
+ List pivotModelList = new ArrayList<>();
+ RestRequestPivotModel pivots = new RestRequestPivotModel();
+ pivots.setKey("creator");
+ RestRequestPivotModel pivotn = new RestRequestPivotModel();
+ pivotn.setKey("numericId");
+ pivotModelList.add(pivots);
+ pivotModelList.add(pivotn);
+ query.setPivots(pivotModelList);
+
+ List statsModels = new ArrayList<>();
+ RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
+ statsModels.add(statsModel1);
+ query.setStats(statsModels);
+ statsModel1.setField("DBID");
+ statsModel1.setLabel("numericId");
+
+ response = query(query);
+
+ response.getContext().assertThat().field("facets").isNotEmpty();
+ assertEquals(response.getContext().getFacets().size(), 2, "There should be 1 pivot facet with stats on the end and a high level stats facet");
+ RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
+ facetResponseModel.assertThat().field("type").is("pivot");
+ facetResponseModel.assertThat().field("label").is("creator");
+ assertEquals(facetResponseModel.getBuckets().get(0).getMetrics().size(), 8, "Metrics are on the end of a pivot bucket");
+ RestGenericFacetResponseModel statsFacet = response.getContext().getFacets().get(1);
+ statsFacet.assertThat().field("type").is("stats");
+ statsFacet.assertThat().field("label").is("numericId");
+
+ }
+
+ private Set assertStatsFacetedResponse(SearchResponse response, String label, int metricsCount) throws Exception
+ {
+ response.getContext().assertThat().field("facets").isNotEmpty();
+ RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
+ facetResponseModel.assertThat().field("type").is("stats");
+ facetResponseModel.assertThat().field("label").is(label);
+ RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
+ List metrics = bucket.getMetrics();
+ assertEquals(metrics.size(),metricsCount);
+ return metrics.stream().map(m -> m.getType()).collect(Collectors.toSet());
+ }
+
+}