diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2ESummaryTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2ESummaryTest.java
new file mode 100644
index 000000000..ba22ca305
--- /dev/null
+++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2ESummaryTest.java
@@ -0,0 +1,102 @@
+/*
+ * #%L
+ * Alfresco Search Services E2E Test
+ * %%
+ * Copyright (C) 2005 - 2020 Alfresco Software Limited
+ * %%
+ * This file is part of the Alfresco software.
+ * If the software was purchased under a paid Alfresco license, the terms of
+ * the paid license agreement will prevail. Otherwise, the software is
+ * provided under the following open source license terms:
+ *
+ * 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 .
+ * #L%
+ */
+package org.alfresco.test.search.functional.searchServices.solr.admin;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Random;
+import java.util.UUID;
+import java.util.stream.IntStream;
+
+import org.alfresco.rest.core.RestResponse;
+import org.alfresco.test.search.functional.AbstractE2EFunctionalTest;
+import org.alfresco.utility.Utility;
+import org.alfresco.utility.model.FileModel;
+import org.alfresco.utility.model.FileType;
+import org.testng.annotations.Test;
+
+/** E2E tests for the SUMMARY admin report. */
+public class SolrE2ESummaryTest extends AbstractE2EFunctionalTest
+{
+ /** The maximum time to wait for a report to update (in ms). */
+ private static final int MAX_TIME = 60 * 1000;
+ /** The frequency to check the report (in ms). */
+ private static final int RETRY_INTERVAL = 100;
+
+ /** Check the FTS section of the admin summary contains the expected fields. */
+ @Test
+ public void testFTSReport() throws Exception
+ {
+ RestResponse response = restClient.withParams("core=alfresco").withSolrAdminAPI().getAction("SUMMARY");
+
+ int toUpdate = response.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content needs to be updated'");
+ assertTrue(toUpdate >= 0, "Expecting non-negative pieces of content to need updating.");
+
+ int inSync = response.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content is in sync'");
+ assertTrue(inSync >= 0, "Expecting non-negative pieces of content to need updating.");
+ }
+
+ /** Check that we can spot a document updating by using the SUMMARY report. */
+ @Test
+ public void testFTSReport_contentUpdate() throws Exception
+ {
+ RestResponse response2 = restClient.withParams("core=alfresco").withSolrAdminAPI().getAction("SUMMARY");
+ int previousInSync = response2.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content is in sync'");
+
+ FileModel file = new FileModel("file.txt", "file.txt", "", FileType.TEXT_PLAIN, "file.txt");
+ FileModel content = dataContent.usingUser(adminUserModel).usingSite(testSite).createContent(file);
+
+ // Wait for the number of "in-sync" documents to increase (i.e. when the document is indexed).
+ Utility.sleep(RETRY_INTERVAL, MAX_TIME, () -> {
+ RestResponse response = restClient.withParams("core=alfresco").withSolrAdminAPI().getAction("SUMMARY");
+ int inSync = response.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content is in sync'");
+ assertTrue(inSync > previousInSync, "Expected a document to be indexed.");
+ });
+
+ // Wait for the number of outdated documents to become zero.
+ Utility.sleep(RETRY_INTERVAL, MAX_TIME, () ->
+ {
+ RestResponse response = restClient.withParams("core=alfresco").withSolrAdminAPI().getAction("SUMMARY");
+ int toUpdate = response.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content needs to be updated'");
+ assertEquals(toUpdate, 0, "Expected number of outdated documents to drop to zero.");
+ });
+
+ // Update the document's content with a large amount of text.
+ StringBuilder largeText = new StringBuilder("Big update");
+ IntStream.range(0, 100000).forEach((i) -> largeText.append(" ").append(UUID.randomUUID().toString()));
+ dataContent.usingUser(adminUserModel).usingResource(content).updateContent(largeText.toString());
+
+ // Expect to spot the number of outdated documents increase beyond zero.
+ Utility.sleep(RETRY_INTERVAL, MAX_TIME, () ->
+ {
+ RestResponse response = restClient.withParams("core=alfresco").withSolrAdminAPI().getAction("SUMMARY");
+ int toUpdate = response.getResponse().body().jsonPath().get("Summary.alfresco.FTS.'Node count whose content needs to be updated'");
+ assertNotEquals(toUpdate, 0, "Expected number of outdated documents to be greater than zero.");
+ });
+ }
+}
diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/SolrInformationServer.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/SolrInformationServer.java
index c77048a63..87aeba0c8 100644
--- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/SolrInformationServer.java
+++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/SolrInformationServer.java
@@ -373,11 +373,11 @@ public class SolrInformationServer implements InformationServer
public static final String AND = " AND ";
public static final String OR = " OR ";
- private static final String REQUEST_HANDLER_NATIVE = "/native";
+ static final String REQUEST_HANDLER_NATIVE = "/native";
static final String REQUEST_HANDLER_GET = "/get";
static final String RESPONSE_DEFAULT_ID = "doc";
- private static final String RESPONSE_DEFAULT_IDS = "response";
+ static final String RESPONSE_DEFAULT_IDS = "response";
static final String PREFIX_ERROR = "ERROR-";
@@ -712,11 +712,10 @@ public class SolrInformationServer implements InformationServer
{
ModifiableSolrParams params =
new ModifiableSolrParams(request.getParams())
- .set(CommonParams.Q, "*:*")
- .set(CommonParams.FQ, FIELD_DOC_TYPE + ":" + DOC_TYPE_NODE)
+ .set(CommonParams.Q, FIELD_DOC_TYPE + ":" + DOC_TYPE_NODE + " AND " + FIELD_TYPE + ":\"{http://www.alfresco.org/model/content/1.0}content\"")
.set(CommonParams.ROWS, 0)
- .set(FacetParams.FACET, true)
- .add(FacetParams.FACET_QUERY, "{!key='OUTDATED'}LATEST_APPLIED_CONTENT_VERSION_ID:{-10 TO -10}");
+ .set(FacetParams.FACET, "on")
+ .add(FacetParams.FACET_QUERY, "{!key='OUTDATED'}" + LAST_INCOMING_CONTENT_VERSION_ID + ":\"" + CONTENT_OUTDATED_MARKER + "\"");
SolrQueryResponse response = cloud.getResponse(nativeRequestHandler, request, params);
@@ -2625,7 +2624,7 @@ public class SolrInformationServer implements InformationServer
* - Do we have an entry in the local content store for the document X?
* - If we didn't have that entry then FTSSTATUS was set to New
*
- * FTSSTatus = DIRTY
+ * FTSSTATUS = DIRTY
*
* When a node, which requires content, arrived here for being indexed, the "Dirty" status was set if
*
@@ -2637,7 +2636,7 @@ public class SolrInformationServer implements InformationServer
* something is different between the local document and the document which is in Solr".
*
* The content store allowed to workaround the problem: the code was deserializing the entry corresponding to the
- * incoming node (which teoretically corresponded to the document indexed in Solr) so both versions were available
+ * incoming node (which theoretically corresponded to the document indexed in Solr) so both versions were available
* for making decisions
*
* ------------------
@@ -2646,7 +2645,7 @@ public class SolrInformationServer implements InformationServer
* about
*
* - the "INSERT" or "UPDATE" nature of the indexing operation that is going to be executed
- * - the values of fields of a given document indeded in Solr
+ * - the values of fields of a given document indexed in Solr
*
* In order to indicate to the ContentTracker which documents will require the content update, we added two
* additional fields in the schema:
@@ -2656,8 +2655,8 @@ public class SolrInformationServer implements InformationServer
* LATEST_APPLIED_CONTENT_VERSION_ID: as the name suggests, this is the latest DOCID applied to this document (again, not the lucene docid)
*
*
- * LAST_INCOMING_CONTENT_VERSION_ID: a field that will contains "-10" if the content is outdated, otherwise it will have the same value
- * of LATEST_APPLIED_CONTENT_VERSION_ID.
+ * LAST_INCOMING_CONTENT_VERSION_ID: this call will set the field to "-10" as the content is outdated. The content tracker will then set it
+ * to have same value as LATEST_APPLIED_CONTENT_VERSION_ID.
*