From 20182ceb5a7b6441f975f4bd089bd3bd54feca64 Mon Sep 17 00:00:00 2001 From: sridharvellingiri Date: Mon, 27 Jan 2020 14:50:14 +0000 Subject: [PATCH 01/94] SEARCH-2072 Updating Slave context end point --- search-services/packaging/src/docker/search_config_setup.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/search-services/packaging/src/docker/search_config_setup.sh b/search-services/packaging/src/docker/search_config_setup.sh index 12fc0bf36..0d2ef18a1 100644 --- a/search-services/packaging/src/docker/search_config_setup.sh +++ b/search-services/packaging/src/docker/search_config_setup.sh @@ -9,6 +9,7 @@ SOLR_RERANK_CONFIG_FILE=$RERANK_TEMPLATE_PATH/solrconfig.xml SOLR_NORERANK_CONFIG_FILE=$NORERANK_TEMPLATE_PATH/solrconfig.xml SOLR_RERANK_CORE_FILE=$RERANK_TEMPLATE_PATH/solrcore.properties SOLR_NORERANK_CORE_FILE=$NORERANK_TEMPLATE_PATH/solrcore.properties +SOLR_CONTEXT_FILE=$PWD/solr/server/contexts/solr-jetty-context.xml if [[ $REPLICATION_TYPE == "master" ]]; then @@ -63,6 +64,7 @@ if [[ $REPLICATION_TYPE == "slave" ]]; then '$REPLICATION_POLL_INTERVAL'<\/str>\ <\/lst>/g' $SOLR_RERANK_CONFIG_FILE $SOLR_NORERANK_CONFIG_FILE sed -i "s/enable.alfresco.tracking=true/enable.alfresco.tracking=false\nenable.master=false\nenable.slave=true/g" $SOLR_RERANK_CORE_FILE $SOLR_NORERANK_CORE_FILE + sed -i 's/default="\/solr"/default="\/solr-slave"/g' $SOLR_CONTEXT_FILE fi SOLR_IN_FILE=$PWD/solr.in.sh From 82d425a23d1e01b50ef099b9b3c4a9b7eb0d4830 Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 3 Feb 2020 10:38:01 +0000 Subject: [PATCH 02/94] SEARCH-1681 A test for EXPLICIT_ID sharding --- .../functional/AbstractE2EFunctionalTest.java | 1 + .../searchServices/search/ShardInfoTest.java | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java index 7470000ab..0f22c4acb 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java @@ -102,6 +102,7 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont deployCustomModel("model/music-model.xml"); deployCustomModel("model/finance-model.xml"); + deployCustomModel("model/sharding-content-model.xml"); } @BeforeClass(alwaysRun = true) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 74fbcf971..1e1f430b6 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -126,4 +126,42 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest restClient.authenticateUser(dataUser.createRandomTestUser()).withShardInfoAPI().getInfo(); restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR); } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithExplicitID() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "EXPLICIT_ID"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } } From 713866b448b4754c97c26647cedcc7a9de359831 Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 3 Feb 2020 12:52:46 +0000 Subject: [PATCH 03/94] SEARCH-1681 Removing testgroup from the explicit sharding test --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 1e1f430b6..aac3a485d 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -127,7 +127,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR); } - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + @Test(groups = { TestGroup.ACS_60n }) public void getShardInfoWithExplicitID() throws JsonProcessingException { RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() From 4cb1403add3622246b107460225fc34fc8e8cc5e Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 3 Feb 2020 14:37:07 +0000 Subject: [PATCH 04/94] Add a way to install custom addons. --- e2e-test/generator-alfresco-docker-compose/README.md | 6 ++++++ .../generators/app/index.js | 10 ++++++++++ .../generators/app/templates/empty/empty | 0 .../app/templates/images/alfresco/Dockerfile | 7 +++++++ .../generators/app/templates/images/share/Dockerfile | 7 +++++++ 5 files changed, 30 insertions(+) create mode 100644 e2e-test/generator-alfresco-docker-compose/generators/app/templates/empty/empty diff --git a/e2e-test/generator-alfresco-docker-compose/README.md b/e2e-test/generator-alfresco-docker-compose/README.md index 0caf4d33d..00a45e386 100644 --- a/e2e-test/generator-alfresco-docker-compose/README.md +++ b/e2e-test/generator-alfresco-docker-compose/README.md @@ -17,6 +17,8 @@ $ tree generators/app/templates/ │   ├── .env │   ├── docker-compose-ce.yml │   └── docker-compose-ee.yml +├── empty +│   └── empty ├── images │   ├── alfresco │   │   ├── Dockerfile @@ -181,6 +183,10 @@ Sample configuration is available in [images/share/model/sharding-share-config-c If *Sharding* is selected, a default `share-config-custom-dev.xml` file with required forms configuration for Sharding custom model will be available in deployment folder. Add your configuration to this file. +## Installing custom addons + +The generator will create `amps` and `jars` directories within `alfresco/modules` and `share/modules`. Any amps or jars placed in these directories will be installed in the corresponding container. + ## Passing parameters from command line Default values for options can be specified in the command line, using a `--name=value` pattern. When an options is specified in the command line, the question is not prompted to the user, so you can generate a Docker Compose template with no user interaction. diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/index.js b/e2e-test/generator-alfresco-docker-compose/generators/app/index.js index 03905232a..e75f7a62d 100644 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/index.js +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/index.js @@ -267,6 +267,16 @@ module.exports = class extends Generator { ) } + // Empty addons directories. + ['alfresco', 'share'].forEach(container => { + ['jars', 'modules'].forEach(addonType => { + this.fs.copy( + this.templatePath('empty/empty'), + this.destinationPath(container + '/modules/' + addonType + '/empty') + ); + }); + }); + // Copy Docker Image for Search applying configuration this.fs.copyTpl( this.templatePath(imagesDirectory + '/search'), diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/empty/empty b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/empty/empty new file mode 100644 index 000000000..e69de29bb diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/alfresco/Dockerfile b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/alfresco/Dockerfile index 87091db7a..9478df4ff 100755 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/alfresco/Dockerfile +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/alfresco/Dockerfile @@ -25,6 +25,13 @@ VOLUME ["${ALF_DATA_DIR}/keystore"] USER root +# Install modules and addons +RUN mkdir -p $TOMCAT_DIR/amps +COPY modules/amps/* $TOMCAT_DIR/amps/ +COPY modules/jars/* $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib/ +RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \ + $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force; + # Default value in "repository.properties" is "dir.keystore=classpath:alfresco/keystore" RUN if [ "$SOLR_COMMS" == "https" ] ; then \ echo -e "\n\ diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/share/Dockerfile b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/share/Dockerfile index 1f76a0ce9..d9516e412 100644 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/share/Dockerfile +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/images/share/Dockerfile @@ -8,5 +8,12 @@ RUN sed -i '/Connector port="8080"/a scheme="https" secure="true"' /usr/local/to sed -i '/Connector port="8080"/a proxyName="localhost" proxyPort="<%=port%>"' /usr/local/tomcat/conf/server.xml <% } %> +# Install modules +RUN mkdir -p $TOMCAT_DIR/amps +COPY modules/amps/* $TOMCAT_DIR/amps/ +COPY modules/jars/* $TOMCAT_DIR/webapps/share/WEB-INF/lib/ +RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \ + $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/share -directory -nobackup -force; + # Copy custom content forms to deployment folder COPY model/* $TOMCAT_DIR/shared/classes/alfresco/web-extension/ \ No newline at end of file From 37aea72fed560856c62b9088efed39215244b5b7 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 3 Feb 2020 15:48:32 +0000 Subject: [PATCH 05/94] Fix typo modules -> amps. --- .../generator-alfresco-docker-compose/generators/app/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/index.js b/e2e-test/generator-alfresco-docker-compose/generators/app/index.js index e75f7a62d..2058411fc 100644 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/index.js +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/index.js @@ -269,7 +269,7 @@ module.exports = class extends Generator { // Empty addons directories. ['alfresco', 'share'].forEach(container => { - ['jars', 'modules'].forEach(addonType => { + ['jars', 'amps'].forEach(addonType => { this.fs.copy( this.templatePath('empty/empty'), this.destinationPath(container + '/modules/' + addonType + '/empty') From 514e05df183ed0c96e711ac320a4853bcb93ccc3 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Tue, 4 Feb 2020 12:58:22 +0000 Subject: [PATCH 06/94] SEARCH-1950 Don't index path information if cascade tracking is disabled. --- .../alfresco/solr/SolrInformationServer.java | 166 ++---------------- 1 file changed, 13 insertions(+), 153 deletions(-) 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 e88a75d31..bd63476bb 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 @@ -2071,10 +2071,13 @@ public class SolrInformationServer implements InformationServer doc.addField(FIELD_TENANT, AlfrescoSolrDataModel.getTenantId(nodeMetaData.getTenantDomain())); - updatePathRelatedFields(nodeMetaData, doc); - updateNamePathRelatedFields(nodeMetaData, doc); - updateAncestorRelatedFields(nodeMetaData, doc); - doc.addField(FIELD_PARENT_ASSOC_CRC, nodeMetaData.getParentAssocsCrc()); + if (cascadeTrackingEnabled()) + { + updatePathRelatedFields(nodeMetaData, doc); + updateNamePathRelatedFields(nodeMetaData, doc); + updateAncestorRelatedFields(nodeMetaData, doc); + doc.addField(FIELD_PARENT_ASSOC_CRC, nodeMetaData.getParentAssocsCrc()); + } if (nodeMetaData.getOwner() != null) { @@ -3423,9 +3426,12 @@ public class SolrInformationServer implements InformationServer if (cachedDoc != null) { - updatePathRelatedFields(nodeMetaData, cachedDoc); - updateNamePathRelatedFields(nodeMetaData, cachedDoc); - updateAncestorRelatedFields(nodeMetaData, cachedDoc); + if (cascadeTrackingEnabled()) + { + updatePathRelatedFields(nodeMetaData, cachedDoc); + updateNamePathRelatedFields(nodeMetaData, cachedDoc); + updateAncestorRelatedFields(nodeMetaData, cachedDoc); + } AddUpdateCommand addDocCmd = new AddUpdateCommand(request); addDocCmd.overwrite = overwrite; @@ -3448,152 +3454,6 @@ public class SolrInformationServer implements InformationServer } } - private void updateDescendantDocs(NodeMetaData parentNodeMetaData, boolean overwrite, - SolrQueryRequest request, UpdateRequestProcessor processor, LinkedHashSet stack) - throws AuthenticationException, IOException, JSONException - { - if (stack.contains(parentNodeMetaData.getId())) - { - LOGGER.warning("Found descendant data loop for node id {}", parentNodeMetaData.getId()); - LOGGER.warning("Stack to node = {} ", stack); - } - else - { - try - { - stack.add(parentNodeMetaData.getId()); - doUpdateDescendantDocs(parentNodeMetaData, overwrite, request, processor, stack); - } - finally - { - stack.remove(parentNodeMetaData.getId()); - } - } - } - - private boolean shouldBeIgnoredByAnyAspect(Set aspects) - { - if (null == aspects) - { - return false; - } - - for (QName aspectForSkipping : aspectsForSkippingDescendantDocs) - { - if (aspects.contains(aspectForSkipping)) - { - return true; - } - } - return false; - } - - private void doUpdateDescendantDocs(NodeMetaData parentNodeMetaData, boolean overwrite, - SolrQueryRequest request, UpdateRequestProcessor processor, LinkedHashSet stack) - throws AuthenticationException, IOException, JSONException - { - - // skipDescendantDocsForSpecificAspects is initialised on a synchronised method, so access must be also synchronised - synchronized (this) - { - if ((skipDescendantDocsForSpecificTypes && typesForSkippingDescendantDocs.contains(parentNodeMetaData.getType())) || - (skipDescendantDocsForSpecificAspects && shouldBeIgnoredByAnyAspect(parentNodeMetaData.getAspects()))) - { - return; - } - } - - Set childIds = new HashSet<>(); - - if (parentNodeMetaData.getChildIds() != null) - { - childIds.addAll(parentNodeMetaData.getChildIds()); - } - - String query = FIELD_PARENT + ":\"" + parentNodeMetaData.getNodeRef() + "\""; - ModifiableSolrParams params = - new ModifiableSolrParams(request.getParams()) - .set(CommonParams.Q, query) - .set(CommonParams.FL, FIELD_SOLR4_ID); - - if (skippingDocsQueryString != null && !skippingDocsQueryString.isEmpty()) - { - params.set(CommonParams.FQ, "NOT ( " + skippingDocsQueryString + " )"); - } - - SolrDocumentList docs = cloud.getSolrDocumentList(nativeRequestHandler, request, params); - for (SolrDocument doc : docs) - { - String id = getFieldValueString(doc, FIELD_SOLR4_ID); - TenantAclIdDbId ids = AlfrescoSolrDataModel.decodeNodeDocumentId(id); - childIds.add(ids.dbId); - } - - for (Long childId : childIds) - { - NodeMetaDataParameters nmdp = new NodeMetaDataParameters(); - nmdp.setFromNodeId(childId); - nmdp.setToNodeId(childId); - nmdp.setIncludeAclId(false); - nmdp.setIncludeAspects(false); - nmdp.setIncludeChildAssociations(false); - nmdp.setIncludeChildIds(true); - nmdp.setIncludeNodeRef(false); - nmdp.setIncludeOwner(false); - nmdp.setIncludeParentAssociations(false); - // We only care about the path and ancestors (which is included) for this case - nmdp.setIncludePaths(true); - nmdp.setIncludeProperties(false); - nmdp.setIncludeType(false); - nmdp.setIncludeTxnId(false); - // Gets only one - List nodeMetaDatas = repositoryClient.getNodesMetaData(nmdp, 1); - - if (!nodeMetaDatas.isEmpty()) - { - NodeMetaData nodeMetaData = nodeMetaDatas.get(0); - if (mayHaveChildren(nodeMetaData)) - { - updateDescendantDocs(nodeMetaData, overwrite, request, processor, stack); - } - - try - { - lock(childId); - - LOGGER.debug("Cascade update child doc {}", childId); - - // Gets the document that we have from the content store and updates it - String fixedTenantDomain = AlfrescoSolrDataModel.getTenantId(nodeMetaData.getTenantDomain()); - SolrInputDocument cachedDoc = solrContentStore.retrieveDocFromSolrContentStore(fixedTenantDomain, nodeMetaData.getId()); - - if (cachedDoc != null) - { - updatePathRelatedFields(nodeMetaData, cachedDoc); - updateNamePathRelatedFields(nodeMetaData, cachedDoc); - updateAncestorRelatedFields(nodeMetaData, cachedDoc); - - AddUpdateCommand addDocCmd = new AddUpdateCommand(request); - addDocCmd.overwrite = overwrite; - addDocCmd.solrDoc = cachedDoc; - - processor.processAdd(addDocCmd); - solrContentStore.storeDocOnSolrContentStore(fixedTenantDomain, nodeMetaData.getId(), cachedDoc); - } - else - { - LOGGER.debug("No child doc found to update {}", childId); - } - } - finally - { - unlock(childId); - } - } - } - } - - private long topNodeId(String sortDir) { try (SolrQueryRequest request = this.newSolrQueryRequest()) From e7beaa125a2b93bb8b38d9d2e6891fb0bc4d6022 Mon Sep 17 00:00:00 2001 From: sridharvellingiri Date: Wed, 5 Feb 2020 12:35:20 +0000 Subject: [PATCH 07/94] SEARCH-2072 Configure Master-Slave docker-compose --- search-services/README.md | 10 +++ search-services/packaging/src/docker/6.x/.env | 15 +++- .../src/docker/6.x/docker-compose.yml | 49 +++++------ .../6.x/master-slave/docker-compose.slave.yml | 87 +++++++++++++++++++ .../src/docker/6.x/master-slave/nginx.conf | 15 ++++ 5 files changed, 146 insertions(+), 30 deletions(-) create mode 100644 search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml create mode 100644 search-services/packaging/src/docker/6.x/master-slave/nginx.conf diff --git a/search-services/README.md b/search-services/README.md index 0c82e56d1..ec41b57c5 100644 --- a/search-services/README.md +++ b/search-services/README.md @@ -433,11 +433,21 @@ cd packaging/target/docker-resources/6.x docker-compose up ``` +##Docker Master-Slave setup +We have seperate docker compose file for slave. To setup Master slave setup + +`docker-compose -f docker-compose.yml -f ./master-slave/docker-compose.slave.yml up` + +The slave running behind the nginx load balancer under 8084, so we can spin up multiple slaves with the same port. To deploy multiple slaves + +`docker-compose -f docker-compose.yml -f ./master-slave/docker-compose.slave.yml up --scale search_slave=2` + This will start up Alfresco, Postgres, Share and SearchServices. You can access the applications using the following URLs: * Alfresco: http://localhost:8081/alfresco * Share: http://localhost:8082/share * Solr: http://localhost:8083/solr + * Solr-slave: http://localhost:8084/solr If you start version 5.x instead you can also access the API Explorer: diff --git a/search-services/packaging/src/docker/6.x/.env b/search-services/packaging/src/docker/6.x/.env index a90d8297d..45466603e 100644 --- a/search-services/packaging/src/docker/6.x/.env +++ b/search-services/packaging/src/docker/6.x/.env @@ -1,8 +1,15 @@ # In order to start the community edition set the value of ALFRESCO_IMAGE to alfresco/alfresco-content-repository-community ALFRESCO_IMAGE=quay.io/alfresco/alfresco-content-repository -ALFRESCO_TAG=6.1.0-EA3 +ALFRESCO_TAG=6.2.0 SHARE_IMAGE=quay.io/alfresco/alfresco-share -SHARE_TAG=6.0 +SHARE_TAG=6.2.0 POSTGRES_TAG=10.1 -SEARCH_TAG=latest -SEARCH_ENABLE_SPELLCHECK=false \ No newline at end of file +SEARCH_TAG=test +SEARCH_ENABLE_SPELLCHECK=false +TRANSFORM_ROUTER_TAG=1.1.0 +TRANSFORM_MISC_TAG=2.1.0 +IMAGE_MAGICK_TAG=2.1.0 +LIBREOFFICE_TAG=2.1.0 +TIKA_TAG=2.1.0 +PDF_RENDERER_TAG=2.1.0 +NGINX_TAG=1.15.5 \ No newline at end of file diff --git a/search-services/packaging/src/docker/6.x/docker-compose.yml b/search-services/packaging/src/docker/6.x/docker-compose.yml index ca4268e79..b875f4640 100644 --- a/search-services/packaging/src/docker/6.x/docker-compose.yml +++ b/search-services/packaging/src/docker/6.x/docker-compose.yml @@ -1,4 +1,5 @@ -version: '3' +version: '3.7' + services: alfresco: image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG} @@ -10,15 +11,31 @@ services: -Ddb.url=jdbc:postgresql://postgres:5432/alfresco -Dsolr.host=search -Dsolr.port=8983 + -Dalfresco.protocol=http -Dsolr.secureComms=none - -Dsolr.base.url=/solr + -Dalfresco.secureComms=none + -Dsolr.baseUrl=/solr -Dindex.subsystem.name=solr6 + -Dalfresco.restApi.basicAuthScheme=true + -Dcsrf.filter.enabled=false + -Dcors.enabled=false -Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\" + + -Dtransform.service.enabled=false + -Dtransform.service.url= + -Dsfs.url= + -Dlocal.transform.service.enabled=false + -DlocalTransform.libreoffice.url= + -DlocalTransform.tika.url= + -DlocalTransform.misc.url= + -DlocalTransform.pdfrenderer.url= + -DlocalTransform.imagemagick.url= " ports: - "7203:7203" #JMX connect via service:jmx:rmi:///jndi/rmi://localhost:7203/jmxrmi - "5005:5005" #Java debugging - "8081:8080" #Browser port for Alfresco + share: image: ${SHARE_IMAGE}:${SHARE_TAG} environment: @@ -26,6 +43,7 @@ services: - REPO_PORT=8080 ports: - 8082:8080 #Browser port for Share + postgres: image: postgres:${POSTGRES_TAG} environment: @@ -34,13 +52,12 @@ services: - POSTGRES_DB=alfresco ports: - 5432:5432 + search: - image: quay.io/alfresco/search-services:${SEARCH_TAG} + image: quay.io/alfresco/insight-engine:${SEARCH_TAG} environment: #Replication properties - - REPLICATION_TYPE=master - #- REPLICATION_AFTER=commit,startup- SOLR_ALFRESCO_HOST=alfresco - #- REPLICATION_CONFIG_FILES=schema.xml,stopwords.txt- SOLR_ALFRESCO_PORT=8080 + # - REPLICATION_TYPE=master #Solr needs to know how to register itself with Alfresco - SOLR_ALFRESCO_HOST=alfresco - SOLR_ALFRESCO_PORT=8080 @@ -55,26 +72,6 @@ services: - ENABLE_SPELLCHECK=${SEARCH_ENABLE_SPELLCHECK} ports: - 8083:8983 #Browser port - #search_slave: - # image: quay.io/alfresco/search-services:${SEARCH_TAG} - # environment: - # #Replication properties - # - REPLICATION_TYPE=slave - # - REPLICATION_MASTER_HOST=search - # - REPLICATION_MASTER_PORT=8983 - # #- REPLICATION_MASTER_PROTOCOL=http - # #- REPLICATION_CORE_NAME=alfresco - # #- REPLICATION_POLL_INTERVAL=00:00:60 - # #Solr needs to know how to register itself with Alfresco - # - SOLR_ALFRESCO_HOST=alfresco - # - SOLR_ALFRESCO_PORT=8080 - # #Alfresco needs to know how to call solr - # - SOLR_SOLR_HOST=search - # - SOLR_SOLR_PORT=8983 - # #Create the default alfresco and archive cores - # - SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive - # ports: - # - 8084:8983 #Browser port activemq: image: alfresco/alfresco-activemq:5.15.6 diff --git a/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml b/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml new file mode 100644 index 000000000..93671b382 --- /dev/null +++ b/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml @@ -0,0 +1,87 @@ +version: "3.7" + +services: + alfresco: + image: ${ALFRESCO_IMAGE}:${ALFRESCO_TAG} + environment: + JAVA_OPTS : " + -Ddb.driver=org.postgresql.Driver + -Ddb.username=alfresco + -Ddb.password=alfresco + -Ddb.url=jdbc:postgresql://postgres:5432/alfresco + -Dsolr.host=search_slave_load_balancer + -Dsolr.port=80 + -Dalfresco.protocol=http + -Dsolr.secureComms=none + -Dalfresco.secureComms=none + -Dsolr.baseUrl=/solr-slave + -Dindex.subsystem.name=solr6 + -Dalfresco.restApi.basicAuthScheme=true + -Dcsrf.filter.enabled=false + -Dcors.enabled=false + -Dmessaging.broker.url=\"failover:(nio://activemq:61616)?timeout=3000&jms.useCompression=true\" + + -Dtransform.service.enabled=false + -Dtransform.service.url= + -Dsfs.url= + -Dlocal.transform.service.enabled=false + -DlocalTransform.libreoffice.url= + -DlocalTransform.tika.url= + -DlocalTransform.misc.url= + -DlocalTransform.pdfrenderer.url= + -DlocalTransform.imagemagick.url= + " + +# Insight Engine or Search Services + search: + image: quay.io/alfresco/search-services:test + environment: + #Solr needs to know how to register itself with Alfresco + - REPLICATION_TYPE=master + - SOLR_ALFRESCO_HOST=alfresco + - SOLR_ALFRESCO_PORT=8080 + - REPLICATION_AFTER=commit,startup + - REPLICATION_CONFIG_FILES=schema.xml,stopwords.txt + #Alfresco needs to know how to call solr + - SOLR_SOLR_HOST=search + - SOLR_SOLR_PORT=8983 + #Create the default alfresco and archive cores + - SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive + #HTTP by default + - ALFRESCO_SECURE_COMMS=none + #Enable Spellcheck by setting to true + - ENABLE_SPELLCHECK=${SEARCH_ENABLE_SPELLCHECK} + ports: + - 8083:8983 #Browser port + + search_slave_load_balancer: + image: nginx:${NGINX_TAG} + links: + - search_slave + volumes: + - ./master-slave/nginx.conf:/etc/nginx/conf.d/default.conf + ports: + - 8084:80 + + search_slave: + image: quay.io/alfresco/insight-engine:test + environment: + #Replication properties + - REPLICATION_TYPE=slave + - REPLICATION_MASTER_HOST=search + - REPLICATION_MASTER_PORT=8983 + #- REPLICATION_CORE_NAME=${solr.core.name} + #- REPLICATION_MASTER_PROTOCOL=http + #- REPLICATION_POLL_INTERVAL=00:00:60 + #Solr needs to know how to register itself with Alfresco + - SOLR_ALFRESCO_HOST=alfresco + - SOLR_ALFRESCO_PORT=8080 + #Alfresco needs to know how to call solr + - SOLR_SOLR_HOST=search + - SOLR_SOLR_PORT=8983 + #Create the default alfresco and archive cores + - SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive + #HTTP by default + - ALFRESCO_SECURE_COMMS=none + ports: + - 8983 #Browser port diff --git a/search-services/packaging/src/docker/6.x/master-slave/nginx.conf b/search-services/packaging/src/docker/6.x/master-slave/nginx.conf new file mode 100644 index 000000000..371806bba --- /dev/null +++ b/search-services/packaging/src/docker/6.x/master-slave/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 80; + resolver 127.0.0.11 valid=5s; + set $upstream_endpoint http://search_slave:8983; + + location / { + rewrite ^/(.*) /$1 break; + proxy_pass $upstream_endpoint; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} \ No newline at end of file From 2f210293c6349828cd37385042bd8ac33ee68630 Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 5 Feb 2020 14:16:40 +0000 Subject: [PATCH 08/94] SEARCH-1681 adding other sharding tests with testgroup to avoid tests on bamboo --- .../searchServices/search/ShardInfoTest.java | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 087641391..70c732525 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -165,4 +165,194 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertEquals(instance.getState(), "ACTIVE"); } } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithDBIDRange() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "DB_ID_RANGE_ID"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithMODACLID() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "MOD_ACL_ID"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithACLID() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "ACL_ID"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithDate() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "DATE"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } + + @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) + public void getShardInfoWithProperty() throws JsonProcessingException + { + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() + .getInfo(); + restClient.assertStatusCodeIs(HttpStatus.OK); + info.assertThat().entriesListIsNotEmpty(); + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); + + List entries = info.getEntries(); + for (RestShardInfoModel shardInfoModel : entries) + { + RestShardInfoModel model = shardInfoModel.getModel(); + assertEquals(model.getTemplate(), "rerank"); + assertEquals(model.getShardMethod(), "PROPERTY"); + assertEquals(model.getMode(), "MASTER"); + assertTrue(model.getHasContent()); + + assertTrue(stores.contains(model.getStores())); + + List shards = model.getShards(); + assertNotNull(shards); + RestShardModel shard = shards.iterator().next(); + assertNotNull(shard); + List instances = shard.getInstances(); + assertNotNull(instances); + RestInstanceModel instance = instances.iterator().next(); + assertNotNull(instance); + + assertTrue(baseUrls.contains(instance.getBaseUrl())); + + assertEquals(instance.getState(), "ACTIVE"); + } + } } From 3d3c7924f998f8e3954987dab0a6827de25e1b51 Mon Sep 17 00:00:00 2001 From: Alex Mukha Date: Wed, 5 Feb 2020 14:35:32 +0000 Subject: [PATCH 09/94] Record new decisions about async content tracker --- .../0007-message-driven-content-tracker.md | 2 +- ...message-driven-content-tracker-next-gen.md | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 search-services/alfresco-search/doc/architecture/decisions/0009-message-driven-content-tracker-next-gen.md diff --git a/search-services/alfresco-search/doc/architecture/decisions/0007-message-driven-content-tracker.md b/search-services/alfresco-search/doc/architecture/decisions/0007-message-driven-content-tracker.md index 41d72017d..f527985f3 100644 --- a/search-services/alfresco-search/doc/architecture/decisions/0007-message-driven-content-tracker.md +++ b/search-services/alfresco-search/doc/architecture/decisions/0007-message-driven-content-tracker.md @@ -4,7 +4,7 @@ Date: 09/04/2019 ## Status -Approved +~~Approved~~ Postponed, see [version 2](0009-message-driven-content-tracker-next-gen.md) ## Context diff --git a/search-services/alfresco-search/doc/architecture/decisions/0009-message-driven-content-tracker-next-gen.md b/search-services/alfresco-search/doc/architecture/decisions/0009-message-driven-content-tracker-next-gen.md new file mode 100644 index 000000000..3d9ee3ff0 --- /dev/null +++ b/search-services/alfresco-search/doc/architecture/decisions/0009-message-driven-content-tracker-next-gen.md @@ -0,0 +1,28 @@ +# Message Driven Content Tracker v2 + +Date: 05/02/2020 + +## Status + +WIP + +## Context + +This is a second iteration of content tracking via message bus design. See [previous version](0007-message-driven-content-tracker.md). + +New content tracker implementation will be based on new Search Services architecture (SS v2.0 or next gen). Main context behind this decision is almost the same as for v1 - get more throughput by leveraging new Transform Service. + +## Decision + +The decision is based on [version 1](0007-message-driven-content-tracker.md). The main differences are: +* Shared File Store may not be the right option as it is only available for Enterprise. Alternatively the URL to content can point to other locations. (TBC) +* The change in behaviour requires a major release of Search Services, most likely version 2.0. +* The changes in Content Repository will be available from version 6.3. +* The synchronous transformation APIs will remain functional until 7.0. + +Details of the architecture to be clarified (WIP). + +## Consequences +Additional latency will be introduced due to the extra calls when using the Transform Service. Also the transformation capabilities are much more limited. + +This design highlights a major difference in behaviour, which requires a major release of Search Services. From d98740f4c181704af7aaafc633d833ba9c820f9a Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 5 Feb 2020 16:41:01 +0000 Subject: [PATCH 10/94] SEARCH-1681 updating the pom file for the restapi version --- e2e-test/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 628c981b8..3b30095da 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,8 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.28 - 1.26 + 1.29 1.13 3.0.19 3.3.0 From c618cb5d1daf38688fc3f80d10e1be8bfffc0323 Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 6 Feb 2020 11:33:38 +0000 Subject: [PATCH 11/94] SEARCH-1681 adding test group to shardInfoWithAdminAuthroity test as build is in explicit_id mode --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 70c732525..075e6f27b 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -40,7 +40,7 @@ import org.springframework.http.HttpStatus; public class ShardInfoTest extends AbstractE2EFunctionalTest { /* The test that will be excluded when running master slave setup, excluding the ASS_MASTER test group. */ - @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER }) + @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.EXPLICIT_SHARDING }) public void getShardInfoWithAdminAuthority() throws JsonProcessingException { RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() From 264c6c956271fec4a5c6535e162db66f711a1ab3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2020 22:12:42 +0000 Subject: [PATCH 12/94] Bump restapi from 1.28 to 1.30 in /e2e-test Bumps [restapi](https://github.com/Alfresco/alfresco-tas-restapi) from 1.28 to 1.30. - [Release notes](https://github.com/Alfresco/alfresco-tas-restapi/releases) - [Commits](https://github.com/Alfresco/alfresco-tas-restapi/compare/v1.28...v1.30) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 628c981b8..ce4a08807 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,7 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.28 + 1.30 1.26 1.13 3.0.19 From 09a5c67678536f2edbeaaec429d0009795ae9ee7 Mon Sep 17 00:00:00 2001 From: Meenal Bhave Date: Fri, 7 Feb 2020 13:28:19 +0000 Subject: [PATCH 13/94] Fix/search 2088: Implemented a new test for permission checks --- .../search/SearchPermissionsTest.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java new file mode 100644 index 000000000..96417269f --- /dev/null +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2020 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.test.search.functional.searchServices.search; + +import javax.json.Json; +import javax.json.JsonObject; + +import org.alfresco.rest.search.SearchResponse; +import org.alfresco.test.search.functional.AbstractE2EFunctionalTest; +import org.alfresco.utility.constants.UserRole; +import org.alfresco.utility.model.FileModel; +import org.alfresco.utility.model.FileType; +import org.alfresco.utility.model.FolderModel; +import org.alfresco.utility.model.UserModel; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Search end point Public API test with Permission checks + * + * @author Meenal Bhave + */ +public class SearchPermissionsTest extends AbstractE2EFunctionalTest +{ + private FileModel file1, file2; + private FolderModel parentFolder, folder1, folder2; + private UserModel testUser1, testUser2, testUser3; + + @BeforeClass(alwaysRun = true) + public void dataPreparation() throws Exception + { + /* + * Create the following file structure in the same Site : In addition to the preconditions created in dataPreparation + * |- permGrandParent + * |-- permChild1 + * |------ permFile1 + * |-- permChild2 + * |------ permFile2 + */ + + parentFolder = new FolderModel("permGrandParent"); + dataContent.usingUser(testUser).usingSite(testSite).createFolder(parentFolder); + folder1 = dataContent.usingUser(testUser).usingSite(testSite).usingResource(parentFolder).createFolderCmisApi("permChild1"); + folder2 = dataContent.usingUser(testUser).usingSite(testSite).usingResource(parentFolder).createFolderCmisApi("permChild2"); + + file1 = new FileModel("permFile1", FileType.TEXT_PLAIN, "File1 with inherited permissions"); + file2 = new FileModel("permFile2", FileType.TEXT_PLAIN, "File2 with inherited permissions"); + + // Create test users + testUser1 = dataUser.createRandomTestUser("UserSiteMember"); + testUser2 = dataUser.createRandomTestUser("UserNotASiteMemeber"); + testUser3 = dataUser.createRandomTestUser("UserWithoutContentAccess"); + + dataUser.addUserToSite(testUser1, testSite, UserRole.SiteCollaborator); + + dataContent.usingUser(testUser).usingSite(testSite).usingResource(folder1).createContent(file1); + dataContent.usingUser(testUser).usingSite(testSite).usingResource(folder2).createContent(file2); + + // Deny testUser1 - access to file1 + JsonObject userPermission = Json + .createObjectBuilder() + .add("permissions", + Json.createObjectBuilder() + .add("isInheritanceEnabled", false) + .add("locallySet", + Json.createObjectBuilder() + .add("authorityId", testUser1.getUsername()) + .add("name", "SiteCollaborator") + .add("accessStatus", "DENIED") + )).build(); + String putBody = userPermission.toString(); + restClient.authenticateUser(testUser).withCoreAPI().usingNode(file1).updateNode(putBody); + + // Allow testUser2 - access to file2, user is not a site member + userPermission = Json + .createObjectBuilder() + .add("permissions", + Json.createObjectBuilder() + .add("isInheritanceEnabled", false) + .add("locallySet", + Json.createObjectBuilder() + .add("authorityId", testUser2.getUsername()) + .add("name", "SiteContributor") + .add("accessStatus", "ALLOWED") + )).build(); + putBody = userPermission.toString(); + restClient.authenticateUser(testUser).withCoreAPI().usingNode(file2).updateNode(putBody); + + waitForContentIndexing(file2.getContent(), true); + } + + @Test + public void searchResultsRespectInheritedPermissions() + { + // Search as testUser: expect all: 5 results: When user is a Site Manager + SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); + int resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 5, "Unexpected Result count for testUser: Expected 5, received: " + resultCount); + + // Search as testUser1: expect 3 results: when user is a site member but without permission to a content + response = queryAsUser(testUser1, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); + + // Search as testUser2: expect 1 result: When user isn't a site member but has granular permissions to a content + response = queryAsUser(testUser2, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); + + // Search as testUser3: expect none: 0 results: When user isn't a site member / does not have granular permissions to the content + response = queryAsUser(testUser3, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); + } +} From e40abc7fa5e22e10e76a8964514c195c776a817d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2020 22:13:21 +0000 Subject: [PATCH 14/94] Bump lombok from 1.18.10 to 1.18.12 in /e2e-test Bumps [lombok](https://github.com/rzwitserloot/lombok) from 1.18.10 to 1.18.12. - [Release notes](https://github.com/rzwitserloot/lombok/releases) - [Changelog](https://github.com/rzwitserloot/lombok/blob/master/doc/changelog.markdown) - [Commits](https://github.com/rzwitserloot/lombok/compare/v1.18.10...v1.18.12) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 628c981b8..f57c9ae59 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -120,7 +120,7 @@ org.projectlombok lombok - 1.18.10 + 1.18.12 test From b239d5f7eddc32572bb58032258fb1c226455597 Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 10 Feb 2020 08:25:48 +0000 Subject: [PATCH 15/94] SEARCH-1681 a single test for sharding with a seperate test group --- .../java/org/alfresco/search/TestGroup.java | 1 + .../searchServices/search/ShardInfoTest.java | 229 +++--------------- 2 files changed, 31 insertions(+), 199 deletions(-) diff --git a/e2e-test/src/main/java/org/alfresco/search/TestGroup.java b/e2e-test/src/main/java/org/alfresco/search/TestGroup.java index fbb90a64e..3cb94174b 100644 --- a/e2e-test/src/main/java/org/alfresco/search/TestGroup.java +++ b/e2e-test/src/main/java/org/alfresco/search/TestGroup.java @@ -30,6 +30,7 @@ public class TestGroup public static final String ASS_MASTER_SLAVE = "ASS_Master_Slave"; // Alfresco Search Services using master slave configurations public static final String ASS_MASTER ="ASS_Master"; // Alfresco search services using master/stand alone mode public static final String EXPLICIT_SHARDING ="Explicit_Sharding"; // Alfresco search services using sharded environment and explicit routing + public static final String SHARDING ="Sharding"; // Alfresco search services using sharded environment public static final String NOT_INSIGHT_ENGINE = "Not_InsightEngine"; // When Alfresco Insight Engine 1.0 isn't running diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 075e6f27b..b940d1288 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -40,7 +40,7 @@ import org.springframework.http.HttpStatus; public class ShardInfoTest extends AbstractE2EFunctionalTest { /* The test that will be excluded when running master slave setup, excluding the ASS_MASTER test group. */ - @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.EXPLICIT_SHARDING }) + @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.SHARDING }) public void getShardInfoWithAdminAuthority() throws JsonProcessingException { RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() @@ -128,231 +128,62 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR); } - @Test(groups = { TestGroup.ACS_60n }) - public void getShardInfoWithExplicitID() throws JsonProcessingException + @Test(groups = { TestGroup.ACS_60n, TestGroup.SHARDING }) + public void getShardInfoWith2OrMoreShards() throws JsonProcessingException { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); + RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI().getInfo(); restClient.assertStatusCodeIs(HttpStatus.OK); info.assertThat().entriesListIsNotEmpty(); + + // Checks based on 2 default cores: alfresco and archive assertEquals(info.getPagination().getTotalItems().intValue(), 2); - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - List entries = info.getEntries(); + // We could check entries.size() matches pagination count above for (RestShardInfoModel shardInfoModel : entries) { RestShardInfoModel model = shardInfoModel.getModel(); assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "EXPLICIT_ID"); assertEquals(model.getMode(), "MASTER"); assertTrue(model.getHasContent()); - assertTrue(stores.contains(model.getStores())); - + assertTrue(model.getNumberOfShards()>=2); + + // Sharding Type related checks (an example) + List shardingMethods = Arrays.asList("DB_ID", "DB_ID_RANGE", "EXPLICIT_ID", "ACL_ID", "MOD_ACL_ID", "DATE", "PROPERTY"); + String shardingMethod = model.getShardMethod(); + assertTrue(shardingMethods.contains(shardingMethod), "Unexpected Sharding Method Found: " + shardingMethod); + // Shard Instance related checks: You could iterate through all the instances in a loop List shards = model.getShards(); - assertNotNull(shards); + assertNotNull(shards.contains(shards), "Unexpected number of shards found:" + shards); RestShardModel shard = shards.iterator().next(); assertNotNull(shard); List instances = shard.getInstances(); - assertNotNull(instances); + assertNotNull(instances.contains(instances), "Unexpected number of instances found:" + instances); RestInstanceModel instance = instances.iterator().next(); assertNotNull(instance); - assertTrue(baseUrls.contains(instance.getBaseUrl())); assertEquals(instance.getState(), "ACTIVE"); - } - } - - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) - public void getShardInfoWithDBIDRange() throws JsonProcessingException - { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); - restClient.assertStatusCodeIs(HttpStatus.OK); - info.assertThat().entriesListIsNotEmpty(); - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); - List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - - List entries = info.getEntries(); - for (RestShardInfoModel shardInfoModel : entries) - { - RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "DB_ID_RANGE_ID"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - - assertTrue(stores.contains(model.getStores())); - - List shards = model.getShards(); - assertNotNull(shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - - assertTrue(baseUrls.contains(instance.getBaseUrl())); - assertEquals(instance.getState(), "ACTIVE"); - } - } - - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) - public void getShardInfoWithMODACLID() throws JsonProcessingException - { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); - restClient.assertStatusCodeIs(HttpStatus.OK); - info.assertThat().entriesListIsNotEmpty(); - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); - List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - - List entries = info.getEntries(); - for (RestShardInfoModel shardInfoModel : entries) - { - RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "MOD_ACL_ID"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - - assertTrue(stores.contains(model.getStores())); - - List shards = model.getShards(); - assertNotNull(shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - - assertTrue(baseUrls.contains(instance.getBaseUrl())); + // shardparams related checks + String shardParams = instance.getShardParams(); + if(shardingMethod == "EXPLICIT_ID"){ + assertNotNull(shardParams, "shard.key="); + } - assertEquals(instance.getState(), "ACTIVE"); - } - } - - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) - public void getShardInfoWithACLID() throws JsonProcessingException - { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); - restClient.assertStatusCodeIs(HttpStatus.OK); - info.assertThat().entriesListIsNotEmpty(); - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); - List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - - List entries = info.getEntries(); - for (RestShardInfoModel shardInfoModel : entries) - { - RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "ACL_ID"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - - assertTrue(stores.contains(model.getStores())); - - List shards = model.getShards(); - assertNotNull(shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - - assertTrue(baseUrls.contains(instance.getBaseUrl())); + if(shardingMethod == "DB_ID_RANGE"){ + assertNotNull(shardParams, "shard.key="); + } - assertEquals(instance.getState(), "ACTIVE"); - } - } - - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) - public void getShardInfoWithDate() throws JsonProcessingException - { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); - restClient.assertStatusCodeIs(HttpStatus.OK); - info.assertThat().entriesListIsNotEmpty(); - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); - List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - - List entries = info.getEntries(); - for (RestShardInfoModel shardInfoModel : entries) - { - RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "DATE"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - - assertTrue(stores.contains(model.getStores())); - - List shards = model.getShards(); - assertNotNull(shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - - assertTrue(baseUrls.contains(instance.getBaseUrl())); + if(shardingMethod == "DATE"){ + assertNotNull(shardParams, "shard.key="); + } - assertEquals(instance.getState(), "ACTIVE"); - } - } - - @Test(groups = { TestGroup.ACS_60n, TestGroup.EXPLICIT_SHARDING }) - public void getShardInfoWithProperty() throws JsonProcessingException - { - RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() - .getInfo(); - restClient.assertStatusCodeIs(HttpStatus.OK); - info.assertThat().entriesListIsNotEmpty(); - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); - List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); - - List entries = info.getEntries(); - for (RestShardInfoModel shardInfoModel : entries) - { - RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getShardMethod(), "PROPERTY"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - - assertTrue(stores.contains(model.getStores())); - - List shards = model.getShards(); - assertNotNull(shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - - assertTrue(baseUrls.contains(instance.getBaseUrl())); - - assertEquals(instance.getState(), "ACTIVE"); + if(shardingMethod == "PROPERTY"){ + assertNotNull(shardParams, "shard.key="); + } } } } From 5eaf0e52922c7e8d1e2c8c876e2f7b0443cb88af Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 10 Feb 2020 09:19:58 +0000 Subject: [PATCH 16/94] SEARCH-1681 a single test for sharding with a seperate test group --- .../functional/searchServices/search/ShardInfoTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index b940d1288..217e56960 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -174,11 +174,12 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest } if(shardingMethod == "DB_ID_RANGE"){ - assertNotNull(shardParams, "shard.key="); + assertNotNull(shardParams, ""); } if(shardingMethod == "DATE"){ - assertNotNull(shardParams, "shard.key="); + assertNotNull(shardParams, "shard.key= " + + "shard.date.grouping"); } if(shardingMethod == "PROPERTY"){ From 242b9bce28ef4900a80f447d067f567ce2f97aa0 Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 10 Feb 2020 12:01:07 +0000 Subject: [PATCH 17/94] SEARCH-1681 adding switch statement instead of if for shard params --- .../searchServices/search/ShardInfoTest.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 217e56960..f46a9c1f7 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -168,22 +168,20 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertEquals(instance.getState(), "ACTIVE"); // shardparams related checks - String shardParams = instance.getShardParams(); - if(shardingMethod == "EXPLICIT_ID"){ - assertNotNull(shardParams, "shard.key="); - } - - if(shardingMethod == "DB_ID_RANGE"){ - assertNotNull(shardParams, ""); - } - - if(shardingMethod == "DATE"){ - assertNotNull(shardParams, "shard.key= " - + "shard.date.grouping"); - } - - if(shardingMethod == "PROPERTY"){ - assertNotNull(shardParams, "shard.key="); + String shardParams = instance.getShardParams(); + switch (shardingMethod) + { + case "DB_ID_RANGE": + assertTrue(shardParams.contains("shard.key=")); + case "PROPERTY": + assertTrue(shardParams.contains("shard.key=")); + case "EXPLICIT_ID": + assertTrue(shardParams.contains("shard.key=")); + case "DATE": + assertTrue(shardParams.contains("shard.key=")); + break; + default: + throw new AssertionError("Not as expected: " + shardParams.toString()); } } } From 7e16a5bd5f62c910d57f962f63d8474c82c83df4 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 11 Feb 2020 10:01:27 +0000 Subject: [PATCH 18/94] Merge branch 'feature/SEARCH-2014_SolrAdminAPI_14x' into 'release/V1.4.x' Feature/search 2014 solr admin api 14x See merge request search_discovery/insightengine!368 (cherry picked from commit 98343dfc59425a4f07fd4450d104e8c426b72802) --- e2e-test/pom.xml | 1 - .../java/org/alfresco/search/TestGroup.java | 6 +- .../solr/admin/SolrE2eAdminTest.java | 519 ++++++++++++ e2e-test/src/test/resources/SearchSuite.xml | 14 + .../solr/AlfrescoCoreAdminHandler.java | 801 +++++++++++++++--- .../org/alfresco/solr/tracker/AclTracker.java | 14 + .../solr/tracker/MetadataTracker.java | 15 + .../solr/AlfrescoCoreAdminHandlerIT.java | 22 +- 8 files changed, 1245 insertions(+), 147 deletions(-) create mode 100644 e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index f12c76d11..28af17776 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -12,7 +12,6 @@ Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share 1.30 - 1.26 1.13 3.0.19 3.3.0 diff --git a/e2e-test/src/main/java/org/alfresco/search/TestGroup.java b/e2e-test/src/main/java/org/alfresco/search/TestGroup.java index fbb90a64e..f2e88318c 100644 --- a/e2e-test/src/main/java/org/alfresco/search/TestGroup.java +++ b/e2e-test/src/main/java/org/alfresco/search/TestGroup.java @@ -23,16 +23,18 @@ public class TestGroup // Used for TestRail test annotation public static final String SEARCH = "search"; public static final String REST_API = "rest-api"; - + public static final String PREUPGRADE = "pre-upgrade"; public static final String POSTUPGRADE = "post-upgrade"; public static final String ASS_MASTER_SLAVE = "ASS_Master_Slave"; // Alfresco Search Services using master slave configurations public static final String ASS_MASTER ="ASS_Master"; // Alfresco search services using master/stand alone mode public static final String EXPLICIT_SHARDING ="Explicit_Sharding"; // Alfresco search services using sharded environment and explicit routing + public static final String ASS_SHARDING = "ASS_Sharding"; // Alfresco Search Services using Sharding + public static final String ASS_SHARDING_DB_ID_RANGE = "ASS_Sharding_DB_ID_RANGE"; // Alfresco Search Services using Sharding with DB_ID_RANGE public static final String NOT_INSIGHT_ENGINE = "Not_InsightEngine"; // When Alfresco Insight Engine 1.0 isn't running - + public static final String ACS_52n = "ACS_52n"; // Alfresco Content Services 5.2.n public static final String ACS_60n = "ACS_60n"; // Alfresco Content Services 6.0 or above public static final String ACS_61n = "ACS_61n"; // Alfresco Content Services 6.1 or above diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java new file mode 100644 index 000000000..0ae0abd97 --- /dev/null +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2020 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.test.search.functional.searchServices.solr.admin; + +import java.util.ArrayList; +import java.util.List; + +import org.alfresco.rest.core.RestResponse; +import org.alfresco.search.TestGroup; +import org.alfresco.test.search.functional.AbstractE2EFunctionalTest; +import org.springframework.context.annotation.Configuration; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * End to end tests for SOLR Admin actions REST API, available from: + * + * http://:/solr/admin/cores?action=* + * + * @author aborroy + * + */ +@Configuration +public class SolrE2eAdminTest extends AbstractE2EFunctionalTest +{ + + + // SOLR default response status codes (returned in responseHeader.status) + private static final String SOLR_RESPONSE_STATUS_OK = "0"; + private static final String SOLR_RESPONSE_STATUS_INTERNAL_ERROR = "400"; + + // Alfresco SOLR action response status identifiers + private static final String ACTION_RESPONSE_REPORT = "report"; + + // Default Alfresco SOLR Core Names + List defaultCoreNames = new ArrayList<>(List.of("alfresco", "archive")); + + @Test(priority = 1) + public void testNodeReport() throws Exception + { + String nodeid = "200"; + RestResponse response = restClient.withParams("nodeid=" + nodeid).withSolrAdminAPI().getAction("nodeReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + + defaultCoreNames.forEach(core -> { + Assert.assertNotNull(response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core)); + }); + } + + /** + * Node Report requires "nodeid" parameter. + * This test will fail as we are missing to pass the parameter. + * @throws Exception + */ + @Test(priority = 2) + public void testNodeReportError() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("nodeReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + } + + @Test(priority = 3) + public void testAclReport() throws Exception + { + String aclid = "1"; + RestResponse response = restClient.withParams("aclid=" + aclid).withSolrAdminAPI().getAction("aclReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + } + + /** + * Acl Report requires "aclid" parameter. + * This test will fail as we are missing to pass the parameter. + * @throws Exception + */ + @Test(priority = 4) + public void testAclReportError() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("aclReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + } + + @Test(priority = 5) + public void testTxReport() throws Exception + { + String coreName = "alfresco"; + String txid = "1"; + + RestResponse response = restClient.withParams("coreName=" + coreName, "txid=" + txid).withSolrAdminAPI().getAction("txReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + } + + /** + * Transaction report requires "txid" parameter. + * This test will fail as we are missing to pass the parameter. + * @throws Exception + */ + @Test(priority = 6) + public void testTxReportError() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("txReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + } + + @Test(priority = 7) + public void testAclTxReport() throws Exception + { + String acltxid = "1"; + + RestResponse response = restClient.withParams("acltxid=" + acltxid).withSolrAdminAPI().getAction("aclTxReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + } + + /** + * AclTx report requires "acltxid" parameter. + * This test will fail as we are missing to pass the parameter. + * @throws Exception + */ + @Test(priority = 8) + public void testAclTxReportError() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("aclTxReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + } + + @Test(priority = 9) + public void testReport() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction(ACTION_RESPONSE_REPORT); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + } + + @Test(priority = 10) + public void testSummary() throws Exception + { + String core = "alfresco"; + + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("summary"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get("Summary").toString(); + Assert.assertNotNull(report); + } + + @Test(priority = 11) + public void testCheck() throws Exception + { + String core = "alfresco"; + + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("check"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * This action only applies to DB_ID_RANGE Sharding method. + * This test verifies expected result when using another deployment + * @throws Exception + */ + @Test(priority = 12) + public void testRangeCheck() throws Exception + { + String coreName = "alfresco"; + + RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("rangeCheck"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String expand = response.getResponse().body().jsonPath().get("expand").toString(); + Assert.assertEquals(expand, "-1"); + } + + /** + * When using DB_ID_RANGE Sharding method, expand param is including a number of nodes to be extended. + * @throws Exception + */ + @Test(priority = 13, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) + public void testRangeCheckSharding() throws Exception + { + String coreName = "alfresco"; + + RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("rangeCheck"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String expand = response.getResponse().body().jsonPath().get("expand").toString(); + Assert.assertNotEquals(expand, "-1"); + } + + /** + * This action only applies to DB_ID_RANGE Sharding method. + * This test verifies expected result when using another deployment + * @throws Exception + */ + @Test(priority = 14) + public void testExpand() throws Exception + { + String coreName = "alfresco"; + String add = "1000"; + + RestResponse response = restClient.withParams("coreName=" + coreName, "add=" + add).withSolrAdminAPI().getAction("expand"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + // This action only applies to DB_ID_RANGE Sharding method + String expand = response.getResponse().body().jsonPath().get("expand").toString(); + Assert.assertEquals(expand, "-1"); + } + + /** + * When using DB_ID_RANGE Sharding method, expand param is including a number of nodes extended. + * @throws Exception + */ + @Test(priority = 15, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) + public void testExpandSharding() throws Exception + { + String coreName = "alfresco"; + String add = "1000"; + + RestResponse response = restClient.withParams("coreName=" + coreName, "add=" + add).withSolrAdminAPI().getAction("expand"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + // This action only applies to DB_ID_RANGE Sharding method + String expand = response.getResponse().body().jsonPath().get("expand").toString(); + Assert.assertNotEquals(expand, "-1"); + } + + @Test(priority = 16) + public void testPurge() throws Exception + { + String core = "alfresco"; + String txid = "1"; + + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("purge"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + @Test(priority = 17) + public void testFix() throws Exception + { + String core = "alfresco"; + + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("fix"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + @Test(priority = 18) + public void testReindex() throws Exception + { + String core = "alfresco"; + String txid = "1"; + + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("reindex"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + @Test(priority = 19) + public void testRetry() throws Exception + { + String core = "alfresco"; + + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("retry"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + @Test(priority = 20) + public void testIndex() throws Exception + { + String core = "alfresco"; + String txid = "1"; + + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("index"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + @Test(priority = 21) + public void testLog4J() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("log4j"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * This test will fail if it's executed twice + * @throws Exception + */ + @Test(priority = 22) + public void testNewCore() throws Exception + { + String core = "newCore"; + String storeRef = "workspace://SpacesStore"; + String template = "rerank"; + + RestResponse response = restClient.withParams("coreName=" + core, "storeRef=" + storeRef, "template=" + template) + .withSolrAdminAPI().getAction("newCore"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * When creating a core that already exists, this action fails. + * @throws Exception + */ + @Test(priority = 23) + public void testNewCoreError() throws Exception + { + String core = "alfresco"; + String template = "rerank"; + + RestResponse response = restClient.withParams("coreName=" + core, "template=" + template) + .withSolrAdminAPI().getAction("newCore"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "error"); + } + + @Test(priority = 24) + public void testUpdateCore() throws Exception + { + String core = "alfresco"; + + RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction("updateCore"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * When updating a core that doesn't exist, this action fails. + * @throws Exception + */ + @Test(priority = 25) + public void testUpdateCoreError() throws Exception + { + String core = "nonExistingCore"; + + RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction("updateCore"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "error"); + } + + /** + * This test updates "shared.properties" memory loading for every SOLR core. + * @throws Exception + */ + @Test(priority = 26) + public void testUpdateShared() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("updateShared"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * This test will fail if it's executed twice + * @throws Exception + */ + @Test(priority = 27) + public void testNewDefaultCore() throws Exception + { + String core = "newDefaultCore"; + String storeRef = "workspace://SpacesStore"; + String template = "rerank"; + + RestResponse response = restClient + .withParams("coreName=" + core, "storeRef=" + storeRef, "template=" + template) + .withSolrAdminAPI().getAction("newDefaultIndex"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + + /** + * When creating a core that already exists, this action fails. + * @throws Exception + */ + @Test(priority = 28) + public void testNewDefaultCoreError() throws Exception + { + String core = "alfresco"; + String template = "rerank"; + + RestResponse response = restClient.withParams("coreName=" + core, "template=" + template) + .withSolrAdminAPI().getAction("newDefaultIndex"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "error"); + } + + /** + * This test has to be executed after "testNewCore" test, otherwise it will fail + */ + @Test(priority = 99, dependsOnMethods = ("testNewCore")) + public void testRemoveCore() throws Exception + { + String core = "newCore"; + String storeRef = "workspace://SpacesStore"; + + RestResponse response = restClient + .withParams("coreName=" + core, "storeRef=" + storeRef) + .withSolrAdminAPI().getAction("removeCore"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + } + +} diff --git a/e2e-test/src/test/resources/SearchSuite.xml b/e2e-test/src/test/resources/SearchSuite.xml index 2d5e701e9..111a01356 100644 --- a/e2e-test/src/test/resources/SearchSuite.xml +++ b/e2e-test/src/test/resources/SearchSuite.xml @@ -20,7 +20,21 @@ + + + + + + + + + + + + + + diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java index 4303ae3dd..b578bea26 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2015 Alfresco Software Limited. + * Copyright (C) 2005-2020 Alfresco Software Limited. * * This file is part of Alfresco * @@ -61,6 +61,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -69,6 +70,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -123,6 +126,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler protected static final Logger LOGGER = LoggerFactory.getLogger(AlfrescoCoreAdminHandler.class); private static final String REPORT = "report"; + private static final String SUMMARY = "Summary"; private static final String ARG_ACLTXID = "acltxid"; static final String ARG_TXID = "txid"; private static final String ARG_ACLID = "aclid"; @@ -142,6 +146,25 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler ARCHIVE_CORE_NAME, StoreRef.STORE_REF_ARCHIVE_SPACESSTORE, VERSION_CORE_NAME, new StoreRef("workspace", "version2Store")); + /** + * Action status to be added to response + * - success: the action has been executed successfully + * - error: the action has not been executed, error message is added to the response + * - scheduled: the action will be executed as part of the Tracker Maintenance step + */ + private static final String ACTION_STATUS_SUCCESS = "success"; + private static final String ACTION_STATUS_ERROR = "error"; + private static final String ACTION_STATUS_SCHEDULED = "scheduled"; + + /** + * JSON/XML labels for the Action response + */ + private static final String ACTION_LABEL = "action"; + private static final String ACTION_STATUS_LABEL = "status"; + private static final String ACTION_ERROR_MESSAGE_LABEL = "errorMessage"; + private static final String ACTION_TX_TO_REINDEX = "txToReindex"; + private static final String ACTION_ACL_CHANGE_SET_TO_REINDEX = "aclChangeSetToReindex"; + private SolrTrackerScheduler scheduler; private TrackerRegistry trackerRegistry; private ConcurrentHashMap informationServers; @@ -194,6 +217,8 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler /** * Creates new default cores based on the "createDefaultCores" String passed in. + * + * Synchronous execution * * @param names comma delimited list of core names that will be created. * @param numShards The total number of shards. @@ -201,9 +226,19 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * @param nodeInstance - Not sure why the core needs to know this. * @param numNodes - Not sure why the core needs to know this. * @param shardIds A comma separated list of shard ids for this core (or null). + * @return Response including the action result: + * - status: success, when the resource has been reloaded + * - status: error, when the resource has NOT been reloaded + * - errorMessage: message, if action status is "error" an error message node is included */ - private void setupNewDefaultCores(String names, int numShards, int replicationFactor, int nodeInstance, int numNodes, String shardIds) + private NamedList setupNewDefaultCores(String names, int numShards, int replicationFactor, int nodeInstance, int numNodes, String shardIds) { + + var wrapper = new Object() + { + NamedList response = new SimpleOrderedMap<>();; + }; + try { List coreNames = @@ -223,14 +258,21 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler throw new AlfrescoRuntimeException("Invalid '" + ALFRESCO_DEFAULTS + "' permitted values are " + STORE_REF_MAP.keySet()); } StoreRef storeRef = STORE_REF_MAP.get(coreName); - newCore(coreName, numShards, storeRef, DEFAULT_TEMPLATE, replicationFactor, nodeInstance, - numNodes, shardIds, null, new SolrQueryResponse()); + wrapper.response.addAll(newCore(coreName, numShards, storeRef, DEFAULT_TEMPLATE, replicationFactor, nodeInstance, + numNodes, shardIds, null)); }); } catch (Exception exception) { LOGGER.error("Failed to create default alfresco cores (workspace/archive stores)", exception); + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + wrapper.response.add(ACTION_ERROR_MESSAGE_LABEL, exception.getMessage()); + return wrapper.response; } + + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + return wrapper.response; + } /** @@ -280,108 +322,172 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler } } - private void initResourceBasedLogging(String resource) + /** + * Update memory loading from "log4j.properties" file for each Core + * + * Synchronous execution + * + * @param resource The name of the resource file to be reloaded + * @result Response including the action result: + * - status: success, when the resource has been reloaded + * - status: error, when the resource has NOT been reloaded + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList initResourceBasedLogging(String resource) { + + NamedList response = new SimpleOrderedMap<>(); + try { Class clazz = Class.forName("org.apache.log4j.PropertyConfigurator"); Method method = clazz.getMethod("configure", Properties.class); - InputStream is = openResource(coreContainer.getSolrHome(), resource); + InputStream is = openResource(coreContainer.getSolrHome() + "/../logs", resource); Properties p = new Properties(); p.load(is); method.invoke(null, p); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + } catch (ClassNotFoundException e) { - // Do nothing here + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "ClassNotFoundException: org.apache.log4j.PropertyConfigurator"); + return response; } catch (Exception e) { LOGGER.info("Failed to load " + resource, e); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, e.getMessage()); + return response; } - } + return response; + } + + @SuppressWarnings("unchecked") protected void handleCustomAction(SolrQueryRequest req, SolrQueryResponse rsp) { + SolrParams params = req.getParams(); String action = ofNullable(params.get(CoreAdminParams.ACTION)) .map(String::trim) .map(String::toUpperCase) .orElse(""); + String coreName = coreName(params); + LOGGER.info("Running action {} for core {} with params {}", action, coreName, params); + try { - switch (action) - { + switch (action) { + // Create a new Core in SOLR case "NEWCORE": case "NEWINDEX": - newCore(req, rsp); + rsp.add(ACTION_LABEL, newCore(req)); break; + // Reload an existing Core in SOLR case "UPDATECORE": case "UPDATEINDEX": - updateCore(req); + rsp.add(ACTION_LABEL, updateCore(req)); break; + // Update memory loading from "shared.properties" file for each Core case "UPDATESHARED": - updateShared(req); + rsp.add(ACTION_LABEL, updateShared(req)); break; + // Unload an existing Core from SOLR case "REMOVECORE": - removeCore(req); + rsp.add(ACTION_LABEL, removeCore(req)); break; + // Create a new Core in SOLR with default settings case "NEWDEFAULTINDEX": case "NEWDEFAULTCORE": - newDefaultCore(req, rsp); + rsp.add(ACTION_LABEL, newDefaultCore(req)); break; + // Enable check flag on a SOLR Core case "CHECK": - actionCHECK(params); + rsp.add(ACTION_LABEL, actionCHECK(coreName)); break; + // Get a report from a nodeId with the associated txId and the indexing status case "NODEREPORT": - actionNODEREPORTS(rsp, params); + rsp.add(REPORT, actionNODEREPORTS(params)); break; + // Get a report from an aclId with the count of documents associated to the ACL case "ACLREPORT": - actionACLREPORT(rsp, params); + rsp.add(REPORT, actionACLREPORT(params)); break; + // Get a report from a txId with detailed information related with the Transaction case "TXREPORT": - actionTXREPORT(rsp, params); + rsp.add(REPORT, actionTXREPORT(params)); break; + // Get a report from an aclTxId with detailed information related with nodes indexed + // for an ACL inside a Transaction case "ACLTXREPORT": - actionACLTXREPORT(rsp, params); + rsp.add(REPORT, actionACLTXREPORT(params)); break; + // Get a detailed report including storage and sizing for a Shards configured + // with Shard DB_ID_RANGE method. If SOLR is not using this configuration, + // "expand = -1" is returned case "RANGECHECK": - rangeCheck(rsp, params); + rsp.getValues().addAll(rangeCheck(params)); break; + // Expand the range for a Shard configured with DB_ID_RANGE having more than 75% + // space used. This configuration is not persisted in solrcore.properties case "EXPAND": - expand(rsp, params); + rsp.getValues().addAll(expand(params)); break; + // Get a detailed report for a core or for every core. This action accepts + // filtering based on commitTime, txid and acltxid case "REPORT": - actionREPORT(rsp, params); + rsp.add(REPORT, actionREPORT(params)); break; + // Add a nodeid, txid, acltxid or aclid to be purged on the next maintenance + // operation performed by MetadataTracker and AclTracker. + // Asynchronous. case "PURGE": - actionPURGE(params); + rsp.add(ACTION_LABEL, actionPURGE(params)); break; + // Add a nodeid, txid, acltxid, aclid or SOLR query to be reindexed on the + // next maintenance operation performed by MetadataTracker and AclTracker. + // Asynchronous. case "REINDEX": - actionREINDEX(params); + rsp.add(ACTION_LABEL, actionREINDEX(params)); break; + // Reindex every node marked as ERROR in a core or in every core. + // Asynchronous. case "RETRY": - actionRETRY(rsp, params); + rsp.add(ACTION_LABEL, actionRETRY(params)); break; + // Add a nodeid, txid, acltxid or aclid to be indexed on the next maintenance + // operation performed by MetadataTracker and AclTracker. + // Asynchronous. case "INDEX": - actionINDEX(params); + rsp.add(ACTION_LABEL, actionINDEX(params)); break; + // Find transactions and acls missing or duplicated in the cores and + // add them to be reindexed on the next maintenance operation + // performed by MetadataTracker and AclTracker. + // Asynchronous. case "FIX": - actionFIX(params); + rsp.add(ACTION_LABEL, actionFIX(params)); break; + // Get detailed report for a core or for every core including information + // related with handlers and trackers. case "SUMMARY": - actionSUMMARY(rsp, params); + rsp.add(SUMMARY, actionSUMMARY(params)); break; + // Update memory loading from "log4j.properties" file for each Core case "LOG4J": - initResourceBasedLogging( + rsp.add(ACTION_LABEL, initResourceBasedLogging( ofNullable(params.get("resource")) - .orElse("log4j-solr.properties")); + .orElse("log4j.properties"))); break; default: super.handleCustomAction(req, rsp); break; } + } catch (Exception ex) { @@ -390,18 +496,42 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler } } - private void newCore(SolrQueryRequest req, SolrQueryResponse rsp) + /** + * Create a new Core in SOLR + * + * Synchronous execution + * + * @param req Query Request including following parameters: + * - coreName, mandatory, the name of the core to be created + * - storeRef, mandatory, the storeRef for the SOLR Core (workspace://SpacesStore, archive://SpacesStore) + * - shardIds, optional, a String including a list of ShardIds separated with comma + * - numShards, optional, the number of Shards to be created + * - template, optional, the name of the SOLR template used to create the core (rerank, norerank) + * - replicationFactor, optional, number of Core replicas + * - nodeInstance, optional, number of the Node instance + * - numNodes, optional, number of Nodes + * + * @return NamedList including the action result: + * - status: success, when the core has been created + * - status: error, when the core has NOT been created + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList newCore(SolrQueryRequest req) { SolrParams params = req.getParams(); req.getContext(); + NamedList response = new SimpleOrderedMap<>(); + // If numCore > 1 we are creating a collection of cores for a sole node in a cluster int numShards = params.getInt("numShards", 1); String store = params.get("storeRef"); if (store == null || store.trim().length() == 0) { - return; + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + coreName(params) + " has NOT been created as storeRef param is required"); + return response; } StoreRef storeRef = new StoreRef(store); @@ -415,11 +545,33 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler String coreName = coreName(params); String shardIds = params.get("shardIds"); - newCore(coreName, numShards, storeRef, templateName, replicationFactor, nodeInstance, numNodes, shardIds, extractCustomProperties(params), rsp); + response = newCore(coreName, numShards, storeRef, templateName, replicationFactor, nodeInstance, numNodes, shardIds, extractCustomProperties(params)); + if (!Objects.equals(response.get(ACTION_STATUS_LABEL), ACTION_STATUS_ERROR)) + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + } + return response; } - private void newDefaultCore(SolrQueryRequest req, SolrQueryResponse response) + /** + * Creates new default cores using default values. + * + * Synchronous execution + * + * @param req Query Request including following parameters: + * - coreName, mandatory, the name of the core to be created + * - storeRef, optional, the storeRef for the SOLR Core (workspace://SpacesStore, archive://SpacesStore) + * - template, optional, the name of the SOLR template used to create the core (rerank, norerank) + * @return Response including the action result: + * - status: success, when the resource has been reloaded + * - status: error, when the resource has NOT been reloaded + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList newDefaultCore(SolrQueryRequest req) { + + NamedList response = new SimpleOrderedMap<>(); + SolrParams params = req.getParams(); String coreName = ofNullable(coreName(params)).orElse(ALFRESCO_CORE_NAME); String templateName = @@ -429,30 +581,37 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler Properties extraProperties = extractCustomProperties(params); - newDefaultCore( + response = newDefaultCore( coreName, ofNullable(params.get("storeRef")) .map(StoreRef::new) .orElse(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE), templateName, - extraProperties, - response); + extraProperties); + if (!Objects.equals(response.get(ACTION_STATUS_LABEL), ACTION_STATUS_ERROR)) + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + } + return response; } - private void newDefaultCore(String coreName, StoreRef storeRef, String templateName, Properties extraProperties, SolrQueryResponse rsp) + private NamedList newDefaultCore(String coreName, StoreRef storeRef, String templateName, Properties extraProperties) { - newCore(coreName, 1, storeRef, templateName, 1, 1, 1, null, extraProperties, rsp); + return newCore(coreName, 1, storeRef, templateName, 1, 1, 1, null, extraProperties); } - protected void newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp) + protected NamedList newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties) { + + NamedList response = new SimpleOrderedMap<>(); + try { // copy core from template File solrHome = new File(coreContainer.getSolrHome()); File templates = new File(solrHome, "templates"); File template = new File(templates, templateName); - + if(numShards > 1) { String collectionName = templateName + "--" + storeRef.getProtocol() + "-" + storeRef.getIdentifier() + "--shards--"+numShards + "-x-"+replicationFactor+"--node--"+nodeInstance+"-of-"+numNodes; @@ -465,9 +624,11 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler File baseDirectory = new File(solrHome, collectionName); - if(nodeInstance == -1) + if (nodeInstance == -1) { - return; + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + coreName + " has NOT been created as nodeInstance param is required"); + return response; } List shards; @@ -480,29 +641,41 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler ExplicitShardingPolicy policy = new ExplicitShardingPolicy(numShards, replicationFactor, numNodes); if(!policy.configurationIsValid()) { - return; + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + coreName + " has NOT been created as explicit Sharding policy is not valid"); + return response; } shards = policy.getShardIdsForNode(nodeInstance); } - for(Integer shard : shards) + List coresNotCreated = new ArrayList<>(); + for (Integer shard : shards) { coreName = coreBase + shard; File newCore = new File(baseDirectory, coreName); - String solrCoreName = coreName; - if (coreName == null) + + response = createAndRegisterNewCore(extraProperties, storeRef, template, coreName, + newCore, numShards, shard, templateName); + if (response.size() > 1) { - if(storeRef.equals(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)) - { - solrCoreName = "alfresco-" + shard; - } - else if(storeRef.equals(StoreRef.STORE_REF_ARCHIVE_SPACESSTORE)) - { - solrCoreName = "archive-" + shard; - } + coresNotCreated.add(coreName); } - createAndRegisterNewCore(rsp, extraProperties, storeRef, template, solrCoreName, newCore, numShards, shard, templateName); } + + response = new SimpleOrderedMap<>(); + if (coresNotCreated.size() > 0) + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, + "Following cores have not been created: " + coresNotCreated); + return response; + } + else + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + return response; + } + } else { @@ -511,11 +684,12 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler coreName = storeRef.getProtocol() + "-" + storeRef.getIdentifier(); } File newCore = new File(solrHome, coreName); - createAndRegisterNewCore(rsp, extraProperties, storeRef, template, coreName, newCore, 0, 0, templateName); + return createAndRegisterNewCore(extraProperties, storeRef, template, coreName, newCore, 0, 0, templateName); } } catch (IOException exception) { + LOGGER.error("I/O Failure detected while creating the new core " + "(name={}, numShard={}, storeRef={}, template={}, replication factor={}, node instance={}, num nodes={}, shard ids={})", coreName, @@ -527,6 +701,10 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler numNodes, shardIds, exception); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, + "Core " + coreName + " has NOT been created. Check the log to find out the reason."); + return response; } } @@ -549,14 +727,17 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .collect(Collectors.toList()); } - private void createAndRegisterNewCore(SolrQueryResponse rsp, Properties extraProperties, StoreRef storeRef, File template, String coreName, File newCore, int shardCount, int shardInstance, String templateName) throws IOException + private NamedList createAndRegisterNewCore(Properties extraProperties, StoreRef storeRef, File template, String coreName, File newCore, int shardCount, int shardInstance, String templateName) throws IOException { + + NamedList response = new SimpleOrderedMap<>(); + if (coreContainer.getLoadedCoreNames().contains(coreName)) { //Core alfresco exists - LOGGER.warn(coreName + " already exists, not creating again."); - rsp.add("core", coreName); - return; + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "core " + coreName + " already exists, not creating again."); + return response; } FileUtils.copyDirectory(template, newCore, false); @@ -601,7 +782,8 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler } SolrCore core = coreContainer.create(coreName, newCore.toPath(), new HashMap<>(), false); - rsp.add("core", core.getName()); + response.add("core", core.getName()); + return response; } boolean hasAlfrescoCore(Collection cores) @@ -611,10 +793,23 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .anyMatch(trackerRegistry::hasTrackersForCore); } - private void updateShared(SolrQueryRequest req) + /** + * Update memory loading from "shared.properties" file for each Core + * + * Synchronous execution + * + * @param req Query Request with no parameters + * @return Response including the action result: + * - status: success, when the properties has been reloaded + * - status: error, when the properties has NOT been reloaded + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList updateShared(SolrQueryRequest req) { SolrParams params = req.getParams(); + NamedList response = new SimpleOrderedMap<>(); + try { File config = new File(AlfrescoSolrDataModel.getResourceDirectory(), AlfrescoSolrDataModel.SHARED_PROPERTIES); @@ -623,65 +818,177 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler coreContainer.getCores().stream() .map(SolrCore::getName) .forEach(coreContainer::reload); + + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + } catch (IOException e) { LOGGER.error("Failed to update Shared properties ", e); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Shared properties couldn't be reloaded for some core. Check the log to find out the reason."); + return response; } + + return response; + } - private void updateCore(SolrQueryRequest req) + /** + * Reload an existing Core in SOLR + * + * Synchronous execution + * + * @param req Query Request including following parameters: + * - coreName, mandatory, the name of the core to be reloaded + * + * @return Response including the action result: + * - status: success, when the core has been reloaded + * - status: error, when the core has NOT been reloaded + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList updateCore(SolrQueryRequest req) { + + var wrapper = new Object() + { + NamedList response = new SimpleOrderedMap<>();; + }; + ofNullable(coreName(req.getParams())) .map(String::trim) .filter(coreName -> !coreName.isEmpty()) - .ifPresent(coreName -> { + .ifPresentOrElse(coreName -> { try (SolrCore core = coreContainer.getCore(coreName)) { if (core == null) { - return; + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + wrapper.response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + coreName + " has NOT been updated as it doesn't exist"); } + else + { - String configLocaltion = core.getResourceLoader().getConfigDir(); - File config = new File(configLocaltion, "solrcore.properties"); - updatePropertiesFile(req.getParams(), config, null); - - coreContainer.reload(coreName); + String configLocaltion = core.getResourceLoader().getConfigDir(); + File config = new File(configLocaltion, "solrcore.properties"); + updatePropertiesFile(req.getParams(), config, null); + + coreContainer.reload(coreName); + + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + + } + } + }, + () -> { + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + wrapper.response.add(ACTION_ERROR_MESSAGE_LABEL, "Core has NOT been updated as coreName param is required"); }); + + return wrapper.response; + } - private void removeCore(SolrQueryRequest req) + /** + * Unload an existing Core from SOLR + * + * Synchronous execution + * + * @param req Query Request including following parameters: + * - coreName, mandatory, the name of the core to be unloaded + * - storeRef, mandatory, the storeRef for the SOLR Core (workspace://SpacesStore, archive://SpacesStore) + * + * @return Response including the action result: + * - status: success, when the core has been unloaded + * - status: error, when the core has NOT been unloaded + * - errorMessage: message, if action status is "error" an error message node is included + */ + private NamedList removeCore(SolrQueryRequest req) { String store = ""; SolrParams params = req.getParams(); + NamedList response = new SimpleOrderedMap<>(); + if (params.get("storeRef") != null) { store = params.get("storeRef"); } - if ((store == null) || (store.length() == 0)) { return; } + if ((store == null) || (store.length() == 0)) + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + params.get("coreName") + " has NOT been removed as storeRef param is required"); + return response; + } StoreRef storeRef = new StoreRef(store); String coreName = ofNullable(coreName(req.getParams())).orElse(storeRef.getProtocol() + "-" + storeRef.getIdentifier()); + SolrCore core = coreContainer.getCore(coreName); + + if (core == null) + { + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, "Core " + params.get("coreName") + " has NOT been removed as it doesn't exist"); + return response; + } + + // Close the references to the core to unload before actually unloading it, + // otherwise this operation gets into and endless loop + while (core.getOpenCount() > 1) + { + core.close(); + } + + // remove core coreContainer.unload(coreName, true, true, true); + + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + return response; + } - private void actionCHECK(SolrParams params) + /** + * Enable check flag on a SOLR Core or on every SOLR Core + * + * Synchronous execution + * + * @param req Query Request without parameters + * - coreName, optional, the name of the core to be checked + * + * @return Response including the action result: + * - status: success, when the core has been created + */ + private NamedList actionCHECK(String cname) { - String cname = coreName(params); coreNames().stream() .filter(coreName -> cname == null || coreName.equals(cname)) .map(trackerRegistry::getTrackersForCore) .flatMap(Collection::stream) .map(Tracker::getTrackerState) .forEach(state -> state.setCheck(true)); + + NamedList response = new SimpleOrderedMap<>(); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SUCCESS); + return response; } - private void actionNODEREPORTS(SolrQueryResponse rsp, SolrParams params) throws JSONException + /** + * Get a report from a nodeId with the associated txId and the indexing status + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - nodeId, mandatory: the number of the node to build the report + * - core, The name of the SOLR Core or "null" to get the report for every core + * @return Response including the action result: + * - report: An Object with the report details + * + * @throws JSONException + */ + private NamedList actionNODEREPORTS(SolrParams params) throws JSONException { Long dbid = ofNullable(params.get(ARG_NODEID)) @@ -689,7 +996,6 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .orElseThrow(() -> new AlfrescoRuntimeException("No dbid parameter set.")); NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); String requestedCoreName = coreName(params); @@ -702,9 +1008,23 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler report.add( coreNameAndPublisher.getFirst(), buildNodeReport(coreNameAndPublisher.getSecond(), dbid))); + return report; } - private void actionACLREPORT(SolrQueryResponse rsp, SolrParams params) throws JSONException + /** + * Get a report from an aclId with the count of documents associated to the ACL + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - aclId, mandatory, the number of the ACL to build the report + * - core, The name of the SOLR Core or "null" to get the report for every core + * @return Response including the action result: + * - report: an Object with the details of the report + * + * @throws JSONException + */ + private NamedList actionACLREPORT(SolrParams params) throws JSONException { Long aclid = ofNullable(params.get(ARG_ACLID)) @@ -712,7 +1032,6 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .orElseThrow(() -> new AlfrescoRuntimeException("No " + ARG_ACLID + " parameter set.")); NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); String requestedCoreName = coreName(params); @@ -729,16 +1048,31 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { addAlertMessage(report); } + + return report; + } - private void actionTXREPORT(SolrQueryResponse rsp, SolrParams params) throws JSONException + /** + * Get a report from a txId with detailed information related with the Transaction + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - txId, mandatory, the number of the Transaction to build the report + * - core, The name of the SOLR Core or "null" to get the report for every core + * @return Response including the action result: + * - report: an Object with the details of the report + * + * @throws JSONException + */ + private NamedList actionTXREPORT(SolrParams params) throws JSONException { String coreName = ofNullable(coreName(params)) .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); if (isMasterOrStandalone(coreName)) { @@ -754,9 +1088,23 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { addAlertMessage(report); } + return report; } - private void actionACLTXREPORT(SolrQueryResponse rsp, SolrParams params) throws JSONException + /** + * Get a report from an aclTxId with detailed information related with nodes indexed + * for an ACL inside a Transaction + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - acltxid, mandatory, the number of the ACL TX Id to build the report + * @return Response including the action result: + * - report: an Object with the details of the report + * + * @throws JSONException + */ + private NamedList actionACLTXREPORT(SolrParams params) throws JSONException { Long acltxid = ofNullable(params.get(ARG_ACLTXID)) @@ -764,7 +1112,6 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .orElseThrow(() -> new AlfrescoRuntimeException("No " + ARG_ACLTXID + " parameter set.")); NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); String requestedCoreName = coreName(params); @@ -786,14 +1133,30 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { addAlertMessage(report); } + return report; } - private void rangeCheck(SolrQueryResponse rsp, SolrParams params) throws IOException + /** + * Get a detailed report including storage and sizing for a Shards configured with Shard DB_ID_RANGE method. + * If SOLR is not using this configuration,"expand = -1" is returned + * + * Synchronous execution + * + * @param params + * - core, The name of the SOLR Core + * @return Response including the action result: + * - report: An Object with the report details + * + * @throws IOException + */ + private NamedList rangeCheck(SolrParams params) throws IOException { String coreName = ofNullable(coreName(params)) .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); + NamedList response = new SimpleOrderedMap<>(); + if (isMasterOrStandalone(coreName)) { InformationServer informationServer = informationServers.get(coreName); @@ -806,9 +1169,9 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler if(!dbidRangeRouter.getInitialized()) { - rsp.add("expand", 0); - rsp.add("exception", "DBIDRangeRouter not initialized yet."); - return; + response.add("expand", 0); + response.add("exception", "DBIDRangeRouter not initialized yet."); + return response; } long startRange = dbidRangeRouter.getStartRange(); @@ -861,35 +1224,51 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler } } - rsp.add("start", startRange); - rsp.add("end", endRange); - rsp.add("nodeCount", nodeCount); - rsp.add("minDbid", minNodeId); - rsp.add("maxDbid", maxNodeId); - rsp.add("density", Math.abs(density)); - rsp.add("expand", bestGuess); - rsp.add("expanded", dbidRangeRouter.getExpanded()); + response.add("start", startRange); + response.add("end", endRange); + response.add("nodeCount", nodeCount); + response.add("minDbid", minNodeId); + response.add("maxDbid", maxNodeId); + response.add("density", Math.abs(density)); + response.add("expand", bestGuess); + response.add("expanded", dbidRangeRouter.getExpanded()); } else { - rsp.add("expand", -1); - rsp.add("exception", "ERROR: Wrong document router type:"+docRouter.getClass().getSimpleName()); + response.add("expand", -1); + response.add("exception", "ERROR: Wrong document router type:"+docRouter.getClass().getSimpleName()); } } else { - NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); - addAlertMessage(report); + addAlertMessage(response); } + return response; } - private synchronized void expand(SolrQueryResponse rsp, SolrParams params) throws IOException + /** + * Expand the range for a Shard configured with DB_ID_RANGE having more than 75% + * space used. This configuration is not persisted in solrcore.properties + * + * Synchronous execution + * + * @param params + * - core, mandatory: The name of the SOLR Core + * - add, mandatory: the number of nodes to be added to the End Range limit + * @return Response including the action result: + * - expand: The number of the new End Range limit or -1 if the action failed + * - exception: Error message if expand is -1 + * + * @throws IOException + */ + private synchronized NamedList expand(SolrParams params) throws IOException { String coreName = ofNullable(coreName(params)) .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); + NamedList response = new SimpleOrderedMap<>(); + if (isMasterOrStandalone(coreName)) { InformationServer informationServer = informationServers.get(coreName); @@ -902,16 +1281,16 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler if(!dbidRangeRouter.getInitialized()) { - rsp.add("expand", -1); - rsp.add("exception", "DBIDRangeRouter not initialized yet."); - return; + response.add("expand", -1); + response.add("exception", "DBIDRangeRouter not initialized yet."); + return response; } if(dbidRangeRouter.getExpanded()) { - rsp.add("expand", -1); - rsp.add("exception", "dbid range has already been expanded."); - return; + response.add("expand", -1); + response.add("exception", "dbid range has already been expanded."); + return response; } long currentEndRange = dbidRangeRouter.getEndRange(); @@ -923,9 +1302,9 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler if(maxNodeId > safe) { - rsp.add("expand", -1); - rsp.add("exception", "Expansion cannot occur if max DBID in the index is more then 75% of range."); - return; + response.add("expand", -1); + response.add("exception", "Expansion cannot occur if max DBID in the index is more then 75% of range."); + return response; } long newEndRange = expansion+dbidRangeRouter.getEndRange(); @@ -936,33 +1315,53 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler dbidRangeRouter.setEndRange(newEndRange); dbidRangeRouter.setExpanded(true); assert newEndRange == dbidRangeRouter.getEndRange(); - rsp.add("expand", dbidRangeRouter.getEndRange()); + response.add("expand", dbidRangeRouter.getEndRange()); } catch(Throwable t) { - rsp.add("expand", -1); - rsp.add("exception", t.getMessage()); + response.add("expand", -1); + response.add("exception", t.getMessage()); LOGGER.error("exception expanding", t); + return response; } } else { - rsp.add("expand", -1); - rsp.add("exception", "Wrong document router type:" + docRouter.getClass().getSimpleName()); + response.add("expand", -1); + response.add("exception", "Wrong document router type:" + docRouter.getClass().getSimpleName()); + return response; } } else { - NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); - addAlertMessage(report); + addAlertMessage(response); } + return response; } - private void actionREPORT(SolrQueryResponse rsp, SolrParams params) throws JSONException + /** + * Get a detailed report for a core or for every core. This action accepts + * filtering based on commitTime, txid and acltxid + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - core, mandatory: The name of the SOLR Core + * - fromTime, optional: from transaction commit time to filter report results + * - toTime, optional: to transaction commit time to filter report results + * - fromTx, optional: from transaction Id to filter report results + * - toTx, optional: to transaction Id time to filter report results + * - fromAclTx, optional: from ACL transaction Id to filter report results + * - toCalTx, optional: to ACL transaction Id to filter report results + * + * @param Response including the action result: + * - report.core: multiple Objects with the details of the report ("core" is the name of the Core) + * + * @throws JSONException + */ + private NamedList actionREPORT(SolrParams params) throws JSONException { NamedList report = new SimpleOrderedMap<>(); - rsp.add(REPORT, report); Long fromTime = getSafeLong(params, "fromTime"); Long toTime = getSafeLong(params, "toTime"); @@ -995,9 +1394,25 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { addAlertMessage(report); } + return report; } - private void actionPURGE(SolrParams params) + /** + * Add a nodeid, txid, acltxid or aclid to be purged on the next maintenance + * operation performed by MetadataTracker and AclTracker. + * + * Asynchronous execution + * + * @param params Query Request with following parameters: + * - core, mandatory: The name of the SOLR Core + * - txid, optional, the number of the Transaction to purge + * - acltxid, optional, the number of the ACL Transaction to purge + * - nodeId, optional, the number of the node to purge + * - aclid, optional, the number of the ACL to purge + * @return Response including the action result: + * - status: scheduled, as it will be executed by Trackers on the next maintenance operation + */ + private NamedList actionPURGE(SolrParams params) { Consumer purgeOnSpecificCore = coreName -> { final MetadataTracker metadataTracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class); @@ -1015,9 +1430,29 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .filter(this::isMasterOrStandalone) .forEach(purgeOnSpecificCore); + + NamedList response = new SimpleOrderedMap<>(); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SCHEDULED); + return response; } - private void actionREINDEX(SolrParams params) + /** + * Add a nodeid, txid, acltxid, aclid or SOLR query to be reindexed on the + * next maintenance operation performed by MetadataTracker and AclTracker. + * + * Asynchronous execution + * + * @param params Query Request with following parameters: + * - core, mandatory: The name of the SOLR Core + * - txid, optional, the number of the Transaction to reindex + * - acltxid, optional, the number of the ACL Transaction to reindex + * - nodeId, optional, the number of the node to reindex + * - aclid, optional, the number of the ACL to reindex + * - query, optional, SOLR Query to reindex results + * @return Response including the action result: + * - action.status: scheduled, as it will be executed by Trackers on the next maintenance operation + */ + private NamedList actionREINDEX(SolrParams params) { Consumer reindexOnSpecificCore = coreName -> { final MetadataTracker metadataTracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class); @@ -1037,10 +1472,27 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .filter(this::isMasterOrStandalone) .forEach(reindexOnSpecificCore); + + NamedList response = new SimpleOrderedMap<>(); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SCHEDULED); + return response; } - private void actionRETRY(SolrQueryResponse rsp, SolrParams params) + /** + * Reindex every node marked as ERROR in a core or in every core. + * + * Asynchronous execution + * + * @param params Query Request with following parameters: + * - core, optional: The name of the SOLR Core + * @param rsp Query Response including the action result: + * - action.status: scheduled, as it will be executed by Trackers on the next maintenance operation + * - core: list of Document Ids with error that are going to reindexed + */ + private NamedList actionRETRY(SolrParams params) { + NamedList response = new SimpleOrderedMap<>(); + final Consumer retryOnSpecificCore = coreName -> { MetadataTracker tracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class); InformationServer srv = informationServers.get(coreName); @@ -1051,13 +1503,21 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { tracker.addNodeToReindex(nodeid); } - rsp.add(coreName, srv.getErrorDocIds()); + response.add(coreName, srv.getErrorDocIds()); } catch (Exception exception) { LOGGER.error("I/O Exception while adding Node to reindex.", exception); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); + response.add(ACTION_ERROR_MESSAGE_LABEL, exception.getMessage()); + } }; + + if (Objects.equals(response.get(ACTION_STATUS_LABEL), ACTION_STATUS_ERROR)) + { + return response; + } String requestedCoreName = coreName(params); @@ -1065,9 +1525,27 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .filter(this::isMasterOrStandalone) .forEach(retryOnSpecificCore); + + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SCHEDULED); + return response; } - private void actionINDEX(SolrParams params) + /** + * Add a nodeid, txid, acltxid or aclid to be indexed on the next maintenance + * operation performed by MetadataTracker and AclTracker. + * + * Asynchronous execution + * + * @param params Query Request with following parameters: + * - core, optional: The name of the SOLR Core + * - txid, optional, the number of the Transaction to index + * - acltxid, optional, the number of the ACL Transaction to index + * - nodeId, optional, the number of the node to index + * - aclid, optional, the number of the ACL to index + * @return Response including the action result: + * - action.status: scheduled, as it will be executed by Trackers on the next maintenance operation + */ + private NamedList actionINDEX(SolrParams params) { Consumer indexOnSpecificCore = coreName -> { final MetadataTracker metadataTracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class); @@ -1085,19 +1563,47 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .filter(this::isMasterOrStandalone) .forEach(indexOnSpecificCore); + + NamedList response = new SimpleOrderedMap<>(); + response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SCHEDULED); + return response; } - private void actionFIX(SolrParams params) throws JSONException + /** + * Find transactions and acls missing or duplicated in the cores and + * add them to be reindexed on the next maintenance operation + * performed by MetadataTracker and AclTracker. + * + * Asynchronous execution + * + * @param params + * - core, optional: The name of the SOLR Core + * @return Response including the action result: + * - action.status: scheduled, as it will be executed by Trackers on the next maintenance operation + * - txToReindex: list of Transaction Ids that are going to be reindexed + * - aclChangeSetToReindex: list of ACL Change Set Ids that are going to be reindexed + * @throws JSONException + */ + private NamedList actionFIX(SolrParams params) throws JSONException { String requestedCoreName = coreName(params); + var wrapper = new Object() + { + NamedList response = new SimpleOrderedMap<>();; + }; coreNames().stream() .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .filter(this::isMasterOrStandalone) - .forEach(this::fixOnSpecificCore); + .forEach(coreName -> { + wrapper.response.add(coreName, fixOnSpecificCore(coreName)); + }); + + wrapper.response.add(ACTION_STATUS_LABEL, ACTION_STATUS_SCHEDULED); + return wrapper.response; } - private void fixOnSpecificCore(String coreName) + private NamedList fixOnSpecificCore(String coreName) { try { @@ -1109,8 +1615,11 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler toReindex.or(indexHealthReport.getMissingTxFromIndex()); long current = -1; // Goes through problems in the index - while ((current = toReindex.nextSetBit(current + 1)) != -1) { + Set txToReindex = new TreeSet<>(); + while ((current = toReindex.nextSetBit(current + 1)) != -1) + { metadataTracker.addTransactionToReindex(current); + txToReindex.add(current); } // Gets the Acl health and fixes any problems @@ -1121,9 +1630,18 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler toReindex.or(indexHealthReport.getMissingAclTxFromIndex()); current = -1; // Goes through the problems in the index - while ((current = toReindex.nextSetBit(current + 1)) != -1) { + Set aclChangeSetToReindex = new TreeSet<>(); + while ((current = toReindex.nextSetBit(current + 1)) != -1) + { aclTracker.addAclChangeSetToReindex(current); + aclChangeSetToReindex.add(current); } + + NamedList response = new SimpleOrderedMap<>(); + response.add(ACTION_TX_TO_REINDEX, txToReindex); + response.add(ACTION_ACL_CHANGE_SET_TO_REINDEX, aclChangeSetToReindex); + return response; + } catch(Exception exception) { @@ -1131,16 +1649,31 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler } } - void actionSUMMARY(SolrQueryResponse rsp, SolrParams params) + /** + * Get detailed report for a core or for every core including information + * related with handlers and trackers. + * + * Synchronous execution + * + * @param params Query Request with following parameters: + * - core, optional: The name of the SOLR Core + * - detail, optional, when true adds details to the report + * - hist, optional, when true adds historic details to the report + * - values, optional, when true adds values detail to the report + * - reset, optional, when true stats are reset + * @return report (Key, Value) list with the results of the report + */ + private NamedList actionSUMMARY(SolrParams params) { NamedList report = new SimpleOrderedMap<>(); - rsp.add("Summary", report); String requestedCoreName = coreName(params); coreNames().stream() .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) .forEach(coreName -> coreSummary(params, report, coreName)); + + return report; } private void coreSummary(SolrParams params, NamedList report, String coreName) @@ -1291,4 +1824,4 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler return contentStore; } -} \ No newline at end of file +} diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java index 7851920cd..3092c7d1b 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java @@ -135,8 +135,13 @@ public class AclTracker extends AbstractTracker indexAcl(readers, false); } this.infoSrv.indexAclTransaction(changeSet, false); + log.info("INDEX ACTION - AclChangeSetId {} has been indexed", aclChangeSetId); requiresCommit = true; } + else + { + log.info("INDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", aclChangeSetId); + } } checkShutdown(); } @@ -160,6 +165,7 @@ public class AclTracker extends AbstractTracker //AclReaders r = readers.get(0); //System.out.println("############## READERS ID:"+r.getId()+":"+r.getReaders()); indexAcl(readers, false); + log.info("INDEX ACTION - AclId {} has been indexed", aclId); } checkShutdown(); } @@ -187,8 +193,13 @@ public class AclTracker extends AbstractTracker } this.infoSrv.indexAclTransaction(changeSet, true); + log.info("REINDEX ACTION - AclChangeSetId {} has been reindexed", aclChangeSetId); requiresCommit = true; } + else + { + log.info("REINDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", aclChangeSetId); + } } checkShutdown(); } @@ -212,6 +223,7 @@ public class AclTracker extends AbstractTracker Acl acl = new Acl(0, aclId); List readers = client.getAclReaders(Collections.singletonList(acl)); indexAcl(readers, true); + log.info("REINDEX ACTION - aclId {} has been reindexed", aclId); requiresCommit = true; } checkShutdown(); @@ -231,6 +243,7 @@ public class AclTracker extends AbstractTracker if (aclChangeSetId != null) { this.infoSrv.deleteByAclChangeSetId(aclChangeSetId); + log.info("PURGE ACTION - Purged aclChangeSetId {}", aclChangeSetId); } checkShutdown(); } @@ -245,6 +258,7 @@ public class AclTracker extends AbstractTracker if (aclId != null) { this.infoSrv.deleteByAclId(aclId); + log.info("PURGE ACTION - Purged aclId {}", aclId); } checkShutdown(); } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 3a7773dd9..dd8c92bfe 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -359,10 +359,15 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker // Index the transaction doc after the node - if this is not found then a reindex will be done. this.infoSrv.indexTransaction(info, false); + log.info("INDEX ACTION - Transaction {} has been indexed", transactionId); requiresCommit = true; trackerStats.addTxDocs(nodes.size()); } + else + { + log.info("INDEX ACTION - Transaction {} was not found in database, it has NOT been reindexed", transactionId); + } } if (docCount > batchCount) @@ -402,6 +407,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker node.setTxnId(Long.MAX_VALUE); this.infoSrv.indexNode(node, false); + log.info("INDEX ACTION - Node {} has been reindexed", node.getId()); requiresCommit = true; } checkShutdown(); @@ -452,6 +458,11 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker // Index the transaction doc after the node - if this is not found then a reindex will be done. this.infoSrv.indexTransaction(info, true); + log.info("REINDEX ACTION - Transaction {} has been reindexed", transactionId); + } + else + { + log.info("REINDEX ACTION - Transaction {} was not found in database, it has NOT been reindexed", transactionId); } } @@ -494,6 +505,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker node.setTxnId(Long.MAX_VALUE); this.infoSrv.indexNode(node, true); + log.info("REINDEX ACTION - Node {} has been reindexed", node.getId()); requiresCommit = true; } checkShutdown(); @@ -515,6 +527,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker if (query != null) { this.infoSrv.reindexNodeByQuery(query); + log.info("REINDEX ACTION - Nodes from query {} have been reindexed", query); requiresCommit = true; } checkShutdown(); @@ -539,6 +552,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker // make sure it is cleaned out so we do not miss deletes this.infoSrv.deleteByTransactionId(transactionId); requiresCommit = true; + log.info("PURGE ACTION - Purged transactionId {}", transactionId); } checkShutdown(); } @@ -559,6 +573,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker { // make sure it is cleaned out so we do not miss deletes this.infoSrv.deleteByNodeId(nodeId); + log.info("PURGE ACTION - Purged nodeId {}", nodeId); } checkShutdown(); } diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java index a9275c2a6..c7f97e07f 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java @@ -368,7 +368,7 @@ public class AlfrescoCoreAdminHandlerIT invalidNames.forEach(spy::setupNewDefaultCores); - verify(spy, never()).newCore(any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(), any()); + verify(spy, never()).newCore(any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any()); reset(spy); @@ -376,16 +376,17 @@ public class AlfrescoCoreAdminHandlerIT String commaSeparatedNames = String.join(",", invalidNames); spy.setupNewDefaultCores(commaSeparatedNames); - verify(spy, never()).newCore(any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(), any()); + verify(spy, never()).newCore(any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any()); } @Test public void coreNamesAreTrimmed_oneCoreNameAtTime() { AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() { @Override - protected void newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp) + protected NamedList newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties) { // Do nothing here otherwise we cannot spy it + return null; } }); @@ -399,18 +400,19 @@ public class AlfrescoCoreAdminHandlerIT coreNames.forEach(spy::setupNewDefaultCores); - verify(spy).newCore(eq(ARCHIVE_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ARCHIVE_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); - verify(spy).newCore(eq(ALFRESCO_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ALFRESCO_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); - verify(spy).newCore(eq(VERSION_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(VERSION_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); + verify(spy).newCore(eq(ARCHIVE_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ARCHIVE_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); + verify(spy).newCore(eq(ALFRESCO_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ALFRESCO_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); + verify(spy).newCore(eq(VERSION_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(VERSION_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); } @Test public void validAndInvalidCoreNames() { AlfrescoCoreAdminHandler spy = spy(new AlfrescoCoreAdminHandler() { @Override - protected void newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties, SolrQueryResponse rsp) + protected NamedList newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties) { // Do nothing here otherwise we cannot spy it + return null; } }); @@ -426,8 +428,8 @@ public class AlfrescoCoreAdminHandlerIT String commaSeparatedNames = String.join(",", coreNames); spy.setupNewDefaultCores(commaSeparatedNames); - verify(spy).newCore(eq(ARCHIVE_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ARCHIVE_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); - verify(spy).newCore(eq(ALFRESCO_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ALFRESCO_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); - verify(spy).newCore(eq(VERSION_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(VERSION_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null), any()); + verify(spy).newCore(eq(ARCHIVE_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ARCHIVE_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); + verify(spy).newCore(eq(ALFRESCO_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(ALFRESCO_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); + verify(spy).newCore(eq(VERSION_CORE_NAME), eq(1), eq(STORE_REF_MAP.get(VERSION_CORE_NAME)), anyString(), eq(1), eq(1), eq(1), eq(null), eq(null)); } } \ No newline at end of file From e2f29c7ab6b780474bc5935da183eddea585b98c Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 11 Feb 2020 15:19:05 +0000 Subject: [PATCH 19/94] SEARCH-1681 review changes to sharding test --- .../searchServices/search/ShardInfoTest.java | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index f46a9c1f7..aee6962a3 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -21,8 +21,11 @@ import static org.testng.Assert.assertTrue; import java.util.Arrays; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.collect.Sets; import org.alfresco.rest.search.RestInstanceModel; import org.alfresco.rest.search.RestShardInfoModel; @@ -127,6 +130,11 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest restClient.authenticateUser(dataUser.createRandomTestUser()).withShardInfoAPI().getInfo(); restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR); } + /** + * This is a test to check that sharding is correctly working on bamboo and locally. + * Include test group 'sharding' on bamboo to enable this test to run + * @throws JsonProcessingException + */ @Test(groups = { TestGroup.ACS_60n, TestGroup.SHARDING }) public void getShardInfoWith2OrMoreShards() throws JsonProcessingException @@ -135,32 +143,32 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest restClient.assertStatusCodeIs(HttpStatus.OK); info.assertThat().entriesListIsNotEmpty(); - // Checks based on 2 default cores: alfresco and archive assertEquals(info.getPagination().getTotalItems().intValue(), 2); - List stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore"); + Set stores = Sets.newHashSet("workspace://SpacesStore", "archive://SpacesStore"); List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); List entries = info.getEntries(); - // We could check entries.size() matches pagination count above + + Set actualStores = entries.stream().map(shardInfoModel -> shardInfoModel.getModel().getStores()).collect(Collectors.toSet()); + assertEquals(actualStores, stores); + for (RestShardInfoModel shardInfoModel : entries) { RestShardInfoModel model = shardInfoModel.getModel(); assertEquals(model.getTemplate(), "rerank"); assertEquals(model.getMode(), "MASTER"); assertTrue(model.getHasContent()); - assertTrue(stores.contains(model.getStores())); assertTrue(model.getNumberOfShards()>=2); - // Sharding Type related checks (an example) List shardingMethods = Arrays.asList("DB_ID", "DB_ID_RANGE", "EXPLICIT_ID", "ACL_ID", "MOD_ACL_ID", "DATE", "PROPERTY"); String shardingMethod = model.getShardMethod(); assertTrue(shardingMethods.contains(shardingMethod), "Unexpected Sharding Method Found: " + shardingMethod); - // Shard Instance related checks: You could iterate through all the instances in a loop + List shards = model.getShards(); - assertNotNull(shards.contains(shards), "Unexpected number of shards found:" + shards); + assertNotNull(shards, "Unexpected number of shards found:" + shards); RestShardModel shard = shards.iterator().next(); assertNotNull(shard); List instances = shard.getInstances(); - assertNotNull(instances.contains(instances), "Unexpected number of instances found:" + instances); + assertNotNull(instances, "Unexpected number of instances found:" + instances); RestInstanceModel instance = instances.iterator().next(); assertNotNull(instance); assertTrue(baseUrls.contains(instance.getBaseUrl())); @@ -171,15 +179,28 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest String shardParams = instance.getShardParams(); switch (shardingMethod) { - case "DB_ID_RANGE": - assertTrue(shardParams.contains("shard.key=")); + case "MOD_ACL_ID": + assertTrue(shardingMethod == "MOD_ACL_ID", "Sharding Method is not MOD_ACL_ID"); + break; + case "ACL_ID": + assertTrue(shardingMethod == "ACL_ID", "Sharding Method is not ACL_ID"); + break; + case "DB_ID": + assertTrue(shardingMethod == "DB_ID", "Sharding Method is not DB_ID"); + break; + case "DB_IN_RANGE": + assertTrue(shardingMethod == "DB_ID_RANGE", "Sharding Method is not DB_ID_RANGE"); + break; + case "DATE": + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for DATE"); + assertTrue(shardParams.contains("shard.grouping="), "Unexpected shard grouping defined for DATE"); + break; case "PROPERTY": - assertTrue(shardParams.contains("shard.key=")); + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for PROPERTY"); + break; case "EXPLICIT_ID": - assertTrue(shardParams.contains("shard.key=")); - case "DATE": - assertTrue(shardParams.contains("shard.key=")); - break; + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for EXPLICIT_ID"); + break; default: throw new AssertionError("Not as expected: " + shardParams.toString()); } From 38052259edc75d3841960e916a62ad74fd18ad8e Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 11 Feb 2020 15:27:36 +0000 Subject: [PATCH 20/94] Merge branch 'feature/SEARCH-2014_SolrAdminAPI_14x' into 'release/V1.4.x' Fixing Integration Tests. See merge request search_discovery/insightengine!370 (cherry picked from commit 7a96075fb2c600dd94909d8a3d8def4de8ec500e) 9b4e3d98 Fixing Integration Tests. --- .../java/org/alfresco/solr/AlfrescoCoreAdminHandler.java | 7 +++---- .../org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java | 5 +++-- .../test/java/org/alfresco/solr/AlfrescoSolrUtils.java | 8 +++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java index b578bea26..9f0c64d97 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java @@ -654,15 +654,14 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler coreName = coreBase + shard; File newCore = new File(baseDirectory, coreName); - response = createAndRegisterNewCore(extraProperties, storeRef, template, coreName, - newCore, numShards, shard, templateName); - if (response.size() > 1) + response.addAll(createAndRegisterNewCore(extraProperties, storeRef, template, coreName, + newCore, numShards, shard, templateName)); + if (Objects.equals(response.get(ACTION_STATUS_LABEL), ACTION_STATUS_ERROR)) { coresNotCreated.add(coreName); } } - response = new SimpleOrderedMap<>(); if (coresNotCreated.size() > 0) { response.add(ACTION_STATUS_LABEL, ACTION_STATUS_ERROR); diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java index c7f97e07f..6703bdde5 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java @@ -61,6 +61,7 @@ import org.apache.solr.common.params.CoreAdminParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.SolrCore; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; @@ -386,7 +387,7 @@ public class AlfrescoCoreAdminHandlerIT protected NamedList newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties) { // Do nothing here otherwise we cannot spy it - return null; + return new SimpleOrderedMap<>(); } }); @@ -412,7 +413,7 @@ public class AlfrescoCoreAdminHandlerIT protected NamedList newCore(String coreName, int numShards, StoreRef storeRef, String templateName, int replicationFactor, int nodeInstance, int numNodes, String shardIds, Properties extraProperties) { // Do nothing here otherwise we cannot spy it - return null; + return new SimpleOrderedMap<>(); } }); diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java index 5d9c0d27e..d8c65469b 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java @@ -881,14 +881,16 @@ public class AlfrescoSolrUtils TimeUnit.SECONDS.sleep(1); if(shards > 1 ) { - NamedList vals = response.getValues(); - List coreNames = vals.getAll("core"); + NamedList action = (NamedList) response.getValues().get("action"); + List coreNames = action.getAll("core"); assertEquals(shards,coreNames.size()); testingCore = getCore(coreContainer, coreNames.get(0)); } else { - assertEquals(coreName, response.getValues().get("core")); + + NamedList action = (NamedList) response.getValues().get("action"); + assertEquals(coreName, action.get("core")); //Get a reference to the new core testingCore = getCore(coreContainer, coreName); } From e3d74bb80841025e635c8c4ce902d414dafa7086 Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 11 Feb 2020 15:55:06 +0000 Subject: [PATCH 21/94] SEARCH-1681 review changes with pagination message --- .../searchServices/search/ShardInfoTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index aee6962a3..1cbbee75c 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -142,8 +142,14 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI().getInfo(); restClient.assertStatusCodeIs(HttpStatus.OK); info.assertThat().entriesListIsNotEmpty(); - - assertEquals(info.getPagination().getTotalItems().intValue(), 2); + + if(info.getPagination().getTotalItems().intValue() == 2){ + assertEquals(info.getPagination().getTotalItems().intValue(), 2); + } + else{ + System.out.println("Pagination is: " + info.getPagination().getTotalItems().intValue() + " not expected value of 2"); + } + Set stores = Sets.newHashSet("workspace://SpacesStore", "archive://SpacesStore"); List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); List entries = info.getEntries(); From 1e663d769f0e3126cec068b0d1be4911f0437ad5 Mon Sep 17 00:00:00 2001 From: mbhave Date: Tue, 11 Feb 2020 15:54:59 +0000 Subject: [PATCH 22/94] Search-2096: Tests added for Search-2096 (cherry picked from commit f8ed1490112c0cd5b0836225f5151209e2886516) --- .../search/SearchPermissionsTest.java | 77 ++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java index 96417269f..62dc9ba69 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java @@ -21,12 +21,16 @@ package org.alfresco.test.search.functional.searchServices.search; import javax.json.Json; import javax.json.JsonObject; +import org.alfresco.dataprep.SiteService.Visibility; +import org.alfresco.rest.requests.Site; import org.alfresco.rest.search.SearchResponse; import org.alfresco.test.search.functional.AbstractE2EFunctionalTest; import org.alfresco.utility.constants.UserRole; +import org.alfresco.utility.data.RandomData; import org.alfresco.utility.model.FileModel; import org.alfresco.utility.model.FileType; import org.alfresco.utility.model.FolderModel; +import org.alfresco.utility.model.SiteModel; import org.alfresco.utility.model.UserModel; import org.testng.Assert; import org.testng.annotations.BeforeClass; @@ -53,6 +57,7 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest * |------ permFile1 * |-- permChild2 * |------ permFile2 + * |-- permChild3 (Later: In test 2) */ parentFolder = new FolderModel("permGrandParent"); @@ -105,8 +110,8 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest waitForContentIndexing(file2.getContent(), true); } - - @Test + + @Test(priority = 1) public void searchResultsRespectInheritedPermissions() { // Search as testUser: expect all: 5 results: When user is a Site Manager @@ -129,4 +134,72 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest resultCount = response.getPagination().getCount(); Assert.assertTrue(resultCount == 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); } + + @Test(priority = 2) + public void searchResultsRespectInheritedPermissionsDisabled() throws Exception + { + // Create folder + FolderModel folder3 = dataContent.usingUser(testUser).usingSite(testSite).usingResource(parentFolder).createFolderCmisApi("permChild32"); + + // Turn off inherited permissions for folder3 + JsonObject userPermission = Json.createObjectBuilder().add("permissions", Json.createObjectBuilder().add("isInheritanceEnabled", false)).build(); + String putBody = userPermission.toString(); + restClient.authenticateUser(testUser).withCoreAPI().usingNode(folder3).updateNode(putBody); + + // Wait for indexing + waitForIndexing(folder3.getName(), true); + + // Search as testUser: expect all: 5 results: When user is a Site Manager + SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); + int resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 6, "Unexpected Result count for testUser: Expected 5, received: " + resultCount); + + // Search as testUser1: expect 3 results: when user is a site member but without permission to a content + response = queryAsUser(testUser1, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); + + // Search as testUser2: expect 1 result: When user isn't a site member but has granular permissions to a content + response = queryAsUser(testUser2, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); + + // Search as testUser3: expect none: 0 results: When user isn't a site member / does not have granular permissions to the content + response = queryAsUser(testUser3, "cm:name:perm*"); + resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); + } + + @Test(priority = 3) + public void searchResultsOnChangingSiteVisibility() throws Exception + { + // Create Site + SiteModel testPermissionsSite = new SiteModel(RandomData.getRandomName("SiteSearchPermissions")); + testPermissionsSite.setVisibility(Visibility.PUBLIC); + + dataSite.usingUser(adminUserModel).createSite(testPermissionsSite); + + // Add Users to the site + dataUser.addUserToSite(testUser, testPermissionsSite, UserRole.SiteCollaborator); + + // Create a folder + String folderName = "Folder" + unique_searchString; + FolderModel folder = dataContent.usingUser(testUser).usingSite(testPermissionsSite).createFolderCmisApi(folderName); + + // Query + Assert.assertTrue(waitForIndexing(folder.getName(), true), "Folder isn't yet indexed"); + + // Edit Site Visibility + testPermissionsSite.setDescription("PrivateSite".concat(testPermissionsSite.getDescription())); + testPermissionsSite.setVisibility(Visibility.PRIVATE); + restClient.authenticateUser(adminUserModel).withCoreAPI().usingSite(testPermissionsSite).updateSite(testPermissionsSite); + + // Wait for indexing + Assert.assertTrue(waitForIndexing("description:" + testPermissionsSite.getDescription(), true), "New Site Description isn't yet been indexed"); + + // Query + SearchResponse response = queryAsUser(testUser, folderName); + int resultCount = response.getPagination().getCount(); + Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser: Expected 1, received: " + resultCount); + } } From ccd12d2693813a7241a4988a9c8bf1066742aed5 Mon Sep 17 00:00:00 2001 From: mbhave Date: Tue, 11 Feb 2020 16:00:55 +0000 Subject: [PATCH 23/94] Search-2096: Need updateSite api from tas-rest-api version 1.30 --- e2e-test/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index f12c76d11..64d65e2bf 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,8 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.30 - 1.26 + 1.31 1.13 3.0.19 3.3.0 From 612486c8faf0f010571169b405a1b6981b302641 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 11 Feb 2020 22:12:34 +0000 Subject: [PATCH 24/94] Bump restapi from 1.30 to 1.31 in /e2e-test Bumps [restapi](https://github.com/Alfresco/alfresco-tas-restapi) from 1.30 to 1.31. - [Release notes](https://github.com/Alfresco/alfresco-tas-restapi/releases) - [Commits](https://github.com/Alfresco/alfresco-tas-restapi/compare/v1.30...v1.31) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index f12c76d11..e1da6b8a7 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,7 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.30 + 1.31 1.26 1.13 3.0.19 From 898c4f82573a848ad889c3391e771bdd09ead675 Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 12 Feb 2020 08:12:16 +0000 Subject: [PATCH 25/94] SEARCH-1681 adding test group to exclude test on bamboo --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 1cbbee75c..67ad4d311 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -43,7 +43,7 @@ import org.springframework.http.HttpStatus; public class ShardInfoTest extends AbstractE2EFunctionalTest { /* The test that will be excluded when running master slave setup, excluding the ASS_MASTER test group. */ - @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.SHARDING }) + @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.EXPLICIT_SHARDING }) public void getShardInfoWithAdminAuthority() throws JsonProcessingException { RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() From cce988b3b6838085a48d39a9f11b2a97b05b7aff Mon Sep 17 00:00:00 2001 From: Tom Page Date: Wed, 12 Feb 2020 08:23:51 +0000 Subject: [PATCH 26/94] Remove duplicate entry for tas.rest.api from pom.xml. --- e2e-test/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index e1da6b8a7..64d65e2bf 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -12,7 +12,6 @@ Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share 1.31 - 1.26 1.13 3.0.19 3.3.0 From d5072eff1b59d596ff6966bc38467c572f2eab8e Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 12 Feb 2020 08:25:00 +0000 Subject: [PATCH 27/94] SEARCH-1681 review changes with pagination message --- .../functional/searchServices/search/ShardInfoTest.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 67ad4d311..aebd9c39e 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -142,13 +142,8 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI().getInfo(); restClient.assertStatusCodeIs(HttpStatus.OK); info.assertThat().entriesListIsNotEmpty(); - - if(info.getPagination().getTotalItems().intValue() == 2){ - assertEquals(info.getPagination().getTotalItems().intValue(), 2); - } - else{ - System.out.println("Pagination is: " + info.getPagination().getTotalItems().intValue() + " not expected value of 2"); - } + + assertEquals(info.getPagination().getTotalItems().intValue(), 2, "Pagination is: " + info.getPagination().getTotalItems().intValue() + " not expected value of 2"); Set stores = Sets.newHashSet("workspace://SpacesStore", "archive://SpacesStore"); List baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive"); From e22bb2966d27eefa98365311a869fc432fa483e9 Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 12 Feb 2020 09:44:12 +0000 Subject: [PATCH 28/94] SEARCH-1681 spelling on DB_ID_RANGE in switch statement --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index aebd9c39e..3391d25bb 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -189,7 +189,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest case "DB_ID": assertTrue(shardingMethod == "DB_ID", "Sharding Method is not DB_ID"); break; - case "DB_IN_RANGE": + case "DB_ID_RANGE": assertTrue(shardingMethod == "DB_ID_RANGE", "Sharding Method is not DB_ID_RANGE"); break; case "DATE": From 087ab1734e91e7ee4b2a4e25e23464f3c9d78300 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Wed, 12 Feb 2020 10:59:08 +0100 Subject: [PATCH 29/94] Add missing parameter messages to responses instead of throwing Exceptions. Extended test coverage. --- .../solr/admin/SolrE2eAdminTest.java | 580 ++++++++++++++++-- .../solr/AlfrescoCoreAdminHandler.java | 109 ++-- 2 files changed, 586 insertions(+), 103 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java index 0ae0abd97..ee6703821 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java @@ -27,7 +27,7 @@ import org.testng.annotations.Test; /** * End to end tests for SOLR Admin actions REST API, available from: * - * http://:/solr/admin/cores?action=* + * http://:/solr/admin/cores?action=(actionName) * * @author aborroy * @@ -39,7 +39,6 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest // SOLR default response status codes (returned in responseHeader.status) private static final String SOLR_RESPONSE_STATUS_OK = "0"; - private static final String SOLR_RESPONSE_STATUS_INTERNAL_ERROR = "400"; // Alfresco SOLR action response status identifiers private static final String ACTION_RESPONSE_REPORT = "report"; @@ -47,6 +46,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest // Default Alfresco SOLR Core Names List defaultCoreNames = new ArrayList<>(List.of("alfresco", "archive")); + /** + * Node Report for every core. + * @throws Exception + */ @Test(priority = 1) public void testNodeReport() throws Exception { @@ -65,20 +68,59 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest } /** - * Node Report requires "nodeid" parameter. - * This test will fail as we are missing to pass the parameter. + * Node Report for an specific core. * @throws Exception */ @Test(priority = 2) + public void testNodeReportCore() throws Exception + { + final String nodeid = "200"; + + defaultCoreNames.forEach(core -> { + + try + { + + RestResponse response = restClient.withParams("nodeid=" + nodeid, "core=" + core).withSolrAdminAPI().getAction("nodeReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); + Assert.assertNotNull(report); + + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * Node Report requires "nodeid" parameter. + * This test will return an error as we are missing to pass the parameter. + * @throws Exception + */ + @Test(priority = 3) public void testNodeReportError() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("nodeReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); + Assert.assertNotNull(reportError); + } - @Test(priority = 3) + /** + * ACL Report for every core. + * @throws Exception + */ + @Test(priority = 4) public void testAclReport() throws Exception { String aclid = "1"; @@ -92,26 +134,58 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest } /** - * Acl Report requires "aclid" parameter. + * ACL Report for an specific core. + * @throws Exception + */ + @Test(priority = 5) + public void testAclReportCore() throws Exception + { + final String aclid = "1"; + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("aclid=" + aclid, "core=" + core).withSolrAdminAPI().getAction("aclReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); + Assert.assertNotNull(report); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + + } + + /** + * ACL Report requires "aclid" parameter. * This test will fail as we are missing to pass the parameter. * @throws Exception */ - @Test(priority = 4) + @Test(priority = 6) public void testAclReportError() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("aclReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); + Assert.assertNotNull(reportError); } - @Test(priority = 5) + /** + * TX Report for every core. + * @throws Exception + */ + @Test(priority = 7) public void testTxReport() throws Exception { - String coreName = "alfresco"; String txid = "1"; - RestResponse response = restClient.withParams("coreName=" + coreName, "txid=" + txid).withSolrAdminAPI().getAction("txReport"); + RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("txReport"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); @@ -120,21 +194,56 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertNotNull(report); } + /** + * TX Report for an specific core. + * @throws Exception + */ + @Test(priority = 8) + public void testTxReportCore() throws Exception + { + final String txid = "1"; + defaultCoreNames.forEach(core -> { + + try + { + + RestResponse response = restClient.withParams("coreName=" + core, "txid=" + txid).withSolrAdminAPI().getAction("txReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); + Assert.assertNotNull(report); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + /** * Transaction report requires "txid" parameter. * This test will fail as we are missing to pass the parameter. * @throws Exception */ - @Test(priority = 6) + @Test(priority = 9) public void testTxReportError() throws Exception { - RestResponse response = restClient.withSolrAdminAPI().getAction("txReport"); + String coreName = "alfresco"; - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("txReport"); + + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); + Assert.assertNotNull(reportError); } - @Test(priority = 7) + /** + * ACL TX Report for every core. + * @throws Exception + */ + @Test(priority = 10) public void testAclTxReport() throws Exception { String acltxid = "1"; @@ -148,21 +257,54 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertNotNull(report); } + /** + * ACL TX Report for specific core. + * @throws Exception + */ + @Test(priority = 11) + public void testAclTxReportCore() throws Exception + { + final String acltxid = "1"; + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("acltxid=" + acltxid, "core=" + core).withSolrAdminAPI().getAction("aclTxReport"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); + Assert.assertNotNull(report); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + + } + /** * AclTx report requires "acltxid" parameter. * This test will fail as we are missing to pass the parameter. * @throws Exception */ - @Test(priority = 8) + @Test(priority = 12) public void testAclTxReportError() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("aclTxReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_INTERNAL_ERROR); + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); + Assert.assertNotNull(reportError); } - @Test(priority = 9) + /** + * Report for every core. + * @throws Exception + */ + @Test(priority = 13) public void testReport() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction(ACTION_RESPONSE_REPORT); @@ -174,12 +316,61 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertNotNull(report); } - @Test(priority = 10) + /** + * Report for specific core. + * @throws Exception + */ + @Test(priority = 14) + public void testReportCore() throws Exception + { + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction(ACTION_RESPONSE_REPORT); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); + Assert.assertNotNull(report); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * Report using params. + * @throws Exception + */ + @Test(priority = 15) + public void testReportWithParams() throws Exception + { + Long fromTime = 0l; + Long toTime = 0l; + + RestResponse response = restClient.withParams("fromTime=" + fromTime, "toTime=" + toTime).withSolrAdminAPI() + .getAction(ACTION_RESPONSE_REPORT); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); + Assert.assertNotNull(report); + } + + /** + * Summary for every core. + * @throws Exception + */ + @Test(priority = 16) public void testSummary() throws Exception { - String core = "alfresco"; - - RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("summary"); + RestResponse response = restClient.withSolrAdminAPI().getAction("summary"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); @@ -188,12 +379,41 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertNotNull(report); } - @Test(priority = 11) + /** + * Summary for specific core. + * @throws Exception + */ + @Test(priority = 17) + public void testSummaryCore() throws Exception + { + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("summary"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String report = response.getResponse().body().jsonPath().get("Summary." + core).toString(); + Assert.assertNotNull(report); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * Check every core. + * @throws Exception + */ + @Test(priority = 18) public void testCheck() throws Exception { - String core = "alfresco"; - - RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("check"); + RestResponse response = restClient.withSolrAdminAPI().getAction("check"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); @@ -202,12 +422,39 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertEquals(actionStatus, "success"); } + /** + * Check specific core. + * @throws Exception + */ + @Test(priority = 19) + public void testCheckCore() throws Exception + { + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("check"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "success"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + /** * This action only applies to DB_ID_RANGE Sharding method. * This test verifies expected result when using another deployment * @throws Exception */ - @Test(priority = 12) + @Test(priority = 20) public void testRangeCheck() throws Exception { String coreName = "alfresco"; @@ -225,7 +472,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * When using DB_ID_RANGE Sharding method, expand param is including a number of nodes to be extended. * @throws Exception */ - @Test(priority = 13, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) + @Test(priority = 21, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) public void testRangeCheckSharding() throws Exception { String coreName = "alfresco"; @@ -244,7 +491,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * This test verifies expected result when using another deployment * @throws Exception */ - @Test(priority = 14) + @Test(priority = 22) public void testExpand() throws Exception { String coreName = "alfresco"; @@ -264,7 +511,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * When using DB_ID_RANGE Sharding method, expand param is including a number of nodes extended. * @throws Exception */ - @Test(priority = 15, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) + @Test(priority = 23, groups = { TestGroup.ASS_SHARDING_DB_ID_RANGE }) public void testExpandSharding() throws Exception { String coreName = "alfresco"; @@ -280,13 +527,16 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertNotEquals(expand, "-1"); } - @Test(priority = 16) + /** + * Purge TX in every core. + * @throws Exception + */ + @Test(priority = 24) public void testPurge() throws Exception { - String core = "alfresco"; String txid = "1"; - RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("purge"); + RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("purge"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); @@ -295,59 +545,210 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertEquals(actionStatus, "scheduled"); } - @Test(priority = 17) + /** + * Purge TX in specific core. + * @throws Exception + */ + @Test(priority = 25) + public void testPurgeCore() throws Exception + { + final String txid = "1"; + + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("purge"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * Purge with no params produces an empty response. + * @throws Exception + */ + @Test(priority = 26) + public void testPurgeEmpty() throws Exception + { + RestResponse response = restClient.withSolrAdminAPI().getAction("purge"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + + /** + * FIX for every core. + * @throws Exception + */ + @Test(priority = 27) public void testFix() throws Exception { - String core = "alfresco"; - - RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("fix"); + RestResponse response = restClient.withSolrAdminAPI().getAction("fix"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); + defaultCoreNames.forEach(core -> { + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); + }); String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); Assert.assertEquals(actionStatus, "scheduled"); } - @Test(priority = 18) + /** + * FIX for specific core. + * @throws Exception + */ + @Test(priority = 28) + public void testFixCore() throws Exception + { + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("fix"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * REINDEX for every core. + * @throws Exception + */ + @Test(priority = 29) public void testReindex() throws Exception { - String core = "alfresco"; String txid = "1"; - RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("reindex"); + RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("reindex"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); - Assert.assertEquals(actionStatus, "scheduled"); + Assert.assertEquals(actionStatus, "scheduled"); } - @Test(priority = 19) + /** + * REINDEX for specific core. + * @throws Exception + */ + @Test(priority = 30) + public void testReindexCore() throws Exception + { + String txid = "1"; + + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("reindex"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * RETRY for every core. + * @throws Exception + */ + @Test(priority = 31) public void testRetry() throws Exception { - String core = "alfresco"; - - RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("retry"); + RestResponse response = restClient.withSolrAdminAPI().getAction("retry"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); Assert.assertEquals(actionStatus, "scheduled"); + + defaultCoreNames.forEach(core -> { + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + }); } - @Test(priority = 20) + /** + * RETRY for specific core. + * @throws Exception + */ + @Test(priority = 32) + public void testRetryCore() throws Exception + { + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("retry"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * INDEX for every core. + * @throws Exception + */ + @Test(priority = 33) public void testIndex() throws Exception { - String core = "alfresco"; String txid = "1"; - RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("index"); + RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("index"); String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); @@ -356,7 +757,40 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertEquals(actionStatus, "scheduled"); } - @Test(priority = 21) + /** + * INDEX for specific core. + * @throws Exception + */ + @Test(priority = 34) + public void testIndexCore() throws Exception + { + final String txid = "1"; + + defaultCoreNames.forEach(core -> { + + try + { + RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("index"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "scheduled"); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + + }); + } + + /** + * Reloads default log4j properties into memory. + * @throws Exception + */ + @Test(priority = 35) public void testLog4J() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("log4j"); @@ -368,11 +802,27 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertEquals(actionStatus, "success"); } + /** + * This test will fail as specified resource to reload doesn't exist. + * @throws Exception + */ + @Test(priority = 36) + public void testLog4JError() throws Exception + { + RestResponse response = restClient.withParams("resource=log4j-unexisting.properties").withSolrAdminAPI().getAction("log4j"); + + String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + Assert.assertEquals(actionStatus, "error"); + } + /** * This test will fail if it's executed twice * @throws Exception */ - @Test(priority = 22) + @Test(priority = 37) public void testNewCore() throws Exception { String core = "newCore"; @@ -393,7 +843,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * When creating a core that already exists, this action fails. * @throws Exception */ - @Test(priority = 23) + @Test(priority = 38) public void testNewCoreError() throws Exception { String core = "alfresco"; @@ -409,7 +859,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest Assert.assertEquals(actionStatus, "error"); } - @Test(priority = 24) + /** + * Reloads core configuration in memory. + * @throws Exception + */ + @Test(priority = 39) public void testUpdateCore() throws Exception { String core = "alfresco"; @@ -427,7 +881,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * When updating a core that doesn't exist, this action fails. * @throws Exception */ - @Test(priority = 25) + @Test(priority = 40) public void testUpdateCoreError() throws Exception { String core = "nonExistingCore"; @@ -445,7 +899,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * This test updates "shared.properties" memory loading for every SOLR core. * @throws Exception */ - @Test(priority = 26) + @Test(priority = 41) public void testUpdateShared() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("updateShared"); @@ -461,7 +915,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * This test will fail if it's executed twice * @throws Exception */ - @Test(priority = 27) + @Test(priority = 42) public void testNewDefaultCore() throws Exception { String core = "newDefaultCore"; @@ -483,7 +937,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * When creating a core that already exists, this action fails. * @throws Exception */ - @Test(priority = 28) + @Test(priority = 43) public void testNewDefaultCoreError() throws Exception { String core = "alfresco"; diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java index 9f0c64d97..d84069eab 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java @@ -984,18 +984,22 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * - core, The name of the SOLR Core or "null" to get the report for every core * @return Response including the action result: * - report: An Object with the report details + * - error: When mandatory parameters are not set, an error node is returned * * @throws JSONException */ private NamedList actionNODEREPORTS(SolrParams params) throws JSONException { - Long dbid = - ofNullable(params.get(ARG_NODEID)) - .map(Long::valueOf) - .orElseThrow(() -> new AlfrescoRuntimeException("No dbid parameter set.")); - + NamedList report = new SimpleOrderedMap<>(); + Long nodeid = ofNullable(params.get(ARG_NODEID)).map(Long::valueOf).orElse(null); + if (nodeid == null) + { + report.add(ACTION_STATUS_ERROR, "No " + ARG_NODEID +" parameter set."); + return report; + } + String requestedCoreName = coreName(params); coreNames().stream() @@ -1006,7 +1010,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler .forEach(coreNameAndPublisher -> report.add( coreNameAndPublisher.getFirst(), - buildNodeReport(coreNameAndPublisher.getSecond(), dbid))); + buildNodeReport(coreNameAndPublisher.getSecond(), nodeid))); return report; } @@ -1020,18 +1024,21 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * - core, The name of the SOLR Core or "null" to get the report for every core * @return Response including the action result: * - report: an Object with the details of the report - * + * - error: When mandatory parameters are not set, an error node is returned + * * @throws JSONException */ private NamedList actionACLREPORT(SolrParams params) throws JSONException { - Long aclid = - ofNullable(params.get(ARG_ACLID)) - .map(Long::valueOf) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + ARG_ACLID + " parameter set.")); - NamedList report = new SimpleOrderedMap<>(); + Long aclid = ofNullable(params.get(ARG_ACLID)).map(Long::valueOf).orElse(null); + if (aclid == null) + { + report.add(ACTION_STATUS_ERROR, "No " + ARG_ACLID + " parameter set."); + return report; + } + String requestedCoreName = coreName(params); coreNames().stream() @@ -1062,32 +1069,43 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * - core, The name of the SOLR Core or "null" to get the report for every core * @return Response including the action result: * - report: an Object with the details of the report + * - error: When mandatory parameters are not set, an error node is returned * * @throws JSONException */ private NamedList actionTXREPORT(SolrParams params) throws JSONException { - String coreName = - ofNullable(coreName(params)) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); - NamedList report = new SimpleOrderedMap<>(); - - if (isMasterOrStandalone(coreName)) + + Long txid = ofNullable(params.get(ARG_TXID)).map(Long::valueOf).orElse(null); + if (txid == null) { - MetadataTracker tracker = trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class); - Long txid = - ofNullable(params.get(ARG_TXID)) - .map(Long::valueOf) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + ARG_TXID + " parameter set.")); - - report.add(coreName, buildTxReport(trackerRegistry, informationServers.get(coreName), coreName, tracker, txid)); + report.add(ACTION_STATUS_ERROR, "No " + ARG_TXID + " parameter set."); + return report; } - else + + String requestedCoreName = coreName(params); + + coreNames().stream() + .filter(coreName -> requestedCoreName == null || coreName.equals(requestedCoreName)) + .map(coreName -> new Pair<>(coreName, trackerRegistry.getTrackerForCore(coreName, MetadataTracker.class))) + .filter(coreNameAndMetadataTracker -> coreNameAndMetadataTracker.getSecond() != null) + .forEach(coreNameAndMetadataTracker -> + report.add( + coreNameAndMetadataTracker.getFirst(), + buildTxReport( + trackerRegistry, + informationServers.get(coreNameAndMetadataTracker.getFirst()), + coreNameAndMetadataTracker.getFirst(), + coreNameAndMetadataTracker.getSecond(), + txid))); + + if (report.size() == 0) { addAlertMessage(report); } return report; + } /** @@ -1100,17 +1118,20 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * - acltxid, mandatory, the number of the ACL TX Id to build the report * @return Response including the action result: * - report: an Object with the details of the report + * - error: When mandatory parameters are not set, an error node is returned * * @throws JSONException */ private NamedList actionACLTXREPORT(SolrParams params) throws JSONException { - Long acltxid = - ofNullable(params.get(ARG_ACLTXID)) - .map(Long::valueOf) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + ARG_ACLTXID + " parameter set.")); - NamedList report = new SimpleOrderedMap<>(); + + Long acltxid = ofNullable(params.get(ARG_ACLTXID)).map(Long::valueOf).orElse(null); + if (acltxid == null) + { + report.add(ACTION_STATUS_ERROR, "No " + ARG_ACLTXID + " parameter set."); + return report; + } String requestedCoreName = coreName(params); @@ -1145,17 +1166,21 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * - core, The name of the SOLR Core * @return Response including the action result: * - report: An Object with the report details + * - error: When mandatory parameters are not set, an error node is returned * * @throws IOException */ private NamedList rangeCheck(SolrParams params) throws IOException { - String coreName = - ofNullable(coreName(params)) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); - NamedList response = new SimpleOrderedMap<>(); + String coreName = ofNullable(coreName(params)).orElse(null); + if (coreName == null) + { + response.add(ACTION_STATUS_ERROR, "No " + CoreAdminParams.CORE + " parameter set."); + return response; + } + if (isMasterOrStandalone(coreName)) { InformationServer informationServer = informationServers.get(coreName); @@ -1235,7 +1260,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler else { response.add("expand", -1); - response.add("exception", "ERROR: Wrong document router type:"+docRouter.getClass().getSimpleName()); + response.add("exception", "ERROR: Wrong document router type:" + docRouter.getClass().getSimpleName()); } } else @@ -1257,17 +1282,21 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler * @return Response including the action result: * - expand: The number of the new End Range limit or -1 if the action failed * - exception: Error message if expand is -1 + * - error: When mandatory parameters are not set, an error node is returned * * @throws IOException */ private synchronized NamedList expand(SolrParams params) throws IOException { - String coreName = - ofNullable(coreName(params)) - .orElseThrow(() -> new AlfrescoRuntimeException("No " + CoreAdminParams.CORE + " parameter set.")); - NamedList response = new SimpleOrderedMap<>(); + String coreName = ofNullable(coreName(params)).orElse(null); + if (coreName == null) + { + response.add(ACTION_STATUS_ERROR, "No " + CoreAdminParams.CORE + " parameter set."); + return response; + } + if (isMasterOrStandalone(coreName)) { InformationServer informationServer = informationServers.get(coreName); From 15a6f2cb6d84a8b3ff842e90fb8070004b7f1654 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 12 Feb 2020 22:14:00 +0000 Subject: [PATCH 30/94] Bump rm.version from 3.3.0 to 3.3.0.1 in /e2e-test Bumps `rm.version` from 3.3.0 to 3.3.0.1. Updates `alfresco-governance-services-automation-enterprise-rest-api` from 3.3.0 to 3.3.0.1 Updates `alfresco-governance-services-automation-community-rest-api` from 3.3.0 to 3.3.0.1 Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 28af17776..426de220e 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -14,7 +14,7 @@ 1.30 1.13 3.0.19 - 3.3.0 + 3.3.0.1 src/test/resources/SearchSuite.xml From e4ba6c6d2c3bb99052937167d27fd04bd7bb3436 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 11:31:08 +0100 Subject: [PATCH 31/94] Adding detailed asserts in order to check parameter values inside the JSON Response. --- .../solr/admin/SolrE2eAdminTest.java | 106 ++++++++++-------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java index ee6703821..6d2172a51 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java @@ -36,7 +36,6 @@ import org.testng.annotations.Test; public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { - // SOLR default response status codes (returned in responseHeader.status) private static final String SOLR_RESPONSE_STATUS_OK = "0"; @@ -44,7 +43,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest private static final String ACTION_RESPONSE_REPORT = "report"; // Default Alfresco SOLR Core Names - List defaultCoreNames = new ArrayList<>(List.of("alfresco", "archive")); + private static final List DEFAULT_CORE_NAMES = new ArrayList<>(List.of("alfresco", "archive")); /** * Node Report for every core. @@ -62,8 +61,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); Assert.assertNotNull(report); - defaultCoreNames.forEach(core -> { - Assert.assertNotNull(response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core)); + DEFAULT_CORE_NAMES.forEach(core -> { + String reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'").toString(); + Assert.assertEquals(nodeid, reportNodeid); }); } @@ -76,7 +76,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { final String nodeid = "200"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -86,8 +86,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); - Assert.assertNotNull(report); + String reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'").toString(); + Assert.assertEquals(nodeid, reportNodeid); } catch (Exception e) @@ -129,8 +129,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + String reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'").toString(); + Assert.assertEquals(aclid, reportAclid); + }); } /** @@ -141,7 +143,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest public void testAclReportCore() throws Exception { final String aclid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -150,8 +152,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); - Assert.assertNotNull(report); + String reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'").toString(); + Assert.assertEquals(aclid, reportAclid); } catch (Exception e) { @@ -159,7 +161,6 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest } }); - } /** @@ -190,8 +191,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + String reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID").toString(); + Assert.assertEquals(txid, reportTxid); + }); } /** @@ -202,7 +205,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest public void testTxReportCore() throws Exception { final String txid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -212,8 +215,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); - Assert.assertNotNull(report); + String reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID").toString(); + Assert.assertEquals(txid, reportTxid); } catch (Exception e) { @@ -253,8 +256,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + String reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount").toString(); + Assert.assertEquals("2", reportAcltxidCount); + }); } /** @@ -265,7 +270,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest public void testAclTxReportCore() throws Exception { final String acltxid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -274,8 +279,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); - Assert.assertNotNull(report); + String reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount").toString(); + Assert.assertEquals("2", reportAcltxidCount); } catch (Exception e) { @@ -283,7 +288,6 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest } }); - } /** @@ -312,8 +316,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); + Assert.assertTrue(reportTxCount > 0); + }); } /** @@ -323,7 +329,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 14) public void testReportCore() throws Exception { - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -332,8 +338,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core).toString(); - Assert.assertNotNull(report); + Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); + Assert.assertTrue(reportTxCount > 0); } catch (Exception e) { @@ -359,8 +365,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); + Assert.assertTrue(reportTxCount == 0); + }); } /** @@ -375,8 +383,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get("Summary").toString(); - Assert.assertNotNull(report); + DEFAULT_CORE_NAMES.forEach(core -> { + Integer reportTxCount = response.getResponse().body().jsonPath().get("Summary." + core + ".'Alfresco Transactions in Index'"); + Assert.assertTrue(reportTxCount > 0); + }); } /** @@ -386,7 +396,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 17) public void testSummaryCore() throws Exception { - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -395,8 +405,8 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - String report = response.getResponse().body().jsonPath().get("Summary." + core).toString(); - Assert.assertNotNull(report); + Integer reportTxCount = response.getResponse().body().jsonPath().get("Summary." + core + ".'Alfresco Transactions in Index'"); + Assert.assertTrue(reportTxCount > 0); } catch (Exception e) { @@ -429,7 +439,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 19) public void testCheckCore() throws Exception { - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -554,7 +564,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { final String txid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -602,7 +612,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); }); @@ -618,7 +628,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 28) public void testFixCore() throws Exception { - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -668,7 +678,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { String txid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -703,7 +713,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); Assert.assertEquals(actionStatus, "scheduled"); - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); }); @@ -716,7 +726,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 32) public void testRetryCore() throws Exception { - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -766,7 +776,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { final String txid = "1"; - defaultCoreNames.forEach(core -> { + DEFAULT_CORE_NAMES.forEach(core -> { try { @@ -803,7 +813,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest } /** - * This test will fail as specified resource to reload doesn't exist. + * This REST API call will fail as the specified resource to reload doesn't exist. * @throws Exception */ @Test(priority = 36) @@ -837,6 +847,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); Assert.assertEquals(actionStatus, "success"); + + String actionCore = response.getResponse().body().jsonPath().get("action.core").toString(); + Assert.assertEquals(core, actionCore); } /** @@ -931,6 +944,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); Assert.assertEquals(actionStatus, "success"); + + String actionCore = response.getResponse().body().jsonPath().get("action.core").toString(); + Assert.assertEquals(core, actionCore); } /** From fe315ca71014d33b55357e570e3205d95297f107 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 11:31:35 +0100 Subject: [PATCH 32/94] Avoid coding useless conditions. --- .../solr/AlfrescoCoreAdminHandler.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java index d84069eab..3d5bce192 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/AlfrescoCoreAdminHandler.java @@ -993,13 +993,13 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler NamedList report = new SimpleOrderedMap<>(); - Long nodeid = ofNullable(params.get(ARG_NODEID)).map(Long::valueOf).orElse(null); - if (nodeid == null) + if (params.get(ARG_NODEID) == null) { report.add(ACTION_STATUS_ERROR, "No " + ARG_NODEID +" parameter set."); return report; } - + + Long nodeid = Long.valueOf(params.get(ARG_NODEID)); String requestedCoreName = coreName(params); coreNames().stream() @@ -1032,13 +1032,13 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { NamedList report = new SimpleOrderedMap<>(); - Long aclid = ofNullable(params.get(ARG_ACLID)).map(Long::valueOf).orElse(null); - if (aclid == null) + if (params.get(ARG_ACLID) == null) { report.add(ACTION_STATUS_ERROR, "No " + ARG_ACLID + " parameter set."); return report; } + Long aclid = Long.valueOf(params.get(ARG_ACLID)); String requestedCoreName = coreName(params); coreNames().stream() @@ -1077,13 +1077,13 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { NamedList report = new SimpleOrderedMap<>(); - Long txid = ofNullable(params.get(ARG_TXID)).map(Long::valueOf).orElse(null); - if (txid == null) + if (params.get(ARG_TXID) == null) { report.add(ACTION_STATUS_ERROR, "No " + ARG_TXID + " parameter set."); return report; } + Long txid = Long.valueOf(params.get(ARG_TXID)); String requestedCoreName = coreName(params); coreNames().stream() @@ -1126,13 +1126,13 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { NamedList report = new SimpleOrderedMap<>(); - Long acltxid = ofNullable(params.get(ARG_ACLTXID)).map(Long::valueOf).orElse(null); - if (acltxid == null) + if (params.get(ARG_ACLTXID) == null) { report.add(ACTION_STATUS_ERROR, "No " + ARG_ACLTXID + " parameter set."); return report; } + Long acltxid = Long.valueOf(params.get(ARG_ACLTXID)); String requestedCoreName = coreName(params); coreNames().stream() @@ -1174,7 +1174,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { NamedList response = new SimpleOrderedMap<>(); - String coreName = ofNullable(coreName(params)).orElse(null); + String coreName = coreName(params); if (coreName == null) { response.add(ACTION_STATUS_ERROR, "No " + CoreAdminParams.CORE + " parameter set."); @@ -1290,7 +1290,7 @@ public class AlfrescoCoreAdminHandler extends CoreAdminHandler { NamedList response = new SimpleOrderedMap<>(); - String coreName = ofNullable(coreName(params)).orElse(null); + String coreName = coreName(params); if (coreName == null) { response.add(ACTION_STATUS_ERROR, "No " + CoreAdminParams.CORE + " parameter set."); From bb4a07eda848af2da7c6dab6f58637b3e6e44d44 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Thu, 13 Feb 2020 11:29:26 +0000 Subject: [PATCH 33/94] SEARCH-2089 Update docker-compose generator to use -Dsolr.baseUrl. --- .../generators/app/templates/6.1/docker-compose-ce.yml | 2 +- .../generators/app/templates/6.1/docker-compose-ee.yml | 2 +- .../generators/app/templates/6.2/docker-compose-ce.yml | 2 +- .../generators/app/templates/6.2/docker-compose-ee.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ce.yml b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ce.yml index cf47d559b..50a2154f0 100755 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ce.yml +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ce.yml @@ -23,7 +23,7 @@ services: -Dsolr.host=<%=searchSolrHost%> -Dsolr.port.ssl=8983 -Dsolr.secureComms=<%=secureComms%> - -Dsolr.base.url=/solr + -Dsolr.baseUrl=/solr -Dindex.subsystem.name=solr6 -Dshare.host=localhost -Dalfresco.port=8080 diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ee.yml b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ee.yml index 31859c711..583b40507 100755 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ee.yml +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.1/docker-compose-ee.yml @@ -22,7 +22,7 @@ services: -Dsolr.host=<%=searchSolrHost%> -Dsolr.port.ssl=8983 -Dsolr.secureComms=<%=secureComms%> - -Dsolr.base.url=/solr <% if (sharding == 'true') { %> + -Dsolr.baseUrl=/solr <% if (sharding == 'true') { %> -Dsolr.useDynamicShardRegistration=true <% } %> -Dindex.subsystem.name=solr6 -Dalfresco-pdf-renderer.url=http://alfresco-pdf-renderer:8090/ diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ce.yml b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ce.yml index 7c137e4a0..c6f466991 100755 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ce.yml +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ce.yml @@ -24,7 +24,7 @@ services: -Dsolr.host=<%=searchSolrHost%> -Dsolr.port.ssl=8983 -Dsolr.secureComms=<%=secureComms%> - -Dsolr.base.url=/solr + -Dsolr.baseUrl=/solr -Dindex.subsystem.name=solr6 -Dshare.host=localhost -Dalfresco.port=8080 diff --git a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ee.yml b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ee.yml index 6a4f4a7fd..407049ddb 100755 --- a/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ee.yml +++ b/e2e-test/generator-alfresco-docker-compose/generators/app/templates/6.2/docker-compose-ee.yml @@ -22,7 +22,7 @@ services: -Dsolr.host=<%=searchSolrHost%> -Dsolr.port.ssl=8983 -Dsolr.secureComms=<%=secureComms%> - -Dsolr.base.url=/solr <% if (sharding == 'true') { %> + -Dsolr.baseUrl=/solr <% if (sharding == 'true') { %> -Dsolr.useDynamicShardRegistration=true <% } %> -Dindex.subsystem.name=solr6 From 6cb9b47fbb68a6bcf649163f94ea70b6b51a497a Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 13 Feb 2020 14:36:37 +0000 Subject: [PATCH 34/94] SEARCH-1681 creating a loop to go through instances and shards --- .../searchServices/search/ShardInfoTest.java | 89 ++++++++++--------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 3391d25bb..7c90ffb74 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -20,6 +20,7 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -155,56 +156,58 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest for (RestShardInfoModel shardInfoModel : entries) { RestShardInfoModel model = shardInfoModel.getModel(); - assertEquals(model.getTemplate(), "rerank"); - assertEquals(model.getMode(), "MASTER"); - assertTrue(model.getHasContent()); - assertTrue(model.getNumberOfShards()>=2); + assertEquals(model.getTemplate(), "rerank", "Template is not rerank, template found: "+ model.getTemplate()); + assertEquals(model.getMode(), "MASTER", "Mode is not MASTER, mode found: "+ model.getMode()); + assertTrue(model.getHasContent(), "There is no content on the shards"); + assertTrue(model.getNumberOfShards()>=2, "Number of shards is not equal to or greater than 2"); List shardingMethods = Arrays.asList("DB_ID", "DB_ID_RANGE", "EXPLICIT_ID", "ACL_ID", "MOD_ACL_ID", "DATE", "PROPERTY"); String shardingMethod = model.getShardMethod(); assertTrue(shardingMethods.contains(shardingMethod), "Unexpected Sharding Method Found: " + shardingMethod); List shards = model.getShards(); - assertNotNull(shards, "Unexpected number of shards found:" + shards); - RestShardModel shard = shards.iterator().next(); - assertNotNull(shard); - List instances = shard.getInstances(); - assertNotNull(instances, "Unexpected number of instances found:" + instances); - RestInstanceModel instance = instances.iterator().next(); - assertNotNull(instance); - assertTrue(baseUrls.contains(instance.getBaseUrl())); - - assertEquals(instance.getState(), "ACTIVE"); - - // shardparams related checks - String shardParams = instance.getShardParams(); - switch (shardingMethod) + assertNotNull(shards); + for (RestShardModel shardInstance : shards) { - case "MOD_ACL_ID": - assertTrue(shardingMethod == "MOD_ACL_ID", "Sharding Method is not MOD_ACL_ID"); - break; - case "ACL_ID": - assertTrue(shardingMethod == "ACL_ID", "Sharding Method is not ACL_ID"); - break; - case "DB_ID": - assertTrue(shardingMethod == "DB_ID", "Sharding Method is not DB_ID"); - break; - case "DB_ID_RANGE": - assertTrue(shardingMethod == "DB_ID_RANGE", "Sharding Method is not DB_ID_RANGE"); - break; - case "DATE": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for DATE"); - assertTrue(shardParams.contains("shard.grouping="), "Unexpected shard grouping defined for DATE"); - break; - case "PROPERTY": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for PROPERTY"); - break; - case "EXPLICIT_ID": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for EXPLICIT_ID"); - break; - default: - throw new AssertionError("Not as expected: " + shardParams.toString()); - } + List instanceList = shardInstance.getInstances(); + for (RestInstanceModel instanceX : instanceList) + { + assertTrue(baseUrls.contains(instanceX.getBaseUrl())); + assertEquals(instanceX.getState(), "ACTIVE", "Shard state is not ACTIVE, shard state is: " + instanceX.getState()); + assertNotNull(instanceX.getPort(), "There is not port found for the instance"); + assertEquals(instanceX.getMode(), "MASTER", "Mode is not MASTER, mode found: "+ instanceX.getMode()); + assertTrue(instanceX.getTransactionsRemaining() >= 0, "Transactions remaining is not more than 0, transactions remaining: " + instanceX.getTransactionsRemaining()); + String shardParams = (instanceX).getShardParams(); + switch (shardingMethod) + { + case "MOD_ACL_ID": + assertEquals(shardingMethod = "MOD_ACL_ID", "MOD_ACL_ID", "Sharding Method is not MOD_ACL_ID"); + break; + case "ACL_ID": + assertEquals(shardingMethod = "ACL_ID", "ACL_ID", "Sharding Method is not ACL_ID"); + break; + case "DB_ID": + assertEquals(shardingMethod = "DB_ID", "DB_ID", "Sharding Method is not DB_ID"); + break; + case "DB_ID_RANGE": + assertEquals(shardingMethod = "DB_ID_RANGE", "DB_ID_RANGE", "Sharding Method is not DB_ID_RANGE"); + //assertEquals(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); + break; + case "DATE": + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for DATE"); + assertTrue(shardParams.contains("shard.grouping="), "Unexpected shard grouping defined for DATE"); + break; + case "PROPERTY": + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for PROPERTY"); + break; + case "EXPLICIT_ID": + assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for EXPLICIT_ID"); + break; + default: + throw new AssertionError("Not as expected: " + shardParams.toString()); + } + } + } } } } From f03ec094cd2186de5b8883847ffbea14e7d30e71 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Thu, 13 Feb 2020 15:26:54 +0000 Subject: [PATCH 35/94] MNT-21021 Add documentation for alfresco.topTermSpanRewriteLimit. --- .../solr/instance/templates/noRerank/conf/solrcore.properties | 1 + .../solr/instance/templates/rerank/conf/solrcore.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties b/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties index a6a5a1fae..fab6b9e2e 100644 --- a/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties +++ b/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties @@ -165,6 +165,7 @@ alfresco.metadata.ignore.datatype.1=app:configurations alfresco.metadata.skipDescendantDocsForSpecificAspects=false #alfresco.metadata.ignore.aspect.0= +# The number of matches from the index to include when rewriting wildcard search terms as an OR-ed list. alfresco.topTermSpanRewriteLimit=1000 # diff --git a/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties b/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties index fdf702da6..d533ceb4d 100644 --- a/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties +++ b/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties @@ -165,6 +165,7 @@ alfresco.metadata.ignore.datatype.1=app:configurations alfresco.metadata.skipDescendantDocsForSpecificAspects=false #alfresco.metadata.ignore.aspect.0= +# The number of matches from the index to include when rewriting wildcard search terms as an OR-ed list. alfresco.topTermSpanRewriteLimit=1000 # From 572ff2831edd12a07be9c6eb35966f18fe067f6f Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 13 Feb 2020 15:33:59 +0000 Subject: [PATCH 36/94] SEARCH-1681 changing cases in the switch statement for shard methods with no checks to be made --- .../functional/searchServices/search/ShardInfoTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 7c90ffb74..6d7fd4388 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -181,16 +181,16 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest switch (shardingMethod) { case "MOD_ACL_ID": - assertEquals(shardingMethod = "MOD_ACL_ID", "MOD_ACL_ID", "Sharding Method is not MOD_ACL_ID"); + //No additional checks required break; case "ACL_ID": - assertEquals(shardingMethod = "ACL_ID", "ACL_ID", "Sharding Method is not ACL_ID"); + //No additional checks required break; case "DB_ID": - assertEquals(shardingMethod = "DB_ID", "DB_ID", "Sharding Method is not DB_ID"); + //No additional checks required break; case "DB_ID_RANGE": - assertEquals(shardingMethod = "DB_ID_RANGE", "DB_ID_RANGE", "Sharding Method is not DB_ID_RANGE"); + //To be commented out once the shard.range is visible on the sharding screen and if wanted //assertEquals(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); break; case "DATE": From 7f31fc41b7c2bd9f1870764d5dc48b8a952900f9 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 17:34:19 +0100 Subject: [PATCH 37/94] Added detailed messages to describe errors when testing. --- .../solr/admin/SolrE2eAdminTest.java | 336 +++++++++--------- 1 file changed, 162 insertions(+), 174 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java index 6d2172a51..143860ca1 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java @@ -15,6 +15,7 @@ package org.alfresco.test.search.functional.searchServices.solr.admin; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.alfresco.rest.core.RestResponse; @@ -37,13 +38,25 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { // SOLR default response status codes (returned in responseHeader.status) - private static final String SOLR_RESPONSE_STATUS_OK = "0"; + private static final Integer SOLR_RESPONSE_STATUS_OK = 0; // Alfresco SOLR action response status identifiers private static final String ACTION_RESPONSE_REPORT = "report"; // Default Alfresco SOLR Core Names private static final List DEFAULT_CORE_NAMES = new ArrayList<>(List.of("alfresco", "archive")); + + /** + * Check that SOLR Response Header contains a Query Time (qtime) and status equals to 0 + * @param response SOLR REST API Response in JSON + */ + private void checkResponseStatusOk(RestResponse response) + { + Integer qtime = response.getResponse().body().jsonPath().get("responseHeader.QTime"); + Assert.assertTrue(qtime >= 0, "Expeted responseHeader.QTime to be a positive number"); + Integer status = response.getResponse().body().jsonPath().get("responseHeader.status"); + Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK, "Expected " + SOLR_RESPONSE_STATUS_OK + " in responseHeader.status,"); + } /** * Node Report for every core. @@ -52,18 +65,14 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 1) public void testNodeReport() throws Exception { - String nodeid = "200"; + Integer nodeid = 200; RestResponse response = restClient.withParams("nodeid=" + nodeid).withSolrAdminAPI().getAction("nodeReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); - - String report = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT).toString(); - Assert.assertNotNull(report); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { - String reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'").toString(); - Assert.assertEquals(nodeid, reportNodeid); + Integer reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'"); + Assert.assertEquals(reportNodeid, nodeid, "Expected " + nodeid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID',"); }); } @@ -74,7 +83,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 2) public void testNodeReportCore() throws Exception { - final String nodeid = "200"; + final Integer nodeid = 200; DEFAULT_CORE_NAMES.forEach(core -> { @@ -83,11 +92,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("nodeid=" + nodeid, "core=" + core).withSolrAdminAPI().getAction("nodeReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'").toString(); - Assert.assertEquals(nodeid, reportNodeid); + Integer reportNodeid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID'"); + Assert.assertEquals(reportNodeid, nodeid, "Expected " + nodeid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".'Node DBID',"); } catch (Exception e) @@ -108,11 +116,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("nodeReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); - Assert.assertNotNull(reportError); + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error"); + Assert.assertEquals(reportError, "No nodeid parameter set.", "Unexpected message in " + ACTION_RESPONSE_REPORT + ".error,"); } @@ -123,15 +130,14 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 4) public void testAclReport() throws Exception { - String aclid = "1"; + Integer aclid = 1; RestResponse response = restClient.withParams("aclid=" + aclid).withSolrAdminAPI().getAction("aclReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { - String reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'").toString(); - Assert.assertEquals(aclid, reportAclid); + Integer reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'"); + Assert.assertEquals(reportAclid, aclid, "Expected " + aclid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id',"); }); } @@ -142,18 +148,17 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 5) public void testAclReportCore() throws Exception { - final String aclid = "1"; + final Integer aclid = 1; DEFAULT_CORE_NAMES.forEach(core -> { try { RestResponse response = restClient.withParams("aclid=" + aclid, "core=" + core).withSolrAdminAPI().getAction("aclReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'").toString(); - Assert.assertEquals(aclid, reportAclid); + Integer reportAclid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id'"); + Assert.assertEquals(reportAclid, aclid, "Expected " + aclid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".'Acl Id',"); } catch (Exception e) { @@ -173,8 +178,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("aclReport"); - String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); - Assert.assertNotNull(reportError); + checkResponseStatusOk(response); + + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error"); + Assert.assertEquals(reportError, "No aclid parameter set.", "Unexpected message in " + ACTION_RESPONSE_REPORT + ".error,"); } /** @@ -184,16 +191,15 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 7) public void testTxReport() throws Exception { - String txid = "1"; + Integer txid = 1; RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("txReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { - String reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID").toString(); - Assert.assertEquals(txid, reportTxid); + Integer reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID"); + Assert.assertEquals(reportTxid, txid, "Expected " + txid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".TXID,"); }); } @@ -204,7 +210,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 8) public void testTxReportCore() throws Exception { - final String txid = "1"; + final Integer txid = 1; DEFAULT_CORE_NAMES.forEach(core -> { try @@ -212,11 +218,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core, "txid=" + txid).withSolrAdminAPI().getAction("txReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID").toString(); - Assert.assertEquals(txid, reportTxid); + Integer reportTxid = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".TXID"); + Assert.assertEquals(reportTxid, txid, "Expected " + txid + " in " + ACTION_RESPONSE_REPORT + "." + core + ".TXID,"); } catch (Exception e) { @@ -238,8 +243,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("txReport"); - String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); - Assert.assertNotNull(reportError); + checkResponseStatusOk(response); + + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error"); + Assert.assertEquals(reportError, "No txid parameter set.", "Unexpected message in " + ACTION_RESPONSE_REPORT + ".error,"); } /** @@ -249,16 +256,15 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 10) public void testAclTxReport() throws Exception { - String acltxid = "1"; + Integer acltxid = 1; RestResponse response = restClient.withParams("acltxid=" + acltxid).withSolrAdminAPI().getAction("aclTxReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { - String reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount").toString(); - Assert.assertEquals("2", reportAcltxidCount); + Integer reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount"); + Assert.assertEquals(reportAcltxidCount, Integer.valueOf(2), "Expected 2 in " + ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount,"); }); } @@ -269,18 +275,17 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 11) public void testAclTxReportCore() throws Exception { - final String acltxid = "1"; + final Integer acltxid = 1; DEFAULT_CORE_NAMES.forEach(core -> { try { RestResponse response = restClient.withParams("acltxid=" + acltxid, "core=" + core).withSolrAdminAPI().getAction("aclTxReport"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount").toString(); - Assert.assertEquals("2", reportAcltxidCount); + Integer reportAcltxidCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount"); + Assert.assertEquals(reportAcltxidCount, Integer.valueOf(2), "Expected 2 in " + ACTION_RESPONSE_REPORT + "." + core + ".aclTxDbAclCount,"); } catch (Exception e) { @@ -300,8 +305,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("aclTxReport"); - String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error").toString(); - Assert.assertNotNull(reportError); + checkResponseStatusOk(response); + + String reportError = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + ".error"); + Assert.assertEquals(reportError, "No acltxid parameter set.", "Unexpected message in " + ACTION_RESPONSE_REPORT + ".error,"); } /** @@ -313,12 +320,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction(ACTION_RESPONSE_REPORT); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); - Assert.assertTrue(reportTxCount > 0); + Assert.assertTrue(reportTxCount > 0, "Expecting a positive integer in " + ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count',"); }); } @@ -335,11 +341,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction(ACTION_RESPONSE_REPORT); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); - Assert.assertTrue(reportTxCount > 0); + Assert.assertTrue(reportTxCount > 0, "Expecting a positive integer in " + ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count',"); } catch (Exception e) { @@ -362,12 +367,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("fromTime=" + fromTime, "toTime=" + toTime).withSolrAdminAPI() .getAction(ACTION_RESPONSE_REPORT); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { Integer reportTxCount = response.getResponse().body().jsonPath().get(ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count'"); - Assert.assertTrue(reportTxCount == 0); + Assert.assertTrue(reportTxCount == 0, "Expecting 0 in " + ACTION_RESPONSE_REPORT + "." + core + ".'DB transaction count',"); }); } @@ -380,12 +384,12 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("summary"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); DEFAULT_CORE_NAMES.forEach(core -> { Integer reportTxCount = response.getResponse().body().jsonPath().get("Summary." + core + ".'Alfresco Transactions in Index'"); - Assert.assertTrue(reportTxCount > 0); + Assert.assertTrue(reportTxCount > 0, "Expecting a positive integer in Summary." + core + ".'Alfresco Transactions in Index',"); + }); } @@ -402,11 +406,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("summary"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); Integer reportTxCount = response.getResponse().body().jsonPath().get("Summary." + core + ".'Alfresco Transactions in Index'"); - Assert.assertTrue(reportTxCount > 0); + Assert.assertTrue(reportTxCount > 0, "Expecting a positive integer in Summary." + core + ".'Alfresco Transactions in Index',"); } catch (Exception e) { @@ -425,10 +428,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("check"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); } @@ -445,10 +447,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("check"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); } catch (Exception e) @@ -471,11 +472,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("rangeCheck"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String expand = response.getResponse().body().jsonPath().get("expand").toString(); - Assert.assertEquals(expand, "-1"); + Integer expand = response.getResponse().body().jsonPath().get("expand"); + Assert.assertEquals(expand, Integer.valueOf(-1), "Expansion is not allowed when not using Shard DB_ID_RANGE method,"); } /** @@ -489,11 +489,10 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + coreName).withSolrAdminAPI().getAction("rangeCheck"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String expand = response.getResponse().body().jsonPath().get("expand").toString(); - Assert.assertNotEquals(expand, "-1"); + Integer expand = response.getResponse().body().jsonPath().get("expand"); + Assert.assertNotEquals(expand, Integer.valueOf(-1), "Expansion is a positive number when using Shard DB_ID_RANGE method,"); } /** @@ -509,12 +508,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + coreName, "add=" + add).withSolrAdminAPI().getAction("expand"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); // This action only applies to DB_ID_RANGE Sharding method - String expand = response.getResponse().body().jsonPath().get("expand").toString(); - Assert.assertEquals(expand, "-1"); + Integer expand = response.getResponse().body().jsonPath().get("expand"); + Assert.assertEquals(expand, Integer.valueOf(-1), "Expansion is not allowed when not using Shard DB_ID_RANGE method,"); } /** @@ -529,12 +527,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + coreName, "add=" + add).withSolrAdminAPI().getAction("expand"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); // This action only applies to DB_ID_RANGE Sharding method - String expand = response.getResponse().body().jsonPath().get("expand").toString(); - Assert.assertNotEquals(expand, "-1"); + Integer expand = response.getResponse().body().jsonPath().get("expand"); + Assert.assertNotEquals(expand, Integer.valueOf(-1), "Expansion is a positive number when using Shard DB_ID_RANGE method,"); } /** @@ -544,14 +541,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 24) public void testPurge() throws Exception { - String txid = "1"; + Integer txid = 1; RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("purge"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } @@ -562,7 +558,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 25) public void testPurgeCore() throws Exception { - final String txid = "1"; + final Integer txid = 1; DEFAULT_CORE_NAMES.forEach(core -> { @@ -570,10 +566,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("purge"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } catch (Exception e) @@ -593,10 +588,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("purge"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } @@ -604,20 +598,24 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest * FIX for every core. * @throws Exception */ - @Test(priority = 27) + @Test(priority = 27, dependsOnMethods = "testPurge") public void testFix() throws Exception { RestResponse response = restClient.withSolrAdminAPI().getAction("fix"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - DEFAULT_CORE_NAMES.forEach(core -> { - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); - }); + List alfrescoTxToReindex = response.getResponse().body().jsonPath().get("action.alfresco.txToReindex"); + Assert.assertEquals(alfrescoTxToReindex, Arrays.asList(1), "Expected 1 transaction to reindex, as it has been purged before,"); + List alfrescoAclToReindex = response.getResponse().body().jsonPath().get("action.alfresco.aclChangeSetToReindex"); + Assert.assertEquals(alfrescoAclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + List archiveTxToReindex = response.getResponse().body().jsonPath().get("action.archive.txToReindex"); + Assert.assertEquals(archiveTxToReindex, Arrays.asList(1), "Expected 1 transactions to reindex, as it has been purged before,"); + List archiveAclToReindex = response.getResponse().body().jsonPath().get("action.archive.aclChangeSetToReindex"); + Assert.assertEquals(archiveAclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } @@ -634,13 +632,15 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("fix"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core +".txToReindex")); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex")); + List txToReindex = response.getResponse().body().jsonPath().get("action." + core +".txToReindex"); + Assert.assertTrue(txToReindex.size() == 0 || txToReindex.size() == 1, + "Expected 0 or 1 transaction to reindex (depending on the method textFix execution (as it is asynchronous),"); + List aclToReindex = response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex"); + Assert.assertEquals(aclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } catch (Exception e) @@ -658,14 +658,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 29) public void testReindex() throws Exception { - String txid = "1"; + Integer txid = 1; RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("reindex"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } @@ -676,7 +675,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 30) public void testReindexCore() throws Exception { - String txid = "1"; + Integer txid = 1; DEFAULT_CORE_NAMES.forEach(core -> { @@ -684,10 +683,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("reindex"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } catch (Exception e) @@ -707,15 +705,14 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("retry"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); DEFAULT_CORE_NAMES.forEach(core -> { - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + List errorNodeList = response.getResponse().body().jsonPath().get("action." + core); + Assert.assertEquals(errorNodeList, Arrays.asList(), "Expected no error nodes,"); }); } @@ -732,14 +729,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core).withSolrAdminAPI().getAction("retry"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); - Assert.assertNotNull(response.getResponse().body().jsonPath().get("action." + core)); + List errorNodeList = response.getResponse().body().jsonPath().get("action." + core); + Assert.assertEquals(errorNodeList, Arrays.asList(), "Expected no error nodes,"); } catch (Exception e) { @@ -756,14 +752,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 33) public void testIndex() throws Exception { - String txid = "1"; + Integer txid = 1; RestResponse response = restClient.withParams("txid=" + txid).withSolrAdminAPI().getAction("index"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } @@ -774,7 +769,7 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest @Test(priority = 34) public void testIndexCore() throws Exception { - final String txid = "1"; + final Integer txid = 1; DEFAULT_CORE_NAMES.forEach(core -> { @@ -782,10 +777,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("core=" + core, "txid=" + txid).withSolrAdminAPI().getAction("index"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); } catch (Exception e) @@ -805,10 +799,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("log4j"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); } @@ -821,10 +814,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withParams("resource=log4j-unexisting.properties").withSolrAdminAPI().getAction("log4j"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "error"); } @@ -842,14 +834,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core, "storeRef=" + storeRef, "template=" + template) .withSolrAdminAPI().getAction("newCore"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); - String actionCore = response.getResponse().body().jsonPath().get("action.core").toString(); - Assert.assertEquals(core, actionCore); + String actionCore = response.getResponse().body().jsonPath().get("action.core"); + Assert.assertEquals(actionCore, core, "Created core name is expected in action.core,"); } /** @@ -865,10 +856,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core, "template=" + template) .withSolrAdminAPI().getAction("newCore"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "error"); } @@ -883,10 +873,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction("updateCore"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); } @@ -901,10 +890,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core).withSolrAdminAPI().getAction("updateCore"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "error"); } @@ -917,10 +905,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest { RestResponse response = restClient.withSolrAdminAPI().getAction("updateShared"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); } @@ -939,14 +926,13 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest .withParams("coreName=" + core, "storeRef=" + storeRef, "template=" + template) .withSolrAdminAPI().getAction("newDefaultIndex"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "success"); - String actionCore = response.getResponse().body().jsonPath().get("action.core").toString(); - Assert.assertEquals(core, actionCore); + String actionCore = response.getResponse().body().jsonPath().get("action.core"); + Assert.assertEquals(actionCore, core, "Created core name is expected in action.core,"); } /** @@ -962,10 +948,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest RestResponse response = restClient.withParams("coreName=" + core, "template=" + template) .withSolrAdminAPI().getAction("newDefaultIndex"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); - String actionStatus = response.getResponse().body().jsonPath().get("action.status").toString(); + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "error"); } @@ -982,8 +967,11 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest .withParams("coreName=" + core, "storeRef=" + storeRef) .withSolrAdminAPI().getAction("removeCore"); - String status = response.getResponse().body().jsonPath().get("responseHeader.status").toString(); - Assert.assertEquals(status, SOLR_RESPONSE_STATUS_OK); + checkResponseStatusOk(response); + + String actionStatus = response.getResponse().body().jsonPath().get("action.status"); + Assert.assertEquals(actionStatus, "success"); + } } From 37242ac1bb629af409d676736fa2daf2b1fe8703 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 18:29:31 +0100 Subject: [PATCH 38/94] As some other tests have been run before SOLR Admin ones, the expected transactions and ACLs to reindex can't be predicted. Enough to check that a list is returned by fix methods, but ignoring the size of this list. --- .../solr/admin/SolrE2eAdminTest.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java index 143860ca1..91060b11a 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/solr/admin/SolrE2eAdminTest.java @@ -605,15 +605,12 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest checkResponseStatusOk(response); - List alfrescoTxToReindex = response.getResponse().body().jsonPath().get("action.alfresco.txToReindex"); - Assert.assertEquals(alfrescoTxToReindex, Arrays.asList(1), "Expected 1 transaction to reindex, as it has been purged before,"); - List alfrescoAclToReindex = response.getResponse().body().jsonPath().get("action.alfresco.aclChangeSetToReindex"); - Assert.assertEquals(alfrescoAclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); - - List archiveTxToReindex = response.getResponse().body().jsonPath().get("action.archive.txToReindex"); - Assert.assertEquals(archiveTxToReindex, Arrays.asList(1), "Expected 1 transactions to reindex, as it has been purged before,"); - List archiveAclToReindex = response.getResponse().body().jsonPath().get("action.archive.aclChangeSetToReindex"); - Assert.assertEquals(archiveAclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); + DEFAULT_CORE_NAMES.forEach(core -> { + List txToReindex = response.getResponse().body().jsonPath().get("action." + core +".txToReindex"); + Assert.assertTrue(txToReindex.size() >= 0, "Expected a list of transactions (or empty list) to be reindexed,"); + List aclToReindex = response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex"); + Assert.assertTrue(aclToReindex.size() >= 0, "Expected a list of ACLs (or empty list) to be reindexed,"); + }); String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); @@ -635,10 +632,9 @@ public class SolrE2eAdminTest extends AbstractE2EFunctionalTest checkResponseStatusOk(response); List txToReindex = response.getResponse().body().jsonPath().get("action." + core +".txToReindex"); - Assert.assertTrue(txToReindex.size() == 0 || txToReindex.size() == 1, - "Expected 0 or 1 transaction to reindex (depending on the method textFix execution (as it is asynchronous),"); + Assert.assertTrue(txToReindex.size() >= 0, "Expected a list of transactions (or empty list) to be reindexed,"); List aclToReindex = response.getResponse().body().jsonPath().get("action." + core + ".aclChangeSetToReindex"); - Assert.assertEquals(aclToReindex, Arrays.asList(), "Expected no ACL to reindex,"); + Assert.assertTrue(aclToReindex.size() >= 0, "Expected a list of ACLs (or empty list) to be reindexed,"); String actionStatus = response.getResponse().body().jsonPath().get("action.status"); Assert.assertEquals(actionStatus, "scheduled"); From ab1636980e9ec2a712b46c0a1994996f3400dcaa Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 18:37:58 +0100 Subject: [PATCH 39/94] Fix unit tests. --- .../alfresco/solr/AlfrescoCoreAdminHandlerIT.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java index 6703bdde5..8369db35d 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java @@ -315,24 +315,27 @@ public class AlfrescoCoreAdminHandlerIT verify(rsp).add(eq("report"), any(NamedList.class)); } - /** Check that when the transaction id is missing we get an exception. */ - @Test(expected = SolrException.class) + /** Check that when the transaction id is missing we get an error message. */ + @Test public void handleCustomActionTXReportMissingTXId() { when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT); alfrescoCoreAdminHandler.handleCustomAction(req, rsp); - verify(rsp, never()).add(anyString(), any()); + verify(rsp).add(eq("report"), any(NamedList.class)); } - /** Check that when the core name is missing we get an exception. */ - @Test(expected = SolrException.class) + /** Check that when the core name is missing we get a report for every core. */ + @Test public void handleCustomActionTXReportMissingCoreName() { when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT); when(params.get(CoreAdminParams.CORE)).thenReturn(null); alfrescoCoreAdminHandler.handleCustomAction(req, rsp); + + // Check that a report was generated (don't look at the contents of the report though). + verify(rsp).add(eq("report"), any(NamedList.class)); } /** Check that when an unknown action is provided we don't generate a report. */ From 223da01b6b729edbd8e5853aef76618c270957e7 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 13 Feb 2020 19:43:34 +0100 Subject: [PATCH 40/94] Remove unnecessary code from unit test. --- .../solr/AlfrescoCoreAdminHandlerIT.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java index 8369db35d..83abaec9b 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoCoreAdminHandlerIT.java @@ -290,23 +290,6 @@ public class AlfrescoCoreAdminHandlerIT when(params.get(CoreAdminParams.ACTION)).thenReturn(TXREPORT); when(params.get(CoreAdminParams.CORE)).thenReturn(CORE_NAME); when(params.get(ARG_TXID)).thenReturn(TX_ID); - // Set up the mock ACL tracker. - when(trackerRegistry.getTrackerForCore(CORE_NAME, AclTracker.class)).thenReturn(aclTracker); - when(aclTracker.checkIndex(Long.valueOf(TX_ID), 0L, null, null)).thenReturn(indexHealthReport); - when(indexHealthReport.getDuplicatedAclTxInIndex()).thenReturn(iOpenBitSet); - when(indexHealthReport.getAclTxInIndexButNotInDb()).thenReturn(iOpenBitSet); - when(indexHealthReport.getMissingAclTxFromIndex()).thenReturn(iOpenBitSet); - when(aclTracker.getTrackerState()).thenReturn(trackerState); - // Set up the mock metadata tracker. - when(trackerRegistry.getTrackerForCore(CORE_NAME, MetadataTracker.class)).thenReturn(metadataTracker); - when(metadataTracker.checkIndex(Long.valueOf(TX_ID), 0L, null, null)).thenReturn(metaReport); - when(metaReport.getDuplicatedTxInIndex()).thenReturn(iOpenBitSet); - when(metaReport.getTxInIndexButNotInDb()).thenReturn(iOpenBitSet); - when(metaReport.getMissingTxFromIndex()).thenReturn(iOpenBitSet); - when(metaReport.getDuplicatedLeafInIndex()).thenReturn(iOpenBitSet); - when(metaReport.getDuplicatedErrorInIndex()).thenReturn(iOpenBitSet); - when(metaReport.getDuplicatedUnindexedInIndex()).thenReturn(iOpenBitSet); - when(metadataTracker.getTrackerState()).thenReturn(trackerState); // Call the method under test. alfrescoCoreAdminHandler.handleCustomAction(req, rsp); From 74f1ded7c84f84e74d0ea5d5845b2aae23392072 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 14 Feb 2020 10:49:10 +0000 Subject: [PATCH 41/94] SEARCH-1681 adding more assertion messages and removing test group for test --- .../searchServices/search/ShardInfoTest.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 6d7fd4388..e51f9326b 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -44,7 +44,7 @@ import org.springframework.http.HttpStatus; public class ShardInfoTest extends AbstractE2EFunctionalTest { /* The test that will be excluded when running master slave setup, excluding the ASS_MASTER test group. */ - @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER, TestGroup.EXPLICIT_SHARDING }) + @Test(groups = { TestGroup.ACS_60n, TestGroup.ASS_MASTER }) public void getShardInfoWithAdminAuthority() throws JsonProcessingException { RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI() @@ -151,7 +151,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest List entries = info.getEntries(); Set actualStores = entries.stream().map(shardInfoModel -> shardInfoModel.getModel().getStores()).collect(Collectors.toSet()); - assertEquals(actualStores, stores); + assertEquals(actualStores, stores, "The number of stores do not match the expected number of stores"); for (RestShardInfoModel shardInfoModel : entries) { @@ -166,13 +166,13 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(shardingMethods.contains(shardingMethod), "Unexpected Sharding Method Found: " + shardingMethod); List shards = model.getShards(); - assertNotNull(shards); + assertNotNull(shards, "There are no shards present"); for (RestShardModel shardInstance : shards) { List instanceList = shardInstance.getInstances(); for (RestInstanceModel instanceX : instanceList) { - assertTrue(baseUrls.contains(instanceX.getBaseUrl())); + assertTrue(baseUrls.contains(instanceX.getBaseUrl()), "The baseUrl is not present"); assertEquals(instanceX.getState(), "ACTIVE", "Shard state is not ACTIVE, shard state is: " + instanceX.getState()); assertNotNull(instanceX.getPort(), "There is not port found for the instance"); assertEquals(instanceX.getMode(), "MASTER", "Mode is not MASTER, mode found: "+ instanceX.getMode()); @@ -181,16 +181,13 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest switch (shardingMethod) { case "MOD_ACL_ID": - //No additional checks required break; case "ACL_ID": - //No additional checks required break; case "DB_ID": - //No additional checks required break; case "DB_ID_RANGE": - //To be commented out once the shard.range is visible on the sharding screen and if wanted + //https://issues.alfresco.com/jira/browse/SEARCH-2110 (once done can be umcommented) //assertEquals(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); break; case "DATE": From cbef1d6c6029b3c27dc282d6376db64a674a0b5c Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 14 Feb 2020 12:02:52 +0000 Subject: [PATCH 42/94] SEARCH-1681 altering comments and assertion messages --- .../functional/searchServices/search/ShardInfoTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index e51f9326b..8e6ccc940 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -172,7 +172,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest List instanceList = shardInstance.getInstances(); for (RestInstanceModel instanceX : instanceList) { - assertTrue(baseUrls.contains(instanceX.getBaseUrl()), "The baseUrl is not present"); + assertTrue(baseUrls.contains(instanceX.getBaseUrl()), "The baseUrl is not present, baseUrl found is: " + instanceX.getBaseUrl()); assertEquals(instanceX.getState(), "ACTIVE", "Shard state is not ACTIVE, shard state is: " + instanceX.getState()); assertNotNull(instanceX.getPort(), "There is not port found for the instance"); assertEquals(instanceX.getMode(), "MASTER", "Mode is not MASTER, mode found: "+ instanceX.getMode()); @@ -187,7 +187,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest case "DB_ID": break; case "DB_ID_RANGE": - //https://issues.alfresco.com/jira/browse/SEARCH-2110 (once done can be umcommented) + // TODO: Uncomment the following assert when fixed: https://issues.alfresco.com/jira/browse/SEARCH-2110 //assertEquals(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); break; case "DATE": From f578b92592f9fcb03684e3faee5a19cab3eb0e2f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:12:51 +0000 Subject: [PATCH 43/94] Bump restapi from 1.31 to 1.33 in /e2e-test Bumps [restapi](https://github.com/Alfresco/alfresco-tas-restapi) from 1.31 to 1.33. - [Release notes](https://github.com/Alfresco/alfresco-tas-restapi/releases) - [Commits](https://github.com/Alfresco/alfresco-tas-restapi/compare/v1.31...v1.33) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index b591be7ff..197a51181 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,7 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.31 + 1.33 1.13 3.0.19 3.3.0.1 From 9b988a73a1acbdcf7120dcc3b11dd1f6b2e03234 Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 18 Feb 2020 08:49:50 +0000 Subject: [PATCH 44/94] SEARCH-2078 fix for getShardInfoWithAdminAuthority --- .../functional/searchServices/search/ShardInfoTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 8e6ccc940..3e5cca579 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -62,7 +62,9 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest RestShardInfoModel model = shardInfoModel.getModel(); assertEquals(model.getTemplate(), "rerank"); assertEquals(model.getMode(), "MASTER"); - assertEquals(model.getShardMethod(), "DB_ID"); + List shardingMethods = Arrays.asList("DB_ID", "DB_ID_RANGE", "EXPLICIT_ID", "ACL_ID", "MOD_ACL_ID", "DATE", "PROPERTY"); + String shardingMethod = model.getShardMethod(); + assertTrue(shardingMethods.contains(shardingMethod), "Unexpected Sharding Method Found: " + shardingMethod); assertTrue(model.getHasContent()); assertTrue(stores.contains(model.getStores())); @@ -79,7 +81,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(baseUrls.contains(instance.getBaseUrl())); // TODO: Ideally Solr Host and Port should be Parameterised - assertEquals(instance.getHost(), "search"); + assertEquals(instance.getHost(), "solr6secondary"); assertEquals(instance.getPort().intValue(), 8983); assertEquals(instance.getState(), "ACTIVE"); assertEquals(instance.getMode(), "MASTER"); From ecc67b28474dc52c4c5c62322fea1add7f03393b Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 18 Feb 2020 09:38:31 +0000 Subject: [PATCH 45/94] SEARCH-2078 fix for getShardInfoWithAdminAuthority --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 3e5cca579..e61d0c088 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -81,7 +81,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(baseUrls.contains(instance.getBaseUrl())); // TODO: Ideally Solr Host and Port should be Parameterised - assertEquals(instance.getHost(), "solr6secondary"); + assertEquals(instance.getHost(), "search"); assertEquals(instance.getPort().intValue(), 8983); assertEquals(instance.getState(), "ACTIVE"); assertEquals(instance.getMode(), "MASTER"); From d33e5834c37a8fe875ba82d3c64ffe85f2a03c1a Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 18 Feb 2020 10:57:42 +0100 Subject: [PATCH 46/94] SEARCH-2112: When transactions are out of Shard range, only the latest transaction needs to be indexed in order to preserve the state up-to-date of the MetadataTracker --- .../solr/tracker/MetadataTracker.java | 39 +++++++++++++------ .../alfresco/solr/client/SOLRAPIClient.java | 2 +- .../alfresco/solr/client/Transactions.java | 2 +- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index dd8c92bfe..9ba07de17 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -20,6 +20,7 @@ package org.alfresco.solr.tracker; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; @@ -32,7 +33,6 @@ import org.alfresco.repo.index.shard.ShardState; import org.alfresco.solr.BoundedDeque; import org.alfresco.solr.InformationServer; import org.alfresco.solr.NodeReport; -import org.alfresco.solr.SolrInformationServer; import org.alfresco.solr.TrackerState; import org.alfresco.solr.adapters.IOpenBitSet; import org.alfresco.solr.client.GetNodesParameters; @@ -716,6 +716,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker // When using DB_ID_RANGE, fromCommitTime cannot be before the commit time of the first transaction // for the DB_ID_RANGE to be indexed and commit time of the last transaction cannot be lower than fromCommitTime. // When there isn't nodes in that range, -1 is returned as commit times + boolean shardOutOfRange = false; if (docRouter instanceof DBIDRangeRouter && txIntervalCommitTimeServiceAvailable) { @@ -728,23 +729,24 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker // Node Range it's not still available in repository if (shardMinCommitTime == -1) { - log.debug("#### [DB_ID_RANGE] No nodes in range [" + dbIdRangeRouter.getStartRange() + "-" - + dbIdRangeRouter.getEndRange() + "] " - + "exist in the repository. Skipping metadata tracking."); - return; + log.debug( + "#### [DB_ID_RANGE] No nodes in range [{}-{}] " + + "exist in the repository. Indexing only latest transaction.", + dbIdRangeRouter.getStartRange(), dbIdRangeRouter.getEndRange()); + shardOutOfRange = true; } if (fromCommitTime > shardMaxCommitTime) { - log.debug("#### [DB_ID_RANGE] Last commit time is greater that max commit time in in range [" - + dbIdRangeRouter.getStartRange() + "-" + dbIdRangeRouter.getEndRange() + "]. " - + "Skipping metadata tracking."); - return; + log.debug("#### [DB_ID_RANGE] Last commit time is greater that max commit time in in range [{}-{}]. " + + "Indexing only latest transaction.", + dbIdRangeRouter.getStartRange(), dbIdRangeRouter.getEndRange()); + shardOutOfRange = true; } // Initial commit time for Node Range is greater than calculated from commit time if (fromCommitTime < shardMinCommitTime) { - log.debug("#### [DB_ID_RANGE] SKIPPING TRANSACTIONS FROM " + fromCommitTime + " TO " - + shardMinCommitTime); + log.debug("#### [DB_ID_RANGE] Skipping transactions from {} to {}", + fromCommitTime, shardMinCommitTime); fromCommitTime = shardMinCommitTime; } } @@ -752,6 +754,21 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker log.debug("#### Get txn from commit time: " + fromCommitTime); transactions = getSomeTransactions(txnsFound, fromCommitTime, TIME_STEP_1_HR_IN_MS, 2000, state.getTimeToStopIndexing()); + + + // When transactions are out of Shard range, only the latest transaction needs to be indexed + // in order to preserve the state up-to-date of the MetadataTracker + if (shardOutOfRange) + { + Transaction latestTransaction = new Transaction(); + latestTransaction.setCommitTimeMs(transactions.getMaxTxnCommitTime()); + latestTransaction.setId(transactions.getMaxTxnId()); + transactions = new Transactions( + Arrays.asList(latestTransaction), + transactions.getMaxTxnCommitTime(), + transactions.getMaxTxnId()); + log.debug("#### [DB_ID_RANGE] Latest transaction to be indexed {}", latestTransaction); + } setLastTxCommitTimeAndTxIdInTrackerState(transactions, state); diff --git a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClient.java b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClient.java index 1556f7cb6..fdf580d44 100644 --- a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClient.java +++ b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/SOLRAPIClient.java @@ -1254,7 +1254,7 @@ public class SOLRAPIClient } /** - * Returns the minimum and the maximum commit time for transactions in a node id range. + * Returns the next commit time from a given commit time. * * @param coreName alfresco, archive * @param fromCommitTime initial transaction commit time diff --git a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/Transactions.java b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/Transactions.java index 1b022a925..ad7bdddbf 100644 --- a/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/Transactions.java +++ b/search-services/alfresco-solrclient-lib/src/main/java/org/alfresco/solr/client/Transactions.java @@ -39,7 +39,7 @@ public class Transactions private Long maxTxnId; - Transactions(List transactions, Long maxTxnCommitTime, Long maxTxnId) + public Transactions(List transactions, Long maxTxnCommitTime, Long maxTxnId) { this.transactions = transactions; this.maxTxnCommitTime = maxTxnCommitTime; From bf17b980da0741a1670b34f5b9156e019b118f93 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 18 Feb 2020 11:55:55 +0100 Subject: [PATCH 47/94] SEARCH-2112: On Shards configured with DB_ID_RANGE, the first indexed transaction can be different from the first transaction in the repository --- .../solr/tracker/MetadataTracker.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 9ba07de17..763678a3a 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -255,7 +255,30 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker if (!state.isCheckedFirstTransactionTime()) { - firstTransactions = client.getTransactions(null, 0L, null, Long.MAX_VALUE, 1); + + // On Shards configured with DB_ID_RANGE, the first indexed transaction can be + // different from the first transaction in the repository as some transactions + // are skipped if they are not related with the range of the Shard. + // Getting the minCommitTime for the Shard is enough in order to check + // that the first transaction is present. + long minCommitTime = 0l; + if (docRouter instanceof DBIDRangeRouter && txIntervalCommitTimeServiceAvailable) + { + try + { + DBIDRangeRouter dbIdRangeRouter = (DBIDRangeRouter) docRouter; + Pair commitTimes = client.getTxIntervalCommitTime(coreName, + dbIdRangeRouter.getStartRange(), dbIdRangeRouter.getEndRange()); + minCommitTime = commitTimes.getFirst(); + } + catch (NoSuchMethodException e) + { + log.warn("txIntervalCommitTimeServiceAvailable is not available. If you are using DB_ID_RANGE shard method, " + + "upgrade your ACS Repository version in order to use this feature: {} ", e.getMessage()); + } + } + + firstTransactions = client.getTransactions(minCommitTime, 0L, null, Long.MAX_VALUE, 1); if (!firstTransactions.getTransactions().isEmpty()) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); From 61faf9ab2d8afd832a617700fe67958f58ff8133 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 18 Feb 2020 15:55:13 +0100 Subject: [PATCH 48/94] Describe skip transactions feature for logging. --- .../main/java/org/alfresco/solr/tracker/MetadataTracker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 763678a3a..7c00a936c 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -140,7 +140,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker catch (NoSuchMethodException e) { log.warn("txIntervalCommitTimeServiceAvailable is not available. If you are using DB_ID_RANGE shard method, " - + "upgrade your ACS Repository version in order to use this feature: {} ", e.getMessage()); + + "upgrade your ACS Repository version in order to use the skip transactions feature: {} ", e.getMessage()); } catch (Exception e) { @@ -274,7 +274,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker catch (NoSuchMethodException e) { log.warn("txIntervalCommitTimeServiceAvailable is not available. If you are using DB_ID_RANGE shard method, " - + "upgrade your ACS Repository version in order to use this feature: {} ", e.getMessage()); + + "upgrade your ACS Repository version in order to use the skip transactions feature: {} ", e.getMessage()); } } From f93e979ed903146c19d98ae6bec8891070a49ca3 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Wed, 19 Feb 2020 11:43:11 +0100 Subject: [PATCH 49/94] SEARCH-2117: Revert limit to 2000l for checking first transactions in database when checking the index and fix Integration Test. --- .../java/org/alfresco/solr/tracker/MetadataTracker.java | 8 ++++---- .../test/java/org/alfresco/solr/AlfrescoSolrUtils.java | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 7c00a936c..9fde7061f 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -243,7 +243,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker state.setCheckedFirstTransactionTime(true); log.info("No transactions found - no verification required"); - firstTransactions = client.getTransactions(null, 0L, null, Long.MAX_VALUE, 1); + firstTransactions = client.getTransactions(null, 0L, null, 2000l, 1); if (!firstTransactions.getTransactions().isEmpty()) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); @@ -278,7 +278,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker } } - firstTransactions = client.getTransactions(minCommitTime, 0L, null, Long.MAX_VALUE, 1); + firstTransactions = client.getTransactions(minCommitTime, 0L, null, 2000l, 1); if (!firstTransactions.getTransactions().isEmpty()) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); @@ -311,7 +311,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker { if (firstTransactions == null) { - firstTransactions = client.getTransactions(null, 0L, null, Long.MAX_VALUE, 1); + firstTransactions = client.getTransactions(null, 0L, null, 2000l, 1); } setLastTxCommitTimeAndTxIdInTrackerState(firstTransactions, state); @@ -1147,7 +1147,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker { // DB TX Count long firstTransactionCommitTime = 0; - Transactions firstTransactions = client.getTransactions(null, 0L, null, Long.MAX_VALUE, 1); + Transactions firstTransactions = client.getTransactions(null, 0L, null, 2000l, 1); if(firstTransactions.getTransactions().size() > 0) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java index d8c65469b..db82478b7 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java @@ -127,7 +127,10 @@ public class AlfrescoSolrUtils long txnCommitTime = System.currentTimeMillis(); Transaction transaction = new Transaction(); transaction.setCommitTimeMs(txnCommitTime); - transaction.setId(generateId()); + // A safer number for a transaction Id should be in [1-2000] range, + // so this is the range accepted for the starting transaction number + // on a SOLR Core + transaction.setId(RANDOMIZER.nextInt(2000) + 1); transaction.setDeletes(deletes); transaction.setUpdates(updates); return transaction; From 92edfc5999df1477b6f9fac2e275452ff1be64ef Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Wed, 19 Feb 2020 14:50:41 +0100 Subject: [PATCH 50/94] SEARCH-2117: Fix integration test approach, setting explicitly a [1..2000] txnId when checkCore is required. --- .../test/java/org/alfresco/solr/AlfrescoSolrUtils.java | 8 ++++---- .../tracker/DistributedAlfrescoSolrTrackerRaceIT.java | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java index db82478b7..92f73d41b 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AlfrescoSolrUtils.java @@ -118,6 +118,9 @@ public class AlfrescoSolrUtils /** * Get transaction. + * When getting an unique transaction for a test, don't use this constructors. + * As this produces a number that can be out of the range [1-2000], that is + * the one checked by the SOLR Core to find the initial transaction is right. * @param deletes * @param updates * @return {@link Transaction} @@ -127,10 +130,7 @@ public class AlfrescoSolrUtils long txnCommitTime = System.currentTimeMillis(); Transaction transaction = new Transaction(); transaction.setCommitTimeMs(txnCommitTime); - // A safer number for a transaction Id should be in [1-2000] range, - // so this is the range accepted for the starting transaction number - // on a SOLR Core - transaction.setId(RANDOMIZER.nextInt(2000) + 1); + transaction.setId(generateId()); transaction.setDeletes(deletes); transaction.setUpdates(updates); return transaction; diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerRaceIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerRaceIT.java index 764dd1237..9d7283a1b 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerRaceIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerRaceIT.java @@ -84,7 +84,8 @@ public class DistributedAlfrescoSolrTrackerRaceIT extends AbstractAlfrescoDistri AclReaders aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null); AclReaders aclReaders2 = getAclReaders(aclChangeSet, acl2, singletonList("jim"), singletonList("phil"), null); - Transaction txn = getTransaction(0, 2); + // Transaction between [1-2000] is required, when greater value checking the core will fail + Transaction txn = getTransaction(0, 2, 1); long txnCommitTimeMs = txn.getCommitTimeMs(); // Subtract from the commit time to go beyond hole retention From 0ccc0140f17065bdb19a3a9491416495853d9a83 Mon Sep 17 00:00:00 2001 From: sridharvellingiri Date: Wed, 19 Feb 2020 16:26:03 +0000 Subject: [PATCH 51/94] SEARCH-2072 Configure Master-Slave docker-compose --- search-services/packaging/src/docker/6.x/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/packaging/src/docker/6.x/docker-compose.yml b/search-services/packaging/src/docker/6.x/docker-compose.yml index b875f4640..13b5861e9 100644 --- a/search-services/packaging/src/docker/6.x/docker-compose.yml +++ b/search-services/packaging/src/docker/6.x/docker-compose.yml @@ -54,7 +54,7 @@ services: - 5432:5432 search: - image: quay.io/alfresco/insight-engine:${SEARCH_TAG} + image: quay.io/alfresco/search-services:${SEARCH_TAG} environment: #Replication properties # - REPLICATION_TYPE=master From 227f1f0c4cc1d3f4d9237c3327bf42306d297651 Mon Sep 17 00:00:00 2001 From: sridharvellingiri Date: Wed, 19 Feb 2020 16:41:24 +0000 Subject: [PATCH 52/94] SEARCH-2072 Change in env values --- .../src/docker/6.x/master-slave/docker-compose.slave.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml b/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml index 93671b382..4adf22758 100644 --- a/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml +++ b/search-services/packaging/src/docker/6.x/master-slave/docker-compose.slave.yml @@ -34,7 +34,7 @@ services: # Insight Engine or Search Services search: - image: quay.io/alfresco/search-services:test + image: quay.io/alfresco/search-services:${SEARCH_TAG} environment: #Solr needs to know how to register itself with Alfresco - REPLICATION_TYPE=master From f9c5aba689a7063d4b9d542e1dc0ee376f050bf9 Mon Sep 17 00:00:00 2001 From: sridharvellingiri Date: Thu, 20 Feb 2020 09:33:22 +0000 Subject: [PATCH 53/94] SEARCH-2072 Notes added to manual fix for SEARCH-2085 issue --- search-services/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/search-services/README.md b/search-services/README.md index ec41b57c5..0d683a32d 100644 --- a/search-services/README.md +++ b/search-services/README.md @@ -449,6 +449,9 @@ This will start up Alfresco, Postgres, Share and SearchServices. You can access * Solr: http://localhost:8083/solr * Solr-slave: http://localhost:8084/solr +Note: Once deployed and all services up and running, goto . Scroll down and click save button. +This is the bug which currently working on [SEARCH-2085](https://issues.alfresco.com/jira/browse/SEARCH-2085) + If you start version 5.x instead you can also access the API Explorer: * API Explorer: http://localhost:8084/api-explorer From bf9c07c87defad8e8b7be645a5b7b889338df47b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 21 Feb 2020 22:14:28 +0000 Subject: [PATCH 54/94] Bump mockito-core from 3.2.4 to 3.3.0 in /search-services Bumps [mockito-core](https://github.com/mockito/mockito) from 3.2.4 to 3.3.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v3.2.4...v3.3.0) Signed-off-by: dependabot-preview[bot] --- search-services/alfresco-search/pom.xml | 2 +- search-services/alfresco-solrclient-lib/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/search-services/alfresco-search/pom.xml b/search-services/alfresco-search/pom.xml index 2e37b62de..fa8b7d7b8 100644 --- a/search-services/alfresco-search/pom.xml +++ b/search-services/alfresco-search/pom.xml @@ -168,7 +168,7 @@ org.mockito mockito-core - 3.2.4 + 3.3.0 test diff --git a/search-services/alfresco-solrclient-lib/pom.xml b/search-services/alfresco-solrclient-lib/pom.xml index 11bd9ea0c..b0a866644 100644 --- a/search-services/alfresco-solrclient-lib/pom.xml +++ b/search-services/alfresco-solrclient-lib/pom.xml @@ -67,7 +67,7 @@ org.mockito mockito-core - 3.2.4 + 3.3.0 test From 1e271559ca9728b7d1e4fb8c625592a83c2f05a2 Mon Sep 17 00:00:00 2001 From: Keerat Date: Mon, 24 Feb 2020 08:21:53 +0000 Subject: [PATCH 55/94] SEARCH-1681 Tests fixes when in a sharded mode --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- .../functional/searchServices/search/StatsSearchTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index e61d0c088..0d28bbb77 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -81,7 +81,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(baseUrls.contains(instance.getBaseUrl())); // TODO: Ideally Solr Host and Port should be Parameterised - assertEquals(instance.getHost(), "search"); + assertNotNull(instance.getHost()); assertEquals(instance.getPort().intValue(), 8983); assertEquals(instance.getState(), "ACTIVE"); assertEquals(instance.getMode(), "MASTER"); diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java index fc48b425f..e998d5b4c 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java @@ -322,7 +322,7 @@ public class StatsSearchTest extends AbstractSearchServicesE2ETest 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); + facetResponseModel.assertThat().field("label").contains(label); RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0); List metrics = bucket.getMetrics(); assertEquals(metrics.size(),metricsCount); From a043c474d236ecd45d550b47b11c1977955499a3 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Mon, 24 Feb 2020 09:41:38 +0100 Subject: [PATCH 56/94] SEARCH-2112: When using Shard DB_ID_RANGE method, check firstTransaction only when Shard is not empty. --- .../solr/tracker/MetadataTracker.java | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 7c00a936c..857169bab 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -278,30 +278,35 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker } } - firstTransactions = client.getTransactions(minCommitTime, 0L, null, Long.MAX_VALUE, 1); - if (!firstTransactions.getTransactions().isEmpty()) - { - Transaction firstTransaction = firstTransactions.getTransactions().get(0); - long firstTxId = firstTransaction.getId(); - long firstTransactionCommitTime = firstTransaction.getCommitTimeMs(); - int setSize = this.infoSrv.getTxDocsSize(""+firstTxId, ""+firstTransactionCommitTime); - - if (setSize == 0) + // When a Shard with DB_ID_RANGE method is empty, minCommitTime is -1. + // No firstTransaction checking is required for this case. + if (minCommitTime != -1l) { + + firstTransactions = client.getTransactions(minCommitTime, 0L, null, 2000l, 1); + if (!firstTransactions.getTransactions().isEmpty()) { - log.error("First transaction was not found with the correct timestamp."); - log.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); - log.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); - log.error("You can also check your SOLR connection details in solrcore.properties."); - throw new AlfrescoRuntimeException("Initial transaction not found with correct timestamp"); - } - else if (setSize == 1) - { - state.setCheckedFirstTransactionTime(true); - log.info("Verified first transaction and timestamp in index"); - } - else - { - log.warn("Duplicate initial transaction found with correct timestamp"); + Transaction firstTransaction = firstTransactions.getTransactions().get(0); + long firstTxId = firstTransaction.getId(); + long firstTransactionCommitTime = firstTransaction.getCommitTimeMs(); + int setSize = this.infoSrv.getTxDocsSize(""+firstTxId, ""+firstTransactionCommitTime); + + if (setSize == 0) + { + log.error("First transaction was not found with the correct timestamp."); + log.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); + log.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); + log.error("You can also check your SOLR connection details in solrcore.properties."); + throw new AlfrescoRuntimeException("Initial transaction not found with correct timestamp"); + } + else if (setSize == 1) + { + state.setCheckedFirstTransactionTime(true); + log.info("Verified first transaction and timestamp in index"); + } + else + { + log.warn("Duplicate initial transaction found with correct timestamp"); + } } } } From c92bffab9c1d6be7df4d95e223e2918141151939 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Mon, 24 Feb 2020 12:29:03 +0100 Subject: [PATCH 57/94] SEARCH-2117: Added a new configuration parameter "solr.initial.transaction.range" with default value 0-2000. This can be used when database initial transaction Id is greater than 2000. --- .../solr/tracker/MetadataTracker.java | 14 +- .../noRerank/conf/solrcore.properties | 7 + .../templates/rerank/conf/solrcore.properties | 7 + ...ibutedAlfrescoSolrTrackerLargeTxnIdIT.java | 121 ++++++++++++++++++ 4 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 9fde7061f..372137ae6 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -86,6 +86,12 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker private boolean txIntervalCommitTimeServiceAvailable = false; /** Whether the cascade tracking is enabled. */ private boolean cascadeTrackerEnabled = true; + + /** + * Transaction Id range to get the first transaction in database. + * 0-2000 by default. + */ + private Pair minTxnIdRange; public MetadataTracker(final boolean isMaster, Properties p, SOLRAPIClient client, String coreName, InformationServer informationServer) @@ -111,6 +117,8 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker nodeBatchSize = Integer.parseInt(p.getProperty("alfresco.nodeBatchSize", "10")); threadHandler = new ThreadHandler(p, coreName, "MetadataTracker"); cascadeTrackerEnabled = informationServer.cascadeTrackingEnabled(); + String[] minTxninitialRangeString = p.getProperty("solr.initial.transaction.range", "0-2000").split("-"); + minTxnIdRange = new Pair(Long.valueOf(minTxninitialRangeString[0]), Long.valueOf(minTxninitialRangeString[1])); // In order to apply performance optimizations, checking the availability of Repo Web Scripts is required. // As these services are available from ACS 6.2 @@ -243,7 +251,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker state.setCheckedFirstTransactionTime(true); log.info("No transactions found - no verification required"); - firstTransactions = client.getTransactions(null, 0L, null, 2000l, 1); + firstTransactions = client.getTransactions(null, minTxnIdRange.getFirst(), null, minTxnIdRange.getSecond(), 1); if (!firstTransactions.getTransactions().isEmpty()) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); @@ -278,7 +286,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker } } - firstTransactions = client.getTransactions(minCommitTime, 0L, null, 2000l, 1); + firstTransactions = client.getTransactions(minCommitTime, minTxnIdRange.getFirst(), null, minTxnIdRange.getSecond(), 1); if (!firstTransactions.getTransactions().isEmpty()) { Transaction firstTransaction = firstTransactions.getTransactions().get(0); @@ -311,7 +319,7 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker { if (firstTransactions == null) { - firstTransactions = client.getTransactions(null, 0L, null, 2000l, 1); + firstTransactions = client.getTransactions(null, minTxnIdRange.getFirst(), null, minTxnIdRange.getSecond(), 1); } setLastTxCommitTimeAndTxIdInTrackerState(firstTransactions, state); diff --git a/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties b/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties index fab6b9e2e..189c181e0 100644 --- a/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties +++ b/search-services/alfresco-search/src/main/resources/solr/instance/templates/noRerank/conf/solrcore.properties @@ -182,6 +182,13 @@ solr.suggester.minSecsBetweenBuilds=3600 # solr.request.content.compress=false +# +# When checking repo and index consistency, first transaction is compared in both Repository and Index repositories. +# In order to get that initial transaction from database, 0-2000 range for txnId should be enough, but this parameter +# can be used when initial transaction Id is greater than 2000. +# +solr.initial.transaction.range=0-2000 + # # Limit the maximum text size of transformed content sent to the index - in bytes diff --git a/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties b/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties index d533ceb4d..1d33062d9 100644 --- a/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties +++ b/search-services/alfresco-search/src/main/resources/solr/instance/templates/rerank/conf/solrcore.properties @@ -182,6 +182,13 @@ solr.suggester.minSecsBetweenBuilds=3600 # solr.request.content.compress=false +# +# When checking repo and index consistency, first transaction is compared in both Repository and Index repositories. +# In order to get that initial transaction from database, 0-2000 range for txnId should be enough, but this parameter +# can be used when initial transaction Id is greater than 2000. +# +solr.initial.transaction.range=0-2000 + # # Limit the maximum text size of transformed content sent to the index - in bytes # diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java new file mode 100644 index 000000000..da7a5ffa8 --- /dev/null +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2005-2020 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.solr.tracker; + +import org.alfresco.repo.search.adaptor.lucene.QueryConstants; +import org.alfresco.solr.AbstractAlfrescoDistributedIT; +import org.alfresco.solr.client.Acl; +import org.alfresco.solr.client.AclChangeSet; +import org.alfresco.solr.client.AclReaders; +import org.alfresco.solr.client.Node; +import org.alfresco.solr.client.NodeMetaData; +import org.alfresco.solr.client.Transaction; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.LegacyNumericRangeQuery; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.solr.SolrTestCaseJ4; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.alfresco.solr.AlfrescoSolrUtils.ancestors; +import static org.alfresco.solr.AlfrescoSolrUtils.getAcl; +import static org.alfresco.solr.AlfrescoSolrUtils.getAclChangeSet; +import static org.alfresco.solr.AlfrescoSolrUtils.getAclReaders; +import static org.alfresco.solr.AlfrescoSolrUtils.getNode; +import static org.alfresco.solr.AlfrescoSolrUtils.getNodeMetaData; +import static org.alfresco.solr.AlfrescoSolrUtils.getTransaction; +import static org.alfresco.solr.AlfrescoSolrUtils.indexAclChangeSet; + +import java.util.Properties; + +/** + * Test environment having initial Transaction Id greater than default range 0-2000 + * @author aborroy + */ +@SolrTestCaseJ4.SuppressSSL +@LuceneTestCase.SuppressCodecs({"Appending","Lucene3x","Lucene40","Lucene41","Lucene42","Lucene43", "Lucene44", "Lucene45","Lucene46","Lucene47","Lucene48","Lucene49"}) +public class DistributedAlfrescoSolrTrackerLargeTxnIdIT extends AbstractAlfrescoDistributedIT +{ + + @BeforeClass + private static void initData() throws Throwable + { + Properties properties = new Properties(); + // Set a wider range for Initial Transaction Id + properties.put("solr.initial.transaction.range", "0-" + Long.MAX_VALUE); + initSolrServers(2, "DistributedAlfrescoSolrTrackerRaceTest", properties); + } + + @AfterClass + private static void destroyData() + { + dismissSolrServers(); + } + + @Test + public void testTracker() throws Exception + { + putHandleDefaults(); + + AclChangeSet aclChangeSet = getAclChangeSet(1); + + Acl acl = getAcl(aclChangeSet); + Acl acl2 = getAcl(aclChangeSet); + + AclReaders aclReaders = getAclReaders(aclChangeSet, acl, singletonList("joel"), singletonList("phil"), null); + AclReaders aclReaders2 = getAclReaders(aclChangeSet, acl2, singletonList("jim"), singletonList("phil"), null); + + // Transaction greater than 2000 is used, to check that "solr.initial.transaction.range" works as expected + Transaction txn = getTransaction(0, 2); + long txnCommitTimeMs = txn.getCommitTimeMs(); + + // Subtract from the commit time to go beyond hole retention + long backdatedCommitTimeMs = txnCommitTimeMs - 4600000; + txn.setCommitTimeMs(backdatedCommitTimeMs); + + //Next create two nodes to update for the transaction + Node folderNode = getNode(txn, acl, Node.SolrApiNodeStatus.UPDATED); + Node fileNode = getNode(txn, acl, Node.SolrApiNodeStatus.UPDATED); + Node errorNode = getNode(txn, acl, Node.SolrApiNodeStatus.UPDATED); + + // Next, create the node metadata for each node. + // Note: the error node metadata will cause an exception. + NodeMetaData folderMetaData = getNodeMetaData(folderNode, txn, acl, "mike", null, false); + NodeMetaData fileMetaData = getNodeMetaData(fileNode, txn, acl, "mike", ancestors(folderMetaData.getNodeRef()), false); + NodeMetaData errorMetaData = getNodeMetaData(errorNode, txn, acl, "lisa", ancestors(folderMetaData.getNodeRef()), true); + + // Index the transaction, nodes, and nodeMetaDatas. + // Note that the content is automatically created by the test framework. + indexTransaction(txn, asList(errorNode, folderNode, fileNode), asList(errorMetaData, folderMetaData, fileMetaData)); + indexAclChangeSet(aclChangeSet, asList(acl, acl2), asList(aclReaders, aclReaders2)); + + BooleanQuery.Builder builder = new BooleanQuery.Builder(); + builder.add(new BooleanClause(new TermQuery(new Term(QueryConstants.FIELD_SOLR4_ID, "TRACKER!STATE!ACLTX")), BooleanClause.Occur.MUST)); + builder.add(new BooleanClause(LegacyNumericRangeQuery.newLongRange(QueryConstants.FIELD_S_ACLTXID, aclChangeSet.getId(), aclChangeSet.getId() + 1, true, false), BooleanClause.Occur.MUST)); + BooleanQuery waitForQuery = builder.build(); + waitForDocCountAllCores(waitForQuery, 1, 80000); + + } +} \ No newline at end of file From 56143aee7446ff3072f4c06db3985d2669bffbca Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Mon, 24 Feb 2020 14:24:02 +0100 Subject: [PATCH 58/94] SEARCH-2117: Declaring "DistributedAlfrescoSolrTrackerLargeTxnTest" as Test Id. --- .../tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java index da7a5ffa8..6dd92cc8d 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DistributedAlfrescoSolrTrackerLargeTxnIdIT.java @@ -65,7 +65,7 @@ public class DistributedAlfrescoSolrTrackerLargeTxnIdIT extends AbstractAlfresco Properties properties = new Properties(); // Set a wider range for Initial Transaction Id properties.put("solr.initial.transaction.range", "0-" + Long.MAX_VALUE); - initSolrServers(2, "DistributedAlfrescoSolrTrackerRaceTest", properties); + initSolrServers(2, "DistributedAlfrescoSolrTrackerLargeTxnTest", properties); } @AfterClass From fdf87e28300d4d788d7ecd79747f5220c79942a2 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Mon, 24 Feb 2020 14:22:24 +0000 Subject: [PATCH 59/94] SEARCH-1953 Only try to call getTxIntervalCommitTime for DB_ID_RANGE sharding. --- .../solr/tracker/MetadataTracker.java | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index 372137ae6..16652d38a 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -18,6 +18,8 @@ */ package org.alfresco.solr.tracker; +import static org.alfresco.repo.index.shard.ShardMethodEnum.DB_ID_RANGE; + import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -140,19 +142,22 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker } // Try invoking txIntervalCommitTime service - try + if (shardMethod.equals(DB_ID_RANGE)) { - client.getTxIntervalCommitTime(coreName, 0l, 0l); - txIntervalCommitTimeServiceAvailable = true; - } - catch (NoSuchMethodException e) - { - log.warn("txIntervalCommitTimeServiceAvailable is not available. If you are using DB_ID_RANGE shard method, " - + "upgrade your ACS Repository version in order to use the skip transactions feature: {} ", e.getMessage()); - } - catch (Exception e) - { - log.error("Checking txIntervalCommitTimeServiceAvailable failed.", e); + try + { + client.getTxIntervalCommitTime(coreName, 0l, 0l); + txIntervalCommitTimeServiceAvailable = true; + } + catch (NoSuchMethodException e) + { + log.warn("txIntervalCommitTimeServiceAvailable is not available. Upgrade your ACS Repository version " + + "to use this feature with DB_ID_RANGE sharding: {} ", e.getMessage()); + } + catch (Exception e) + { + log.error("Checking txIntervalCommitTimeServiceAvailable failed.", e); + } } } From a507bcb7824cea75d4e4f3ed62151037838a8075 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 24 Feb 2020 22:13:35 +0000 Subject: [PATCH 60/94] Bump alfresco-data-model from 8.87 to 8.88 in /search-services Bumps [alfresco-data-model](https://github.com/Alfresco/alfresco-data-model) from 8.87 to 8.88. - [Release notes](https://github.com/Alfresco/alfresco-data-model/releases) - [Commits](https://github.com/Alfresco/alfresco-data-model/compare/8.87...8.88) Signed-off-by: dependabot-preview[bot] --- search-services/alfresco-solrclient-lib/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/alfresco-solrclient-lib/pom.xml b/search-services/alfresco-solrclient-lib/pom.xml index 11bd9ea0c..41cdaf120 100644 --- a/search-services/alfresco-solrclient-lib/pom.xml +++ b/search-services/alfresco-solrclient-lib/pom.xml @@ -22,7 +22,7 @@ - 8.87 + 8.88 2.10.2 From 29b53b55bd3df86ed31cee8e44c4fcc8926722a4 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 25 Feb 2020 09:28:13 +0100 Subject: [PATCH 61/94] SEARCH-2096: Remove SEARCH-2027 approach to delete SOLR Documents only when they existed, as it has been detected some race conditions that lead to duplicating documents in the index. --- .../search/SearchPermissionsTest.java | 1 - .../alfresco/solr/SolrInformationServer.java | 28 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java index 62dc9ba69..763322842 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java @@ -22,7 +22,6 @@ import javax.json.Json; import javax.json.JsonObject; import org.alfresco.dataprep.SiteService.Visibility; -import org.alfresco.rest.requests.Site; import org.alfresco.rest.search.SearchResponse; import org.alfresco.test.search.functional.AbstractE2EFunctionalTest; import org.alfresco.utility.constants.UserRole; 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 e88a75d31..0dbce72f2 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 @@ -2249,15 +2249,11 @@ public class SolrInformationServer implements InformationServer String errorDocId = PREFIX_ERROR + node.getId(); - // Try finding the node before performing removal operation - DocSet docSet = request.getSearcher().getDocSet(new TermQuery(new Term(FIELD_SOLR4_ID, errorDocId))); - - if (docSet.size() > 0) - { - DeleteUpdateCommand delErrorDocCmd = new DeleteUpdateCommand(request); - delErrorDocCmd.setId(errorDocId); - processor.processDelete(delErrorDocCmd); - } + // SEARCH-2096: Try finding the node before performing removal operation fails on some race conditions + // This is why the approach was removed before identifying these conditions + DeleteUpdateCommand delErrorDocCmd = new DeleteUpdateCommand(request); + delErrorDocCmd.setId(errorDocId); + processor.processDelete(delErrorDocCmd); } @@ -2273,15 +2269,11 @@ public class SolrInformationServer implements InformationServer private void deleteNode(UpdateRequestProcessor processor, SolrQueryRequest request, long dbid) throws IOException { - // Try finding the node before performing removal operation - DocSet docSet = request.getSearcher().getDocSet(LongPoint.newExactQuery(FIELD_DBID, dbid)); - - if (docSet.size() > 0) - { - DeleteUpdateCommand delDocCmd = new DeleteUpdateCommand(request); - delDocCmd.setQuery(FIELD_DBID + ":" + dbid); - processor.processDelete(delDocCmd); - } + // SEARCH-2096: Try finding the node before performing removal operation fails on some race conditions + // This is why the approach was removed before identifying these conditions + DeleteUpdateCommand delDocCmd = new DeleteUpdateCommand(request); + delDocCmd.setQuery(FIELD_DBID + ":" + dbid); + processor.processDelete(delDocCmd); } From 50effd5f3c41fa5b435ed0841226b4d483f1ba66 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Tue, 25 Feb 2020 11:37:21 +0100 Subject: [PATCH 62/94] SEARCH-2096: Using SolrQueryRequest to find existing nodes instead of current searcher. --- .../alfresco/solr/SolrInformationServer.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) 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 0dbce72f2..1679141a5 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 @@ -151,7 +151,6 @@ import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.document.Document; -import org.apache.lucene.document.LongPoint; import org.apache.lucene.index.IndexCommit; import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.LeafReaderContext; @@ -194,7 +193,6 @@ import org.apache.solr.schema.SchemaField; import org.apache.solr.search.DelegatingCollector; import org.apache.solr.search.DocIterator; import org.apache.solr.search.DocList; -import org.apache.solr.search.DocSet; import org.apache.solr.search.QueryWrapperFilter; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.update.AddUpdateCommand; @@ -2248,12 +2246,13 @@ public class SolrInformationServer implements InformationServer { String errorDocId = PREFIX_ERROR + node.getId(); - - // SEARCH-2096: Try finding the node before performing removal operation fails on some race conditions - // This is why the approach was removed before identifying these conditions - DeleteUpdateCommand delErrorDocCmd = new DeleteUpdateCommand(request); - delErrorDocCmd.setId(errorDocId); - processor.processDelete(delErrorDocCmd); + // Remove document only when it exists + if (getDocListSize(FIELD_SOLR4_ID + ":" + errorDocId) > 0) + { + DeleteUpdateCommand delErrorDocCmd = new DeleteUpdateCommand(request); + delErrorDocCmd.setId(errorDocId); + processor.processDelete(delErrorDocCmd); + } } @@ -2268,13 +2267,13 @@ public class SolrInformationServer implements InformationServer private void deleteNode(UpdateRequestProcessor processor, SolrQueryRequest request, long dbid) throws IOException { - - // SEARCH-2096: Try finding the node before performing removal operation fails on some race conditions - // This is why the approach was removed before identifying these conditions - DeleteUpdateCommand delDocCmd = new DeleteUpdateCommand(request); - delDocCmd.setQuery(FIELD_DBID + ":" + dbid); - processor.processDelete(delDocCmd); - + // Remove document only when it exists + if (getDocListSize(FIELD_DBID + ":" + dbid) > 0) + { + DeleteUpdateCommand delDocCmd = new DeleteUpdateCommand(request); + delDocCmd.setQuery(FIELD_DBID + ":" + dbid); + processor.processDelete(delDocCmd); + } } private boolean isContentIndexedForNode(Map properties) From 6afb42635f4b06116d073f94ea84545e5c022913 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Tue, 25 Feb 2020 11:11:26 +0000 Subject: [PATCH 63/94] SEARCH-2128 Call initMocks to ensure mocks are reset for each test. --- .../solr/tracker/DBIDRangeRouterTest.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DBIDRangeRouterTest.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DBIDRangeRouterTest.java index a293df87b..a683191ae 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DBIDRangeRouterTest.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/DBIDRangeRouterTest.java @@ -18,29 +18,28 @@ */ package org.alfresco.solr.tracker; +import static java.util.stream.IntStream.range; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import java.util.Properties; +import java.util.Random; + import org.alfresco.repo.index.shard.ShardMethodEnum; import org.alfresco.solr.client.Acl; import org.alfresco.solr.client.Node; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import java.util.Properties; -import java.util.Random; - -import static java.util.stream.IntStream.range; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.when; +import org.mockito.MockitoAnnotations; /** * {@link DBIDRangeRouter} test case. * * @author agazzarini */ -@RunWith(MockitoJUnitRunner.class) public class DBIDRangeRouterTest { private final Random randomizer = new Random(); @@ -55,6 +54,7 @@ public class DBIDRangeRouterTest @Before public void setUp() { + MockitoAnnotations.initMocks(this); Properties properties = new Properties(); properties.put("shard.range", "200-20000"); router = DocRouterFactory.getRouter(properties, ShardMethodEnum.DB_ID_RANGE); From a0db4a2e311e64f948beef708d61f0ca7b43a614 Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 25 Feb 2020 15:17:15 +0000 Subject: [PATCH 64/94] SEARCH-1681 Tests fixes when in a sharded mode --- .../functional/searchServices/search/FacetedSearchTest.java | 5 +++++ .../functional/searchServices/search/ShardInfoTest.java | 2 +- .../functional/searchServices/search/StatsSearchTest.java | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java index ce389980d..2244cfdb9 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java @@ -125,8 +125,13 @@ public class FacetedSearchTest extends AbstractSearchServicesE2ETest SearchResponse response = query(query); + waitForContentIndexing(file4.getContent(), true); + response.assertThat().entriesListIsNotEmpty(); response.getContext().assertThat().field("facetQueries").isNotEmpty(); + Assert.assertTrue(waitForContentIndexing("small", true)); + Assert.assertTrue(waitForContentIndexing("medium", true)); + Assert.assertTrue(waitForContentIndexing("large", true)); FacetFieldBucket facet = response.getContext().getFacetQueries().get(0); facet.assertThat().field("label").contains("small").and().field("count").isGreaterThan(0); diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 0d28bbb77..573af0ae3 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -81,7 +81,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(baseUrls.contains(instance.getBaseUrl())); // TODO: Ideally Solr Host and Port should be Parameterised - assertNotNull(instance.getHost()); + assertNotNull(instance.getHost(), "The solr host is not present"); assertEquals(instance.getPort().intValue(), 8983); assertEquals(instance.getState(), "ACTIVE"); assertEquals(instance.getMode(), "MASTER"); diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java index e998d5b4c..c2b39fb4f 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java @@ -322,7 +322,9 @@ public class StatsSearchTest extends AbstractSearchServicesE2ETest response.getContext().assertThat().field("facets").isNotEmpty(); RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0); facetResponseModel.assertThat().field("type").is("stats"); - facetResponseModel.assertThat().field("label").contains(label); + // TODO : Change back to facetResponseModel.assertThat().field("label").is(label); + // when https://issues.alfresco.com/jira/browse/SEARCH-2125 is fixed + facetResponseModel.assertThat().field("label").is(label); RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0); List metrics = bucket.getMetrics(); assertEquals(metrics.size(),metricsCount); From c4dbd97cf631a9215fa7c48573822340f60c40ec Mon Sep 17 00:00:00 2001 From: Keerat Date: Tue, 25 Feb 2020 15:19:00 +0000 Subject: [PATCH 65/94] SEARCH-1681 Removing additinal comments --- .../functional/searchServices/search/FacetedSearchTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java index 2244cfdb9..ce389980d 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/FacetedSearchTest.java @@ -125,13 +125,8 @@ public class FacetedSearchTest extends AbstractSearchServicesE2ETest SearchResponse response = query(query); - waitForContentIndexing(file4.getContent(), true); - response.assertThat().entriesListIsNotEmpty(); response.getContext().assertThat().field("facetQueries").isNotEmpty(); - Assert.assertTrue(waitForContentIndexing("small", true)); - Assert.assertTrue(waitForContentIndexing("medium", true)); - Assert.assertTrue(waitForContentIndexing("large", true)); FacetFieldBucket facet = response.getContext().getFacetQueries().get(0); facet.assertThat().field("label").contains("small").and().field("count").isGreaterThan(0); From 844a9f3a66b02c2883c0d9ae7adefd69f847ec34 Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 26 Feb 2020 12:26:52 +0000 Subject: [PATCH 66/94] SEARCH-2078 Fix for the stats tests --- .../functional/searchServices/search/StatsSearchTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java index c2b39fb4f..5de017a74 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/StatsSearchTest.java @@ -324,7 +324,7 @@ public class StatsSearchTest extends AbstractSearchServicesE2ETest facetResponseModel.assertThat().field("type").is("stats"); // TODO : Change back to facetResponseModel.assertThat().field("label").is(label); // when https://issues.alfresco.com/jira/browse/SEARCH-2125 is fixed - facetResponseModel.assertThat().field("label").is(label); + facetResponseModel.assertThat().field("label").contains(label); RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0); List metrics = bucket.getMetrics(); assertEquals(metrics.size(),metricsCount); From b451a22d3db65e5271b3cad7c72a3dd310caed82 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2020 22:13:09 +0000 Subject: [PATCH 67/94] Bump utility from 3.0.19 to 3.0.20 in /e2e-test Bumps [utility](https://github.com/Alfresco/alfresco-tas-utility) from 3.0.19 to 3.0.20. - [Release notes](https://github.com/Alfresco/alfresco-tas-utility/releases) - [Changelog](https://github.com/Alfresco/alfresco-tas-utility/blob/master/docs/CHANGELOG.md) - [Commits](https://github.com/Alfresco/alfresco-tas-utility/compare/utility-3.0.19...utility-3.0.20) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 197a51181..54a1f2067 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -13,7 +13,7 @@ 1.33 1.13 - 3.0.19 + 3.0.20 3.3.0.1 src/test/resources/SearchSuite.xml From 8357147cd14e9c51860e6b0971304aa5ea44ea31 Mon Sep 17 00:00:00 2001 From: agazzarini Date: Thu, 27 Feb 2020 14:46:12 +0100 Subject: [PATCH 68/94] [ SEARCH-2110 ] Shard additional parameters are always sent, regardless shard method --- .../solr/tracker/CoreStatePublisher.java | 16 +++++++++------- .../solr/tracker/DBIDRangeRouter.java | 4 ++-- .../solr/tracker/DateMonthRouter.java | 19 ++++++++++--------- .../org/alfresco/solr/tracker/DocRouter.java | 9 +++++---- .../solr/tracker/DocRouterWithFallback.java | 4 ++-- ...licitShardIdWithDynamicPropertyRouter.java | 14 ++++++++------ .../alfresco/solr/tracker/PropertyRouter.java | 17 ++++++++++------- 7 files changed, 46 insertions(+), 37 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CoreStatePublisher.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CoreStatePublisher.java index 6c38fb47a..591863964 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CoreStatePublisher.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CoreStatePublisher.java @@ -40,6 +40,7 @@ import org.alfresco.service.cmr.dictionary.PropertyDefinition; import org.alfresco.service.namespace.QName; import org.alfresco.solr.AlfrescoCoreAdminHandler; import org.alfresco.solr.AlfrescoSolrDataModel; +import org.alfresco.solr.BoundedDeque; import org.alfresco.solr.InformationServer; import org.alfresco.solr.NodeReport; import org.alfresco.solr.TrackerState; @@ -52,8 +53,8 @@ import java.util.Properties; /** * Superclass for all components which are able to inform Alfresco about the hosting node state. - * This has been introduced in SEARCH-1752 for splitting the dual responsibility of the {@link MetadataTracker}. - * As consequence of that, this class contains all the members needed for obtaining a valid + * This has been introduced in SEARCH-1752 for splitting the dual responsibility of the {@link org.alfresco.solr.tracker.MetadataTracker}. + * As consequence of that, this class contains only the members needed for obtaining a valid * {@link org.alfresco.repo.index.shard.ShardState} that can be periodically communicated to Alfresco. * * @author Andrea Gazzarini @@ -176,15 +177,15 @@ public abstract class CoreStatePublisher extends AbstractTracker * The {@link ShardState} is primarily used in two places: * *
    - *
  • Transaction tracking: (see {@link MetadataTracker#trackTransactions()}): for pulling/tracking transactions from Alfresco
  • + *
  • Transaction tracking: (see {@link MetadataTracker#getSomeTransactions(BoundedDeque, Long, long, int, long}): for pulling/tracking transactions from Alfresco
  • *
  • - * DynamicSharding: when the {@link MetadataTracker} is running on a slave instance it doesn't actually act - * as a tracker, it calls Alfresco to register the state of the node (the shard) without pulling any transactions. - * As consequence of that, Alfresco will be aware about the shard which will be included in subsequent queries. + * DynamicSharding: the {@link MetadataTracker} is not running on a slave instances; in those cases a special + * "tracker" ({@link SlaveCoreStatePublisher}) will be in charge to send the correspondin shard state to Alfresco. *
  • *
* * @return the {@link ShardState} instance which stores the current state of the hosting shard. + * @see SlaveCoreStatePublisher */ ShardState getShardState() { @@ -198,10 +199,11 @@ public abstract class CoreStatePublisher extends AbstractTracker HashMap propertyBag = new HashMap<>(); propertyBag.put("coreName", coreName); + HashMap extendedPropertyBag = new HashMap<>(propertyBag); updateShardProperty(); - shardProperty.ifPresent(p -> extendedPropertyBag.putAll(docRouter.getProperties(p))); + extendedPropertyBag.putAll(docRouter.getProperties(shardProperty)); return ShardStateBuilder.shardState() .withMaster(isMaster) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DBIDRangeRouter.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DBIDRangeRouter.java index bbbcca37d..b405b479a 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DBIDRangeRouter.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DBIDRangeRouter.java @@ -19,6 +19,7 @@ package org.alfresco.solr.tracker; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -108,9 +109,8 @@ public class DBIDRangeRouter implements DocRouter } @Override - public Map getProperties(QName shardProperty) + public Map getProperties(Optional shardProperty) { return Map.of(DocRouterFactory.SHARD_RANGE_KEY, startRange + "-" + expandableRange); } - } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DateMonthRouter.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DateMonthRouter.java index 8870f02e6..20282e8d9 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DateMonthRouter.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DateMonthRouter.java @@ -26,10 +26,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Calendar; -import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.Map; +import java.util.Optional; + +import static java.util.Collections.emptyMap; /** * The date-based sharding assigns dates sequentially through shards based on the month. @@ -121,14 +123,13 @@ public class DateMonthRouter implements DocRouter } @Override - public Map getProperties(QName shardProperty) + public Map getProperties(Optional shardProperty) { - - return (shardProperty == null ? - Collections.emptyMap() : - Map.of(DocRouterFactory.SHARD_KEY_KEY, shardProperty.getPrefixString(), - DocRouterFactory.SHARD_DATE_GROUPING_KEY, String.valueOf(grouping))); - + return shardProperty + .map(QName::getPrefixString) + .map(prefix -> Map.of( + DocRouterFactory.SHARD_KEY_KEY, prefix, + DocRouterFactory.SHARD_DATE_GROUPING_KEY, String.valueOf(grouping))) + .orElse(emptyMap()); } - } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouter.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouter.java index 694780c4b..d146acc98 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouter.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouter.java @@ -22,6 +22,7 @@ import org.alfresco.solr.client.Node; import java.util.Collections; import java.util.Map; +import java.util.Optional; import org.alfresco.service.namespace.QName; import org.alfresco.solr.client.Acl; @@ -65,13 +66,13 @@ public interface DocRouter Boolean routeNode(int shardCount, int shardInstance, Node node); /** - * Get additional properties to "shardProperty" depending on the Shard Method - * @param shardProperty custom property used to configure the Router + * Get additional properties to "shardProperty" depending on the Shard Method. + * + * @param shardProperty custom property used to configure the Router. Note not all routers need that. * @return pair of key, value */ - default public Map getProperties(QName shardProperty) { + default Map getProperties(Optional shardProperty) { return Collections.emptyMap(); } - } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouterWithFallback.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouterWithFallback.java index d809b330f..08462a801 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouterWithFallback.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/DocRouterWithFallback.java @@ -9,6 +9,7 @@ import java.util.Objects; import static java.util.Optional.ofNullable; import java.util.Map; +import java.util.Optional; /** * A composable {@link DocRouter} which consists of @@ -47,9 +48,8 @@ public class DocRouterWithFallback implements DocRouter } @Override - public Map getProperties(QName shardProperty) + public Map getProperties(Optional shardProperty) { return primaryStrategy.getProperties(shardProperty); } - } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ExplicitShardIdWithDynamicPropertyRouter.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ExplicitShardIdWithDynamicPropertyRouter.java index 383414bcc..67a6e6c85 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ExplicitShardIdWithDynamicPropertyRouter.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ExplicitShardIdWithDynamicPropertyRouter.java @@ -18,13 +18,15 @@ */ package org.alfresco.solr.tracker; -import java.util.Collections; import java.util.Map; +import java.util.Optional; import org.alfresco.service.namespace.QName; import org.alfresco.solr.client.Acl; import org.alfresco.solr.client.Node; +import static java.util.Collections.emptyMap; + /** * Routes a document only if the shardInstance matches the provided shardId. * The access control information is duplicated in each shard. @@ -78,11 +80,11 @@ public class ExplicitShardIdWithDynamicPropertyRouter extends ComposableDocRoute } @Override - public Map getProperties(QName shardProperty) + public Map getProperties(Optional shardProperty) { - return (shardProperty == null ? - Collections.emptyMap() : - Map.of(DocRouterFactory.SHARD_KEY_KEY, shardProperty.getPrefixString())); + return shardProperty + .map(QName::getPrefixString) + .map(prefix -> Map.of(DocRouterFactory.SHARD_KEY_KEY, prefix)) + .orElse(emptyMap()); } - } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/PropertyRouter.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/PropertyRouter.java index c64c59ab0..d1b4d620d 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/PropertyRouter.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/PropertyRouter.java @@ -26,11 +26,13 @@ import org.apache.solr.common.util.Hash; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collections; import java.util.Map; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.util.Collections.emptyMap; + /** * Routes based on a text property field. * In this method, the value of some property is hashed and this hash is used to assign the node to a random shard. @@ -126,12 +128,13 @@ public class PropertyRouter implements DocRouter } @Override - public Map getProperties(QName shardProperty) + public Map getProperties(Optional shardProperty) { - return (shardProperty == null ? - Collections.emptyMap() : - Map.of(DocRouterFactory.SHARD_KEY_KEY, shardProperty.getPrefixString(), - DocRouterFactory.SHARD_REGEX_KEY, propertyRegEx)); + return shardProperty + .map(QName::getPrefixString) + .map(prefix -> Map.of( + DocRouterFactory.SHARD_KEY_KEY, prefix, + DocRouterFactory.SHARD_REGEX_KEY, propertyRegEx)) + .orElse(emptyMap()); } - } From 700d86ca8e867f0cb2608da3bee0b63512013c53 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Thu, 27 Feb 2020 15:13:23 +0100 Subject: [PATCH 69/94] SEARCH-2097: Adding verbose log (INFO, DEBUG and TRACE levels) for AclTracker. Adding detailed information for rollback operations, dumping the Exception that caused that rollback. --- .../alfresco/solr/SolrInformationServer.java | 3 +- .../solr/tracker/AbstractTracker.java | 30 +++-- .../solr/tracker/AbstractWorkerRunnable.java | 8 +- .../org/alfresco/solr/tracker/AclTracker.java | 127 ++++++++++++------ .../alfresco/solr/tracker/CascadeTracker.java | 4 +- .../alfresco/solr/tracker/CommitTracker.java | 19 ++- .../alfresco/solr/tracker/ContentTracker.java | 5 +- .../solr/tracker/MetadataTracker.java | 4 +- .../org/alfresco/solr/tracker/Tracker.java | 4 +- .../AlfrescoSolrTrackerRollbackIT.java | 2 +- 10 files changed, 137 insertions(+), 69 deletions(-) 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 4ca525913..c59e1d2ea 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 @@ -3090,7 +3090,8 @@ public class SolrInformationServer implements InformationServer { if (!activeTrackerThreads.contains(Thread.currentThread().getId())) { - throw new TrackerStateException("The trackers work was rolled back by another tracker error"); + throw new TrackerStateException( + "The trackers work was rolled back by another tracker error. The original cause has been dumped previously in the log."); } } finally diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java index f4d381cd1..5c09cd0dc 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java @@ -68,6 +68,10 @@ public abstract class AbstractTracker implements Tracker protected boolean transformContent; String shardTemplate; protected volatile boolean rollback; + /** + * When rollback is set, original error is also gathered in order to provide detailed logging. + */ + protected Throwable rollbackCausedBy; protected final Type type; /* @@ -176,13 +180,13 @@ public abstract class AbstractTracker implements Tracker assert(assertTrackerStateRemainsNull()); } - LOGGER.info("... Running {} for core [{}]", this.getClass().getSimpleName(), coreName); + LOGGER.info("[CORE {}] ... Running {}", coreName, this.getClass().getSimpleName()); if(this.state == null) { this.state = getTrackerState(); - LOGGER.debug("Global Tracker State set to: {}", this.state.toString()); + LOGGER.debug("[CORE {}] Global Tracker State set to: {}", coreName, this.state.toString()); this.state.setRunning(true); } else @@ -199,34 +203,34 @@ public abstract class AbstractTracker implements Tracker } catch(IndexTrackingShutdownException t) { - setRollback(true); - LOGGER.info("Stopping index tracking for {} - {}", getClass().getSimpleName(), coreName); + setRollback(true, t); + LOGGER.info("[CORE {}] Stopping index tracking for {}", coreName, getClass().getSimpleName()); } catch(Throwable t) { - setRollback(true); + setRollback(true, t); if (t instanceof SocketTimeoutException || t instanceof ConnectException) { if (LOGGER.isDebugEnabled()) { // DEBUG, so give the whole stack trace - LOGGER.warn("Tracking communication timed out for {} - {}", getClass().getSimpleName(), coreName, t); + LOGGER.warn("[CORE {}] Tracking communication timed out for {}", coreName, getClass().getSimpleName(), t); } else { // We don't need the stack trace. It timed out. - LOGGER.warn("Tracking communication timed out for for {} - {}", getClass().getSimpleName(), coreName); + LOGGER.warn("[CORE {}] Tracking communication timed out for {}", coreName, getClass().getSimpleName()); } } else { - LOGGER.error("Tracking failed for for {} - {}", getClass().getSimpleName(), coreName, t); + LOGGER.error("[CORE {}] Tracking failed for {}", coreName, getClass().getSimpleName(), t); } } } catch (InterruptedException e) { - LOGGER.error("Semaphore interrupted for for {} - {}", getClass().getSimpleName(), coreName, e); + LOGGER.error("[CORE {}] Semaphore interrupted for {}", coreName, getClass().getSimpleName(), e); } finally { @@ -244,10 +248,16 @@ public abstract class AbstractTracker implements Tracker { return this.rollback; } + + public Throwable getRollbackCausedBy() + { + return this.rollbackCausedBy; + } - public void setRollback(boolean rollback) + public void setRollback(boolean rollback, Throwable rollbackCausedBy) { this.rollback = rollback; + this.rollbackCausedBy = rollbackCausedBy; } private void continueState() diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractWorkerRunnable.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractWorkerRunnable.java index 30f228ebe..2aa335d98 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractWorkerRunnable.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractWorkerRunnable.java @@ -40,6 +40,7 @@ abstract class AbstractWorkerRunnable implements Runnable public void run() { boolean failed = true; + Exception failCausedBy = null; try { doWork(); @@ -47,7 +48,8 @@ abstract class AbstractWorkerRunnable implements Runnable } catch (Exception e) { - log.warn("Index tracking batch hit an unrecoverable error ", e); + log.warn("Index tracking batch hit an unrecoverable error ", e); + failCausedBy = e; } finally { @@ -55,12 +57,12 @@ abstract class AbstractWorkerRunnable implements Runnable queueHandler.removeFromQueueAndProdHead(this); if(failed) { - onFail(); + onFail(failCausedBy); } } } abstract protected void doWork() throws Exception; - abstract protected void onFail(); + abstract protected void onFail(Throwable failCausedBy); } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java index 3092c7d1b..e28785c7a 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AclTracker.java @@ -54,7 +54,7 @@ import org.slf4j.LoggerFactory; public class AclTracker extends AbstractTracker { - protected final static Logger log = LoggerFactory.getLogger(AclTracker.class); + protected final static Logger LOGGER = LoggerFactory.getLogger(AclTracker.class); private static final int DEFAULT_CHANGE_SET_ACLS_BATCH_SIZE = 100; private static final int DEFAULT_ACL_BATCH_SIZE = 10; @@ -135,12 +135,14 @@ public class AclTracker extends AbstractTracker indexAcl(readers, false); } this.infoSrv.indexAclTransaction(changeSet, false); - log.info("INDEX ACTION - AclChangeSetId {} has been indexed", aclChangeSetId); + LOGGER.info("[CORE {}] - INDEX ACTION - AclChangeSetId {} has been indexed", coreName, aclChangeSetId); requiresCommit = true; } else { - log.info("INDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", aclChangeSetId); + LOGGER.info( + "[CORE {}] - INDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", + coreName, aclChangeSetId); } } checkShutdown(); @@ -165,7 +167,7 @@ public class AclTracker extends AbstractTracker //AclReaders r = readers.get(0); //System.out.println("############## READERS ID:"+r.getId()+":"+r.getReaders()); indexAcl(readers, false); - log.info("INDEX ACTION - AclId {} has been indexed", aclId); + LOGGER.info("[CORE {}] - INDEX ACTION - AclId {} has been indexed", coreName, aclId); } checkShutdown(); } @@ -193,12 +195,14 @@ public class AclTracker extends AbstractTracker } this.infoSrv.indexAclTransaction(changeSet, true); - log.info("REINDEX ACTION - AclChangeSetId {} has been reindexed", aclChangeSetId); + LOGGER.info("[CORE {}] - REINDEX ACTION - AclChangeSetId {} has been reindexed", coreName, aclChangeSetId); requiresCommit = true; } else { - log.info("REINDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", aclChangeSetId); + LOGGER.info( + "[CORE {}] - REINDEX ACTION - AclChangeSetId {} was not found in database, it has NOT been reindexed", + coreName, aclChangeSetId); } } checkShutdown(); @@ -223,7 +227,7 @@ public class AclTracker extends AbstractTracker Acl acl = new Acl(0, aclId); List readers = client.getAclReaders(Collections.singletonList(acl)); indexAcl(readers, true); - log.info("REINDEX ACTION - aclId {} has been reindexed", aclId); + LOGGER.info("[CORE {}] - REINDEX ACTION - aclId {} has been reindexed", coreName, aclId); requiresCommit = true; } checkShutdown(); @@ -243,7 +247,7 @@ public class AclTracker extends AbstractTracker if (aclChangeSetId != null) { this.infoSrv.deleteByAclChangeSetId(aclChangeSetId); - log.info("PURGE ACTION - Purged aclChangeSetId {}", aclChangeSetId); + LOGGER.info("[CORE {}] - PURGE ACTION - Purged aclChangeSetId {}", coreName, aclChangeSetId); } checkShutdown(); } @@ -258,7 +262,7 @@ public class AclTracker extends AbstractTracker if (aclId != null) { this.infoSrv.deleteByAclId(aclId); - log.info("PURGE ACTION - Purged aclId {}", aclId); + LOGGER.info("[CORE {}] - PURGE ACTION - Purged aclId {}", coreName, aclId); } checkShutdown(); } @@ -330,7 +334,7 @@ public class AclTracker extends AbstractTracker { state.setCheckedLastAclTransactionTime(true); state.setCheckedFirstAclTransactionTime(true); - log.info("No acl transactions found - no verification required"); + LOGGER.info("[CORE {}] - No acl transactions found - no verification required", coreName); firstChangeSets = client.getAclChangeSets(null, 0L, null, 2000L, 1); if (!firstChangeSets.getAclChangeSets().isEmpty()) @@ -354,20 +358,20 @@ public class AclTracker extends AbstractTracker if (setSize == 0) { - log.error("First acl transaction was not found with the correct timestamp."); - log.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); - log.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); - log.error("You can also check your SOLR connection details in solrcore.properties."); + LOGGER.error("[CORE {}] First acl transaction was not found with the correct timestamp.", coreName); + LOGGER.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); + LOGGER.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); + LOGGER.error("You can also check your SOLR connection details in solrcore.properties."); throw new AlfrescoRuntimeException("Initial acl transaction not found with correct timestamp"); } else if (setSize == 1) { state.setCheckedFirstTransactionTime(true); - log.info("Verified first acl transaction and timestamp in index"); + LOGGER.info("[CORE {}] Verified first acl transaction and timestamp in index", coreName); } else { - log.warn("Duplicate initial acl transaction found with correct timestamp"); + LOGGER.warn("[CORE {}] Duplicate initial acl transaction found with correct timestamp", coreName); } } } @@ -388,19 +392,19 @@ public class AclTracker extends AbstractTracker AclChangeSet maxAclTxInIndex = this.infoSrv.getMaxAclChangeSetIdAndCommitTimeInIndex(); if (maxAclTxInIndex.getCommitTimeMs() > maxChangeSetCommitTimeInRepo) { - log.error("Last acl transaction was found in index with timestamp later than that of repository."); - log.error("Max Acl Tx In Index: " + maxAclTxInIndex.getId() + ", In Repo: " + maxChangeSetIdInRepo); - log.error("Max Acl Tx Commit Time In Index: " + maxAclTxInIndex.getCommitTimeMs() + ", In Repo: " + LOGGER.error("[CORE {}] Last acl transaction was found in index with timestamp later than that of repository.", coreName); + LOGGER.error("Max Acl Tx In Index: " + maxAclTxInIndex.getId() + ", In Repo: " + maxChangeSetIdInRepo); + LOGGER.error("Max Acl Tx Commit Time In Index: " + maxAclTxInIndex.getCommitTimeMs() + ", In Repo: " + maxChangeSetCommitTimeInRepo); - log.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); - log.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); - log.error("You can also check your SOLR connection details in solrcore.properties."); + LOGGER.error("SOLR has successfully connected to your repository however the SOLR indexes and repository database do not match."); + LOGGER.error("If this is a new or rebuilt database your SOLR indexes also need to be re-built to match the database."); + LOGGER.error("You can also check your SOLR connection details in solrcore.properties."); throw new AlfrescoRuntimeException("Last acl transaction found in index with incorrect timestamp"); } else { state.setCheckedLastAclTransactionTime(true); - log.info("Verified last acl transaction timestamp in index less than or equal to that of repository."); + LOGGER.info("[CORE {}] - Verified last acl transaction timestamp in index less than or equal to that of repository.", coreName); } } } @@ -430,7 +434,7 @@ public class AclTracker extends AbstractTracker AclChangeSets aclChangeSets; // step forward in time until we find something or hit the time bound // max id unbounded - Long startTime = fromCommitTime == null ? Long.valueOf(0L) :fromCommitTime; + Long startTime = fromCommitTime == null ? Long.valueOf(0L) : fromCommitTime; do { aclChangeSets = client.getAclChangeSets(startTime, null, startTime + actualTimeStep, null, maxResults); @@ -659,30 +663,58 @@ public class AclTracker extends AbstractTracker */ this.state = getTrackerState(); - + Long fromCommitTime = getChangeSetFromCommitTime(changeSetsFound, state.getLastGoodChangeSetCommitTimeInIndex()); aclChangeSets = getSomeAclChangeSets(changeSetsFound, fromCommitTime, TIME_STEP_1_HR_IN_MS, 2000, state.getTimeToStopIndexing()); - - + setLastChangeSetIdAndCommitTimeInTrackerState(aclChangeSets, state); - log.info("Scanning Acl change sets ..."); - if (aclChangeSets.getAclChangeSets().size() > 0) { - log.info(".... from " + aclChangeSets.getAclChangeSets().get(0)); - log.info(".... to " + aclChangeSets.getAclChangeSets().get(aclChangeSets.getAclChangeSets().size() - 1)); - } else { - log.info(".... none found after lastTxCommitTime " + fromCommitTime); + if (aclChangeSets.getAclChangeSets().size() > 0) + { + LOGGER.info("{}-[CORE {}] Found {} ACL change sets after lastTxCommitTime {}, ACL Change Sets from {} to {}", + Thread.currentThread().getId(), + coreName, + aclChangeSets.getAclChangeSets().size(), + fromCommitTime, + aclChangeSets.getAclChangeSets().get(0), + aclChangeSets.getAclChangeSets().get(aclChangeSets.getAclChangeSets().size() - 1)); + } + else + { + LOGGER.info("{}-[CORE {}] No ACL change set found after lastTxCommitTime {}", + Thread.currentThread().getId(), coreName, fromCommitTime); } - + ArrayList changeSetBatch = new ArrayList(); - for (AclChangeSet changeSet : aclChangeSets.getAclChangeSets()) { + for (int i = 0; i < aclChangeSets.getAclChangeSets().size(); i++) + { + + AclChangeSet changeSet = aclChangeSets.getAclChangeSets().get(i); + boolean isInIndex = (changeSet.getCommitTimeMs() <= state.getLastIndexedChangeSetCommitTime() && infoSrv.aclChangeSetInIndex(changeSet.getId(), true)); - - if (isInIndex) { + + if (isInIndex) + { + // Logging progress for large ACL Change Set tracking every 100 tracked ACLs + if (LOGGER.isTraceEnabled()) + { + LOGGER.trace("{}-[CORE {}] Tracking {} of {} ACL Change Sets. Change Set Id was already indexed: {}", + Thread.currentThread().getId(), coreName, i + 1, aclChangeSets.getAclChangeSets().size(), changeSet.getId()); + } changeSetsFound.add(changeSet); - } else { + } + else + { + + // Logging progress for ACL Change Set + if (LOGGER.isTraceEnabled()) + { + LOGGER.trace("{}-[CORE {}] Tracking {} of {} ACL Change Sets. Current Change Set Id to be indexed: {}", + Thread.currentThread().getId(), coreName, i + 1, aclChangeSets.getAclChangeSets().size(), changeSet.getId()); + } + // Make sure we do not go ahead of where we started - we will check the holes here // correctly next time if (changeSet.getCommitTimeMs() > state.getTimeToStopIndexing()) { @@ -745,10 +777,12 @@ public class AclTracker extends AbstractTracker { getWriteLock().release(); } + } while ((aclChangeSets.getAclChangeSets().size() > 0) && (upToDate == false)); + + LOGGER.info("{}-[CORE {}] Tracked {} ACLs", Thread.currentThread().getId(), coreName, totalAclCount); - log.info("total number of acls updated: " + totalAclCount); } private void setLastChangeSetIdAndCommitTimeInTrackerState(AclChangeSets aclChangeSets, TrackerState state) @@ -811,12 +845,19 @@ public class AclTracker extends AbstractTracker ArrayList aclBatch = new ArrayList(); List acls = client.getAcls(nonEmptyChangeSets, null, Integer.MAX_VALUE); + + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("{}-[CORE {}] Found {} Acls from Acl Change Sets: {}", Thread.currentThread().getId(), + coreName, acls.size(), nonEmptyChangeSets); + } for (Acl acl : acls) { - if (log.isDebugEnabled()) + if (LOGGER.isTraceEnabled()) { - log.debug(acl.toString()); + LOGGER.trace("{}-[CORE {}] Adding ACL {} to scheduled indexing job", Thread.currentThread().getId(), + coreName, acl.toString()); } aclBatch.add(acl); if (aclBatch.size() > aclBatchSize) @@ -859,9 +900,9 @@ public class AclTracker extends AbstractTracker } @Override - protected void onFail() + protected void onFail(Throwable failCausedBy) { - setRollback(true); + setRollback(true, failCausedBy); } private List filterAcls(List acls) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CascadeTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CascadeTracker.java index 56f0f6b3f..18e79394f 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CascadeTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CascadeTracker.java @@ -114,9 +114,9 @@ public class CascadeTracker extends AbstractTracker implements Tracker } @Override - protected void onFail() + protected void onFail(Throwable failCausedBy) { - setRollback(true); + setRollback(true, failCausedBy); } } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CommitTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CommitTracker.java index 6f7332035..e087752b2 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CommitTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/CommitTracker.java @@ -194,6 +194,17 @@ public class CommitTracker extends AbstractTracker } infoSrv.rollback(); + + // Log reasons why the rollback is performed + if (aclTracker.getRollbackCausedBy() != null) + { + log.warn("Rollback performed due to ACL Tracker error", aclTracker.getRollbackCausedBy()); + } + if (metadataTracker.getRollbackCausedBy() != null) + { + log.warn("Rollback performed due to Metadata Tracker error", metadataTracker.getRollbackCausedBy()); + } + } catch (Exception e) { @@ -202,19 +213,19 @@ public class CommitTracker extends AbstractTracker finally { //Reset acl Tracker - aclTracker.setRollback(false); + aclTracker.setRollback(false, null); aclTracker.invalidateState(); //Reset metadataTracker - metadataTracker.setRollback(false); + metadataTracker.setRollback(false, null); metadataTracker.invalidateState(); //Reset contentTracker - contentTracker.setRollback(false); + contentTracker.setRollback(false, null); contentTracker.invalidateState(); //Reset cascadeTracker - cascadeTracker.ifPresent(c -> c.setRollback(false)); + cascadeTracker.ifPresent(c -> c.setRollback(false, null)); cascadeTracker.ifPresent(c -> invalidateState()); //Release the locks diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ContentTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ContentTracker.java index 4c3ed15a8..e4b837280 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ContentTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/ContentTracker.java @@ -155,9 +155,10 @@ public class ContentTracker extends AbstractTracker implements Tracker } @Override - protected void onFail() + protected void onFail(Throwable failCausedBy) { - // Will redo if not persisted + // This will be redone in future tracking operations + log.warn("Content tracker failed due to {}", failCausedBy.getMessage(), failCausedBy); } } } diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java index ed6fc6da6..8636c9c71 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/MetadataTracker.java @@ -1039,9 +1039,9 @@ public class MetadataTracker extends CoreStatePublisher implements Tracker } @Override - protected void onFail() + protected void onFail(Throwable failCausedBy) { - setRollback(true); + setRollback(true, failCausedBy); } private List filterNodes(List nodes) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/Tracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/Tracker.java index 976d52c20..b7e049fa5 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/Tracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/Tracker.java @@ -41,9 +41,11 @@ public interface Tracker boolean getRollback(); + Throwable getRollbackCausedBy(); + Properties getProps(); - void setRollback(boolean rollback); + void setRollback(boolean rollback, Throwable rollbackCausedBy); void invalidateState(); diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/AlfrescoSolrTrackerRollbackIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/AlfrescoSolrTrackerRollbackIT.java index 2313586ac..9baf19990 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/AlfrescoSolrTrackerRollbackIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/tracker/AlfrescoSolrTrackerRollbackIT.java @@ -195,7 +195,7 @@ public class AlfrescoSolrTrackerRollbackIT extends AbstractAlfrescoSolrIT //This will prove the rollback transaction was rolled back SOLRAPIQueueClient.transactionQueue.remove(rollbackTxn); - metadataTracker.setRollback(true); + metadataTracker.setRollback(true, new Exception("Forced rollback!")); commitTracker.getRunLock().release(); From 521c48542292e2af2ba2effe3cc4c491f57209e3 Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 27 Feb 2020 15:25:07 +0000 Subject: [PATCH 70/94] SEARCH-2110 uncommenting the TODO for the getShardInfoWith2OrMoreShards Test --- .../search/functional/searchServices/search/ShardInfoTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 573af0ae3..3e5d0b95c 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -189,8 +189,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest case "DB_ID": break; case "DB_ID_RANGE": - // TODO: Uncomment the following assert when fixed: https://issues.alfresco.com/jira/browse/SEARCH-2110 - //assertEquals(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); + assertTrue(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); break; case "DATE": assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for DATE"); From 2f52756a54c834b105a6a1372233a8af28b9d57e Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 27 Feb 2020 15:45:30 +0000 Subject: [PATCH 71/94] SEARCH-2110 adding shard.regex paramter for property sharding --- .../search/functional/searchServices/search/ShardInfoTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 3e5d0b95c..7bbf78438 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -197,6 +197,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest break; case "PROPERTY": assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for PROPERTY"); + assertTrue(shardParams.contains("shard.regex="), "Unexpected shard regex defined for PROPERTY"); break; case "EXPLICIT_ID": assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for EXPLICIT_ID"); From 8da67753c2b6b52b430e8aa593f776a4a3ccd076 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 27 Feb 2020 22:12:53 +0000 Subject: [PATCH 72/94] Bump restapi from 1.33 to 1.34 in /e2e-test Bumps [restapi](https://github.com/Alfresco/alfresco-tas-restapi) from 1.33 to 1.34. - [Release notes](https://github.com/Alfresco/alfresco-tas-restapi/releases) - [Commits](https://github.com/Alfresco/alfresco-tas-restapi/compare/v1.33...v1.34) Signed-off-by: dependabot-preview[bot] --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 197a51181..bb2d80192 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,7 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.33 + 1.34 1.13 3.0.19 3.3.0.1 From 1f62b4f7dfafc3c92ec2b229fbacaf038d6d8c89 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 28 Feb 2020 08:40:56 +0000 Subject: [PATCH 73/94] SEARCH-2110 fixing review comments --- .../searchServices/search/ShardInfoTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 7bbf78438..0465a74e5 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -189,18 +189,18 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest case "DB_ID": break; case "DB_ID_RANGE": - assertTrue(shardParams.contains("shard.range="), "Unexpected shard params defined for DB_ID_RANGE"); + assertTrue(shardParams.contains("shard.range="), "Shard Parameters Not as expected for the Shard Method: DB_ID_RANGE"); break; case "DATE": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for DATE"); - assertTrue(shardParams.contains("shard.grouping="), "Unexpected shard grouping defined for DATE"); + assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: DATE"); + assertTrue(shardParams.contains("shard.date.grouping="), "Shard Parameters Not as expected for the Shard Method: DATE"); break; case "PROPERTY": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for PROPERTY"); - assertTrue(shardParams.contains("shard.regex="), "Unexpected shard regex defined for PROPERTY"); + assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: PROPERTY"); + assertTrue(shardParams.contains("shard.regex="), "Shard Parameters Not as expected for the Shard Method: PROPERTY"); break; case "EXPLICIT_ID": - assertTrue(shardParams.contains("shard.key="), "Unexpected shard params defined for EXPLICIT_ID"); + assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: EXPLICIT_ID"); break; default: throw new AssertionError("Not as expected: " + shardParams.toString()); From fb01193a29e2451648681ade848ec0b725f78a24 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 28 Feb 2020 08:50:14 +0000 Subject: [PATCH 74/94] SEARCH-2110 fixing review comments --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index 0465a74e5..ff2c59e3e 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -203,7 +203,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: EXPLICIT_ID"); break; default: - throw new AssertionError("Not as expected: " + shardParams.toString()); + throw new AssertionError("Shard Parameters Not as expected for the Shard Method: " + model.getShardMethod() + ": " + shardParams.toString()); } } } From d50ff3f31efd77640d1cf8b44be8080486f4a431 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 28 Feb 2020 08:52:51 +0000 Subject: [PATCH 75/94] SEARCH-2110 fixing review comments --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index ff2c59e3e..ab0935b58 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -203,7 +203,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: EXPLICIT_ID"); break; default: - throw new AssertionError("Shard Parameters Not as expected for the Shard Method: " + model.getShardMethod() + ": " + shardParams.toString()); + throw new AssertionError("Shard Method Not expected: " + model.getShardMethod() + ": " + shardParams.toString()); } } } From c05e6e207f87f8a533ac1d8842c57241228ee86c Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 28 Feb 2020 08:56:12 +0000 Subject: [PATCH 76/94] SEARCH-2110 fixing review comments --- .../search/functional/searchServices/search/ShardInfoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java index ab0935b58..fe8dd1f9c 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/ShardInfoTest.java @@ -203,7 +203,7 @@ public class ShardInfoTest extends AbstractE2EFunctionalTest assertTrue(shardParams.contains("shard.key="), "Shard Parameters Not as expected for the Shard Method: EXPLICIT_ID"); break; default: - throw new AssertionError("Shard Method Not expected: " + model.getShardMethod() + ": " + shardParams.toString()); + throw new AssertionError("Shard Method Not expected: " + model.getShardMethod()); } } } From 2de5324573e1849b0e19513b67deae5e5292b0df Mon Sep 17 00:00:00 2001 From: mbhave Date: Fri, 28 Feb 2020 12:48:57 +0000 Subject: [PATCH 77/94] Search-2088: Updated comments in the test to simplify understanding --- .../search/SearchPermissionsTest.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java index 763322842..7b23b59c3 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java @@ -113,6 +113,14 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest @Test(priority = 1) public void searchResultsRespectInheritedPermissions() { + /** + * Private Site Folder Structure available for this test + * |- permGrandParent + * |-- permChild1 + * |------ permFile1 (inheritance disabled, deny permission to testUser1) + * |-- permChild2 + * |------ permFile2 (inheritance disabled, allow permission to testUser2) + */ // Search as testUser: expect all: 5 results: When user is a Site Manager SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); int resultCount = response.getPagination().getCount(); @@ -138,7 +146,7 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest public void searchResultsRespectInheritedPermissionsDisabled() throws Exception { // Create folder - FolderModel folder3 = dataContent.usingUser(testUser).usingSite(testSite).usingResource(parentFolder).createFolderCmisApi("permChild32"); + FolderModel folder3 = dataContent.usingUser(testUser).usingSite(testSite).usingResource(parentFolder).createFolderCmisApi("permChild3"); // Turn off inherited permissions for folder3 JsonObject userPermission = Json.createObjectBuilder().add("permissions", Json.createObjectBuilder().add("isInheritanceEnabled", false)).build(); @@ -148,10 +156,20 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest // Wait for indexing waitForIndexing(folder3.getName(), true); - // Search as testUser: expect all: 5 results: When user is a Site Manager + /** + * Private Site Folder Structure available now for this test + * |- permGrandParent + * |-- permChild1 + * |------ permFile1 (inheritance disabled, deny permission to testUser1) + * |-- permChild2 + * |------ permFile2 (inheritance disabled, allow permission to testUser2) + * |-- permChild3 (inheritance disabled) + */ + + // Search as testUser: expect all: 6 results: When user is a Site Manager SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); int resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 6, "Unexpected Result count for testUser: Expected 5, received: " + resultCount); + Assert.assertTrue(resultCount == 6, "Unexpected Result count for testUser: Expected 6, received: " + resultCount); // Search as testUser1: expect 3 results: when user is a site member but without permission to a content response = queryAsUser(testUser1, "cm:name:perm*"); From 339ff5d4c1800dca54d1b59311a61db59cf1b6cd Mon Sep 17 00:00:00 2001 From: mbhave Date: Fri, 28 Feb 2020 15:13:12 +0000 Subject: [PATCH 78/94] Search-2088: Changes assertTrue to assertEquals --- .../search/SearchPermissionsTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java index 7b23b59c3..f2b79e547 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchPermissionsTest.java @@ -124,22 +124,22 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest // Search as testUser: expect all: 5 results: When user is a Site Manager SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); int resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 5, "Unexpected Result count for testUser: Expected 5, received: " + resultCount); + Assert.assertEquals(resultCount, 5, "Unexpected Result count for testUser: Expected 5, received: " + resultCount); // Search as testUser1: expect 3 results: when user is a site member but without permission to a content response = queryAsUser(testUser1, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); + Assert.assertEquals(resultCount, 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); // Search as testUser2: expect 1 result: When user isn't a site member but has granular permissions to a content response = queryAsUser(testUser2, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); + Assert.assertEquals(resultCount, 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); // Search as testUser3: expect none: 0 results: When user isn't a site member / does not have granular permissions to the content response = queryAsUser(testUser3, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); + Assert.assertEquals(resultCount, 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); } @Test(priority = 2) @@ -169,22 +169,22 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest // Search as testUser: expect all: 6 results: When user is a Site Manager SearchResponse response = queryAsUser(testUser, "cm:name:perm*"); int resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 6, "Unexpected Result count for testUser: Expected 6, received: " + resultCount); + Assert.assertEquals(resultCount, 6, "Unexpected Result count for testUser: Expected 6, received: " + resultCount); // Search as testUser1: expect 3 results: when user is a site member but without permission to a content response = queryAsUser(testUser1, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); + Assert.assertEquals(resultCount, 3, "Unexpected Result count for testUser1: Expected 3, received: " + resultCount); // Search as testUser2: expect 1 result: When user isn't a site member but has granular permissions to a content response = queryAsUser(testUser2, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); + Assert.assertEquals(resultCount, 1, "Unexpected Result count for testUser2: Expected 1, received: " + resultCount); // Search as testUser3: expect none: 0 results: When user isn't a site member / does not have granular permissions to the content response = queryAsUser(testUser3, "cm:name:perm*"); resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); + Assert.assertEquals(resultCount, 0, "Unexpected Result count for testUser3: Expected 0, received: " + resultCount); } @Test(priority = 3) @@ -217,6 +217,6 @@ public class SearchPermissionsTest extends AbstractE2EFunctionalTest // Query SearchResponse response = queryAsUser(testUser, folderName); int resultCount = response.getPagination().getCount(); - Assert.assertTrue(resultCount == 1, "Unexpected Result count for testUser: Expected 1, received: " + resultCount); + Assert.assertEquals(resultCount, 1, "Unexpected Result count for testUser: Expected 1, received: " + resultCount); } } From ff6e588551832d3ba90867cbf1964b84a573f8b4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 22:16:09 +0000 Subject: [PATCH 79/94] Bump randomizedtesting-runner from 2.7.6 to 2.7.7 in /search-services Bumps randomizedtesting-runner from 2.7.6 to 2.7.7. Signed-off-by: dependabot-preview[bot] --- search-services/alfresco-search/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/alfresco-search/pom.xml b/search-services/alfresco-search/pom.xml index fa8b7d7b8..ab8c550b9 100644 --- a/search-services/alfresco-search/pom.xml +++ b/search-services/alfresco-search/pom.xml @@ -181,7 +181,7 @@ com.carrotsearch.randomizedtesting randomizedtesting-runner - 2.7.6 + 2.7.7 test From 000565a782c2903bebee6422604440446de87b5b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2020 22:12:17 +0000 Subject: [PATCH 80/94] Bump dependency.jackson.version in /search-services Bumps `dependency.jackson.version` from 2.10.2 to 2.10.3. Updates `jackson-core` from 2.10.2 to 2.10.3 - [Release notes](https://github.com/FasterXML/jackson-core/releases) - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.10.2...jackson-core-2.10.3) Updates `jackson-annotations` from 2.10.2 to 2.10.3 - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) Updates `jackson-databind` from 2.10.2 to 2.10.3 - [Release notes](https://github.com/FasterXML/jackson/releases) - [Commits](https://github.com/FasterXML/jackson/commits) Signed-off-by: dependabot-preview[bot] --- search-services/alfresco-solrclient-lib/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/alfresco-solrclient-lib/pom.xml b/search-services/alfresco-solrclient-lib/pom.xml index b0a866644..9a0b643a7 100644 --- a/search-services/alfresco-solrclient-lib/pom.xml +++ b/search-services/alfresco-solrclient-lib/pom.xml @@ -23,7 +23,7 @@ 8.87 - 2.10.2 + 2.10.3 From 182d6d9ed967132470ff4a367e2a60eadecb20c7 Mon Sep 17 00:00:00 2001 From: Tom Page Date: Wed, 4 Mar 2020 08:28:55 +0000 Subject: [PATCH 81/94] Update license notice for Jackson 2.10.3. --- .../packaging/src/main/resources/licenses/notice.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/search-services/packaging/src/main/resources/licenses/notice.txt b/search-services/packaging/src/main/resources/licenses/notice.txt index b3eb46870..9b216f7cc 100644 --- a/search-services/packaging/src/main/resources/licenses/notice.txt +++ b/search-services/packaging/src/main/resources/licenses/notice.txt @@ -52,9 +52,9 @@ cxf-rt-wsdl-3.2.12.jar https://cxf.apache.org/ chemistry-opencmis-server-support-1.0.0.jar http://chemistry.apache.org/ chemistry-opencmis-server-bindings-1.0.0.jar http://chemistry.apache.org/ quartz-2.3.2.jar http://quartz-scheduler.org/ -jackson-core-2.10.2.jar https://github.com/FasterXML/jackson -jackson-annotations-2.10.2.jar https://github.com/FasterXML/jackson -jackson-databind-2.10.2.jar https://github.com/FasterXML/jackson +jackson-core-2.10.3.jar https://github.com/FasterXML/jackson +jackson-annotations-2.10.3.jar https://github.com/FasterXML/jackson +jackson-databind-2.10.3.jar https://github.com/FasterXML/jackson commons-httpclient-3.1-HTTPCLIENT-1265.jar http://jakarta.apache.org/commons/ spring-aop-5.2.3.RELEASE.jar http://projects.spring.io/spring-framework/ spring-beans-5.2.3.RELEASE.jar http://projects.spring.io/spring-framework/ From dbd4b51526af7766ce5bfd5359fc063474661f0d Mon Sep 17 00:00:00 2001 From: Tom Page Date: Wed, 4 Mar 2020 08:34:21 +0000 Subject: [PATCH 82/94] Update license notice for jibx-run 1.3.3. --- .../packaging/src/main/resources/licenses/notice.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/search-services/packaging/src/main/resources/licenses/notice.txt b/search-services/packaging/src/main/resources/licenses/notice.txt index b3eb46870..1acfa1cc8 100644 --- a/search-services/packaging/src/main/resources/licenses/notice.txt +++ b/search-services/packaging/src/main/resources/licenses/notice.txt @@ -98,7 +98,7 @@ javax.activation-api-1.2.0.jar https://github.com/javaee/activation/blob/master === BSD === -jibx-run-1.3.1.jar http://jibx.sourceforge.net/ +jibx-run-1.3.3.jar http://jibx.sourceforge.net/ dom4j-2.1.1.jar https://github.com/dom4j/dom4j/blob/master/LICENSE From 0394b207166d485802599a680f86a5674a99cddd Mon Sep 17 00:00:00 2001 From: Keerat Date: Wed, 4 Mar 2020 09:20:21 +0000 Subject: [PATCH 83/94] SEARCH-2078 adding solr call to get response for failing test --- .../functional/searchServices/search/SearchSpellCheckTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index 5afb9fce9..fb21ef6d7 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -316,6 +316,9 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest Assert.assertTrue(isContentInSearchResponse(response, file.getName()), "Expected file not returned in the search results: " + file.getName()); Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file.getName()); testSearchSpellcheckResponse(response, "searchInsteadFor", "eklipse"); + + // TODO: Add 2 Solr Queries, one for each shard to check the suggestions on each shard + restClient.authenticateUser(testUser).withParams("spellcheck.q=eclipses&spellcheck=on").withSolrAPI().getSelectQuery(); // Incorrect spelling with no field for file2 response = SearchSpellcheckQuery(testUser, "eclipses", "eclipses"); From d92697c71b12b3bb47bd1a019248ae1030ee59b7 Mon Sep 17 00:00:00 2001 From: mbhave Date: Wed, 4 Mar 2020 11:52:48 +0000 Subject: [PATCH 84/94] Search-2078: Added some logging for the failing tests to capture solr response --- .../searchServices/search/SearchSpellCheckTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index fb21ef6d7..1e404e9a3 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -317,7 +317,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file.getName()); testSearchSpellcheckResponse(response, "searchInsteadFor", "eklipse"); - // TODO: Add 2 Solr Queries, one for each shard to check the suggestions on each shard + // Add Solr Query, to check the suggestions on each shard restClient.authenticateUser(testUser).withParams("spellcheck.q=eclipses&spellcheck=on").withSolrAPI().getSelectQuery(); // Incorrect spelling with no field for file2 @@ -466,6 +466,9 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file2.getName()); testSearchSpellcheckResponse(response, null, null); + // Add Solr Query, to check the suggestions on the shard + restClient.authenticateUser(testUser).withParams("spellcheck.q=spaceber&spellcheck=on").withSolrAPI().getSelectQuery(); + // Checks for User 2 // Incorrect spelling for files created no field response = SearchSpellcheckQuery(testUser2, "spaceber", "spaceber"); From abc8eef3a63c003984d245d082f2e0268095f3dc Mon Sep 17 00:00:00 2001 From: mbhave Date: Wed, 4 Mar 2020 11:54:39 +0000 Subject: [PATCH 85/94] Search-2078: Added new version of TAS Rest API required for fixing the solr-search api port configuration issue --- e2e-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/pom.xml b/e2e-test/pom.xml index 197a51181..586b8f9ae 100644 --- a/e2e-test/pom.xml +++ b/e2e-test/pom.xml @@ -11,7 +11,7 @@ Search Analytics E2E Tests Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share - 1.33 + 1.35 1.13 3.0.19 3.3.0.1 From 73efb64cfbc67fcf94749f0985ea44696d933b9f Mon Sep 17 00:00:00 2001 From: agazzarini Date: Wed, 4 Mar 2020 13:29:13 +0100 Subject: [PATCH 86/94] [ SEARCH-2108 ] Fix, Integration Test and Javadoc --- .../org/alfresco/solr/AbstractAlfrescoDistributedIT.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AbstractAlfrescoDistributedIT.java b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AbstractAlfrescoDistributedIT.java index 77c6d5f58..7b3650462 100644 --- a/search-services/alfresco-search/src/test/java/org/alfresco/solr/AbstractAlfrescoDistributedIT.java +++ b/search-services/alfresco-search/src/test/java/org/alfresco/solr/AbstractAlfrescoDistributedIT.java @@ -225,6 +225,15 @@ public abstract class AbstractAlfrescoDistributedIT extends SolrITInitializer } } + public static void explicitCommitOnAllClients() throws Exception + { + List clients = getStandaloneAndShardedClients(); + + for (SolrClient client : clients) { + client.commit(); + } + } + /** * Gets the Default test client. */ From 77e1ef2fb1242da9804f4da97b2b77de99c84974 Mon Sep 17 00:00:00 2001 From: mbhave Date: Thu, 5 Mar 2020 18:37:59 +0000 Subject: [PATCH 87/94] Search-2116: Added some tests for testing pagination for search and sql queries --- .../functional/AbstractE2EFunctionalTest.java | 56 +++- .../search/SearchQueryPaginationTest.java | 265 ++++++++++++++++++ 2 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java index d65cfac7c..601fee8d7 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/AbstractE2EFunctionalTest.java @@ -22,6 +22,7 @@ import org.alfresco.dataprep.SiteService.Visibility; import org.alfresco.rest.core.RestProperties; import org.alfresco.rest.core.RestWrapper; import org.alfresco.rest.model.RestRequestSpellcheckModel; +import org.alfresco.rest.search.Pagination; import org.alfresco.rest.search.RestRequestHighlightModel; import org.alfresco.rest.search.RestRequestQueryModel; import org.alfresco.rest.search.SearchRequest; @@ -394,10 +395,15 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont return restClient.authenticateUser(user).withSearchAPI().search(searchRequest); } - protected SearchResponse queryAsUser(UserModel user, RestRequestQueryModel queryModel) + protected SearchResponse queryAsUser(UserModel user, RestRequestQueryModel queryModel, Pagination paging) { SearchRequest searchRequest = new SearchRequest(); searchRequest.setQuery(queryModel); + + if (ofNullable(paging).isPresent()) + { + searchRequest.setPaging(paging); + } return restClient.authenticateUser(user).withSearchAPI().search(searchRequest); } @@ -437,7 +443,7 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont */ protected SearchResponse testSearchQuery(String query, Integer expectedCount, SearchLanguage queryLanguage) { - SearchResponse response = performSearch(testUser, query, queryLanguage); + SearchResponse response = performSearch(testUser, query, queryLanguage, getDefaultPagingOptions()); if (ofNullable(expectedCount).isPresent()) { @@ -456,7 +462,7 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont */ protected SearchResponse testSearchQueryOrdered(String query, List expectedNames, SearchLanguage queryLanguage) { - SearchResponse response = performSearch(testUser, query, queryLanguage); + SearchResponse response = performSearch(testUser, query, queryLanguage, getDefaultPagingOptions()); List names = response.getEntries().stream().map(s -> s.getModel().getName()).collect(Collectors.toList()); @@ -475,7 +481,7 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont */ protected SearchResponse testSearchQueryUnordered(String query, Set expectedNames, SearchLanguage queryLanguage) { - SearchResponse response = performSearch(testUser, query, queryLanguage); + SearchResponse response = performSearch(testUser, query, queryLanguage, getDefaultPagingOptions()); Set names = response.getEntries().stream().map(s -> s.getModel().getName()).collect(Collectors.toSet()); @@ -484,7 +490,7 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont return response; } - private SearchResponse performSearch(UserModel asUser, String query, SearchLanguage queryLanguage) + protected SearchResponse performSearch(UserModel asUser, String query, SearchLanguage queryLanguage, Pagination paging) { RestRequestQueryModel queryModel = new RestRequestQueryModel(); queryModel.setQuery(query); @@ -499,11 +505,49 @@ public abstract class AbstractE2EFunctionalTest extends AbstractTestNGSpringCont queryModel.setLanguage(queryLanguage.toString()); } - SearchResponse response = queryAsUser(asUser, queryModel); + SearchResponse response = queryAsUser(asUser, queryModel, paging); return response; } + /** + * Returns pagination object with alfresco default settings + * Sets skipCount = 0, maxItems = 100 + * + * @return + */ + private Pagination getDefaultPagingOptions() + { + Pagination paging = new Pagination(); + paging.setSkipCount(0); + paging.setMaxItems(100); + + return paging; + } + + /** + * Set the pagination options for the API query + * @param skipCount Integer + * @param maxItems Integer + * @return + */ + protected Pagination setPaging(Integer skipCount, Integer maxItems) + { + Pagination paging = new Pagination(); + + if (ofNullable(skipCount).isPresent()) + { + paging.setSkipCount(skipCount); + } + + if (ofNullable(maxItems).isPresent()) + { + paging.setMaxItems(maxItems); + } + + return paging; + } + /** * Method to create and run a simple spellcheck query * When a spellcheck query is run a user, the query inputed and the user query is inputted diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java new file mode 100644 index 000000000..e79402d6f --- /dev/null +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java @@ -0,0 +1,265 @@ +/* + * Copyright 2019 Alfresco Software, Ltd. All rights reserved. + * License rights for this program may be obtained from Alfresco Software, Ltd. + * pursuant to a written agreement and any use of this program without such an + * agreement is prohibited. + */ + +package org.alfresco.test.search.functional.searchServices.search; + +import org.alfresco.rest.search.SearchResponse; +import org.alfresco.test.search.functional.searchServices.cmis.AbstractCmisE2ETest; +import org.alfresco.utility.model.FileModel; +import org.alfresco.utility.model.FileType; +import org.alfresco.utility.model.FolderModel; +import org.alfresco.utility.model.UserModel; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * The purpose of this test is to test search query pagination using cmis and afts query + * + * @author Meenal Bhave + */ +public class SearchQueryPaginationTest extends AbstractCmisE2ETest +{ + private UserModel testUser2; + private FolderModel testFolder ; + private FileModel testFile; + + @BeforeClass(alwaysRun = true) + public void dataPreparation() throws Exception + { + // Create testUser2: This user does not have access to the testSite + testUser2 = dataUser.createRandomTestUser("testUser2"); + + // Create a new folder and 10 files inside the folder + testFolder = dataContent.usingUser(testUser).usingSite(testSite).createFolder(); + + for (int i = 0; i < 10; i++) + { + testFile = new FileModel(i + "-File.txt", unique_searchString, "", FileType.TEXT_PLAIN); + dataContent.usingUser(testUser).usingSite(testSite).usingResource(testFolder).createContent(testFile); + } + + waitForMetadataIndexing(testFile.getName(), true); + } + + @Test(priority = 1) + public void testCmisSearchWithPagination() + { + // Search for the cmis documents using cmis query + String query = "select * from cmis:document"; + + // Set skipCount = 0, maxItems = 1000 + SearchResponse response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, 1000)); + + // Get getTotalItems, Expect hasModeItems = false + Integer totalDocuments = response.getPagination().getTotalItems(); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocuments/2, maxItems = 1000 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments/2, 1000)); + + // Check getTotalItems is the same, hasMoreItems = False + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocument, maxItems = 1000 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments, 1000)); + + // Check getTotalItems is the same, hasMoreItems = false + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 0, maxItems = totalDocuments/2 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, totalDocuments/2)); + + // Check getTotalItems is the same, hasMoreItems = True + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocuments/2-1, maxItems = totalDocuments/2 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments/2-1, totalDocuments/2)); + + // Check getTotalItems is the same, hasMoreItems = True + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocuments, maxItems = totalDocuments/2 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments, totalDocuments/2)); + + // Check getTotalItems is the same, hasMoreItems = false + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 0, maxItems = totalDocuments + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, totalDocuments)); + + // Check getTotalItems is the same, hasMoreItems = false + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocuments/2+1, maxItems = totalDocuments + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments/2+1, totalDocuments)); + + // Check getTotalItems is the same, hasMoreItems = false + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = totalDocuments, maxItems = totalDocuments + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments, totalDocuments)); + + // Check getTotalItems is the same, hasMoreItems = false + Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 0, maxItems = 0 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, 0)); + Assert.assertTrue(response.isEmpty(), "Empty Response, Error is expected when maxItems is <= 0"); + + // Set skipCount = totalDocuments, maxItems = 0 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments, 0)); + Assert.assertTrue(response.isEmpty(), "Empty Response, Error is expected when maxItems <= 0"); + + // Set skipCount = -1, maxItems = 1 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(-1, 1)); + Assert.assertTrue(response.isEmpty(), "Empty Response, Error is expected when skipCount < 0"); + } + + @Test(priority = 2) + public void testPagination() + { + // Search for the files under the testFolder using cmis query + String parentId = testFolder.getNodeRefWithoutVersion(); + String query = "select * from cmis:document where IN_FOLDER('" + parentId + "')"; + + // Set skipCount = 0, maxItems = 100 + SearchResponse response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, 100)); + + // Check getTotalItems = 10, Expect hasModeItems = false + testPaginationDetails(response, 10, 0, 100); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 0, maxItems = 10: Expect hasModeItems = false + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, 10)); + + testPaginationDetails(response, 10, 0, 10); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 0, maxItems = 5: Expect hasModeItems = true + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(0, 5)); + + testPaginationDetails(response, 10, 0, 5); + Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 2, maxItems = 10: Expect hasModeItems = false + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(2, 10)); + + testPaginationDetails(response, 10, 2, 10); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 2, maxItems = 7: Expect hasModeItems = true + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(2, 7)); + + testPaginationDetails(response, 10, 2, 7); + Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 2, maxItems = 8: Expect hasModeItems = false + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(2, 8)); + + testPaginationDetails(response, 10, 2, 8); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + } + + @Test(priority = 3) + public void testPaginationRespectsACLs() + { + // Search for the files under the testFolder using cmis query + String parentId = testFolder.getNodeRefWithoutVersion(); + String query = "select * from cmis:document where IN_FOLDER('" + parentId + "')"; + + // Set skipCount = 0, maxItems = 100 + SearchResponse response = performSearch(testUser2, query, SearchLanguage.CMIS, setPaging(0, 100)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 0, 0, 100); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 1, maxItems = 1 + response = performSearch(testUser2, query, SearchLanguage.CMIS, setPaging(1, 1)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 0, 1, 1); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + } + + @Test(priority = 4) + public void testSearchApiPagination() + { + // Search for the files with specific title + String query = "cm:title:'" + unique_searchString + "'"; + + // Set skipCount = 0, maxItems = 100 + SearchResponse response = performSearch(testUser, query, SearchLanguage.AFTS, setPaging(0, 100)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 10, 0, 100); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 1, maxItems = 1 + response = performSearch(testUser, query, SearchLanguage.AFTS, setPaging(1, 1)); + + // Get getTotalItems, Expect hasModeItems = true + testPaginationDetails(response, 10, 1, 1); + Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 9, maxItems = 10 + response = performSearch(testUser, query, SearchLanguage.AFTS, setPaging(9, 10)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 10, 9, 10); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 10, maxItems = 10 + response = performSearch(testUser, query, SearchLanguage.AFTS, setPaging(10, 10)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 10, 10, 10); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + } + + @Test(priority = 5) + public void testSearchApiPaginationRespectsACLs() + { + // Search for the files with specific title + String query = "cm:title:'" + unique_searchString + "'"; + + // Set skipCount = 0, maxItems = 100 + SearchResponse response = performSearch(testUser2, query, SearchLanguage.AFTS, setPaging(0, 100)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 0, 0, 100); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + + // Set skipCount = 1, maxItems = 1 + response = performSearch(testUser2, query, SearchLanguage.AFTS, setPaging(1, 1)); + + // Get getTotalItems, Expect hasModeItems = false + testPaginationDetails(response, 0, 1, 1); + Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); + } + + private void testPaginationDetails(SearchResponse response, int expectedTotalCount, int skipCount, int maxItems) + { + Assert.assertEquals(response.getPagination().getTotalItems().intValue(), expectedTotalCount, "Unexpected document count"); + + Assert.assertEquals(response.getPagination().getSkipCount(), skipCount, "Unexpected skip count returned"); + Assert.assertEquals(response.getPagination().getMaxItems(), maxItems, "Unexpected maxItems returned"); + + // count = (total-skipCount) < maxItems ? total-skipCount: maxItems + int expectedCount = (expectedTotalCount < skipCount) ? 0 : (expectedTotalCount-skipCount) < maxItems ? expectedTotalCount-skipCount : maxItems; + Assert.assertEquals(response.getPagination().getCount(), expectedCount, "Unexpected document count"); + } +} From 9616698acb75e3dbfdc85110c1448e956a8e891c Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 5 Mar 2020 19:09:03 +0000 Subject: [PATCH 88/94] SEARCH-2078 fix for the spellcheck ACL test in a sharded mode --- .../functional/searchServices/search/SearchSpellCheckTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index 5afb9fce9..3fbb5a864 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -472,7 +472,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest testSearchSpellcheckResponse(response, "searchInsteadFor", "spacecar"); // correct spelling no field - response = SearchSpellcheckQuery(testUser2, "spacebar", "spacebar"); + response = SearchSpellcheckQuery(testUser2, "spacebur", "spacebur"); // Matching Result, Spellcheck = searchInsteadFor: spacecar Assert.assertFalse(isContentInSearchResponse(response, file1.getName()), "Expected file not returned in the search results: " + file1.getName()); From 907041b8df52f453e5f6cf9ee94f01f47ae340f8 Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 5 Mar 2020 19:17:31 +0000 Subject: [PATCH 89/94] SEARCH-2078 fix for the spellcheck parameter test in a sharded mode --- .../functional/searchServices/search/SearchSpellCheckTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index 3fbb5a864..26659d591 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -318,7 +318,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest testSearchSpellcheckResponse(response, "searchInsteadFor", "eklipse"); // Incorrect spelling with no field for file2 - response = SearchSpellcheckQuery(testUser, "eclipses", "eclipses"); + response = SearchSpellcheckQuery(testUser, "eclipsess", "eclipsess"); // Matching Result, Spellcheck = searchInsteadFor: eklipses Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file.getName()); From 548c5794511e6e2ec5185534dcb0429918789d75 Mon Sep 17 00:00:00 2001 From: Keerat Date: Thu, 5 Mar 2020 21:40:30 +0000 Subject: [PATCH 90/94] SEARCH-2078 fix for the spellcheck ACL test in a sharded mode --- .../functional/searchServices/search/SearchSpellCheckTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index 26659d591..4823fe29a 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -465,7 +465,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest // Checks for User 2 // Incorrect spelling for files created no field - response = SearchSpellcheckQuery(testUser2, "spaceber", "spaceber"); + response = SearchSpellcheckQuery(testUser2, "spacefur", "spacefur"); // Matching Result, Spellcheck = searchInsteadFor: spacecar Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file2.getName()); From d5eefa5d946a15845959df8ab381f71e6ff1c2d9 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 6 Mar 2020 12:44:55 +0000 Subject: [PATCH 91/94] SEARCH-2078 fix for the spellcheck ACL test in a sharded mode --- .../searchServices/search/SearchSpellCheckTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index b0c150033..fe0fb1c8b 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -471,14 +471,14 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest // Checks for User 2 // Incorrect spelling for files created no field - response = SearchSpellcheckQuery(testUser2, "spacefur", "spacefur"); + response = SearchSpellcheckQuery(testUser2, "spacebur", "spacebur"); // Matching Result, Spellcheck = searchInsteadFor: spacecar Assert.assertTrue(isContentInSearchResponse(response, file2.getName()), "Expected file not returned in the search results: " + file2.getName()); testSearchSpellcheckResponse(response, "searchInsteadFor", "spacecar"); // correct spelling no field - response = SearchSpellcheckQuery(testUser2, "spacebur", "spacebur"); + response = SearchSpellcheckQuery(testUser2, "spacebar", "spacebar"); // Matching Result, Spellcheck = searchInsteadFor: spacecar Assert.assertFalse(isContentInSearchResponse(response, file1.getName()), "Expected file not returned in the search results: " + file1.getName()); From 5d9c90ea7e03605913a843c034d1d1c01e5a24f4 Mon Sep 17 00:00:00 2001 From: Keerat Date: Fri, 6 Mar 2020 12:52:55 +0000 Subject: [PATCH 92/94] SEARCH-2078 fix for the spellcheck with the new queries --- .../searchServices/search/SearchSpellCheckTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java index fe0fb1c8b..d695b6b23 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchSpellCheckTest.java @@ -318,7 +318,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest testSearchSpellcheckResponse(response, "searchInsteadFor", "eklipse"); // Add Solr Query, to check the suggestions on each shard - restClient.authenticateUser(testUser).withParams("spellcheck.q=eclipses&spellcheck=on").withSolrAPI().getSelectQuery(); + restClient.authenticateUser(testUser).withParams("spellcheck.q=eclipsess&spellcheck=on").withSolrAPI().getSelectQuery(); // Incorrect spelling with no field for file2 response = SearchSpellcheckQuery(testUser, "eclipsess", "eclipsess"); @@ -467,7 +467,7 @@ public class SearchSpellCheckTest extends AbstractSearchServicesE2ETest testSearchSpellcheckResponse(response, null, null); // Add Solr Query, to check the suggestions on the shard - restClient.authenticateUser(testUser).withParams("spellcheck.q=spaceber&spellcheck=on").withSolrAPI().getSelectQuery(); + restClient.authenticateUser(testUser).withParams("spellcheck.q=spacebur&spellcheck=on").withSolrAPI().getSelectQuery(); // Checks for User 2 // Incorrect spelling for files created no field From f4f00bf9325d1bf96f2a28f2601b5c3c5c283a16 Mon Sep 17 00:00:00 2001 From: mbhave Date: Fri, 6 Mar 2020 14:54:38 +0000 Subject: [PATCH 93/94] Search-2116: Removed redundant test and simplified a test --- .../search/SearchQueryPaginationTest.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java index e79402d6f..92ab67fb7 100644 --- a/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java +++ b/e2e-test/src/test/java/org/alfresco/test/search/functional/searchServices/search/SearchQueryPaginationTest.java @@ -59,13 +59,6 @@ public class SearchQueryPaginationTest extends AbstractCmisE2ETest Integer totalDocuments = response.getPagination().getTotalItems(); Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); - // Set skipCount = totalDocuments/2, maxItems = 1000 - response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments/2, 1000)); - - // Check getTotalItems is the same, hasMoreItems = False - Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); - Assert.assertFalse(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); - // Set skipCount = totalDocument, maxItems = 1000 response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments, 1000)); @@ -80,8 +73,8 @@ public class SearchQueryPaginationTest extends AbstractCmisE2ETest Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); Assert.assertTrue(response.getPagination().isHasMoreItems(), "Incorrect: hasMoreItems"); - // Set skipCount = totalDocuments/2-1, maxItems = totalDocuments/2 - response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(totalDocuments/2-1, totalDocuments/2)); + // Set skipCount = 1, maxItems = totalDocuments-2 + response = performSearch(testUser, query, SearchLanguage.CMIS, setPaging(1, totalDocuments-2)); // Check getTotalItems is the same, hasMoreItems = True Assert.assertEquals(response.getPagination().getTotalItems(), totalDocuments, "Total Document Count doesn't match"); From 7e91e77eae5640c6c53603d77de0b43b29194546 Mon Sep 17 00:00:00 2001 From: Angel Borroy Date: Mon, 9 Mar 2020 11:39:59 +0100 Subject: [PATCH 94/94] SEARCH-2097: Consolidating log messages --- .../org/alfresco/solr/tracker/AbstractTracker.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java index 5c09cd0dc..47930d6c0 100644 --- a/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java +++ b/search-services/alfresco-search/src/main/java/org/alfresco/solr/tracker/AbstractTracker.java @@ -180,7 +180,7 @@ public abstract class AbstractTracker implements Tracker assert(assertTrackerStateRemainsNull()); } - LOGGER.info("[CORE {}] ... Running {}", coreName, this.getClass().getSimpleName()); + LOGGER.info("[CORE {}] Running {}", coreName, this.getClass().getSimpleName()); if(this.state == null) { @@ -211,15 +211,10 @@ public abstract class AbstractTracker implements Tracker setRollback(true, t); if (t instanceof SocketTimeoutException || t instanceof ConnectException) { + LOGGER.warn("[CORE {}] Tracking communication timed out for {}", coreName, getClass().getSimpleName()); if (LOGGER.isDebugEnabled()) { - // DEBUG, so give the whole stack trace - LOGGER.warn("[CORE {}] Tracking communication timed out for {}", coreName, getClass().getSimpleName(), t); - } - else - { - // We don't need the stack trace. It timed out. - LOGGER.warn("[CORE {}] Tracking communication timed out for {}", coreName, getClass().getSimpleName()); + LOGGER.debug("[CORE {}] Stack trace", coreName, t); } } else