From 263495aaf3ef829c68072679293856083b370df9 Mon Sep 17 00:00:00 2001 From: Meenal Bhave Date: Tue, 14 Aug 2018 15:19:09 +0100 Subject: [PATCH] Fix/search 892 --- .../main/resources/model/flipStatus-model.xml | 107 +++++++++++++ .../search/AbstractSearchServiceE2E.java | 146 +++++++++++++++--- .../sql/CustomModelChangesTest.java | 126 +++++++++++++++ .../service/search/unit/SetupTest.java | 35 +++-- e2e-test/src/test/resources/SearchSuite.xml | 40 +++-- .../{config.properties => default.properties} | 2 +- 6 files changed, 408 insertions(+), 48 deletions(-) create mode 100644 e2e-test/src/main/resources/model/flipStatus-model.xml create mode 100644 e2e-test/src/test/java/org/alfresco/service/search/e2e/insightEngine/sql/CustomModelChangesTest.java rename e2e-test/src/test/resources/{config.properties => default.properties} (97%) diff --git a/e2e-test/src/main/resources/model/flipStatus-model.xml b/e2e-test/src/main/resources/model/flipStatus-model.xml new file mode 100644 index 000000000..9be97049d --- /dev/null +++ b/e2e-test/src/main/resources/model/flipStatus-model.xml @@ -0,0 +1,107 @@ + + + Administrator + + + + + + + + + + + + song + cm:content + + + lyricist + d:text + false + + TRUE + true + + + + artist-singer-male + d:text + false + + TRUE + false + + + + genre + d:text + false + false + + BOTH + true + + + + lyrics + d:mltext + false + + TRUE + false + + + + popular + d:boolean + false + false + + TRUE + + + + artist-singer-female + d:text + false + + TRUE + false + + + + + + + + + + + AudioVisual + + + video + d:boolean + false + false + + TRUE + + + + audio + d:boolean + false + true + + TRUE + + + + + + + + + \ No newline at end of file diff --git a/e2e-test/src/test/java/org/alfresco/service/search/AbstractSearchServiceE2E.java b/e2e-test/src/test/java/org/alfresco/service/search/AbstractSearchServiceE2E.java index ac1c97b07..10acedca1 100644 --- a/e2e-test/src/test/java/org/alfresco/service/search/AbstractSearchServiceE2E.java +++ b/e2e-test/src/test/java/org/alfresco/service/search/AbstractSearchServiceE2E.java @@ -7,11 +7,6 @@ package org.alfresco.service.search; * agreement is prohibited. */ -import static lombok.AccessLevel.PROTECTED; - - -import javax.naming.AuthenticationException; - import org.alfresco.cmis.CmisWrapper; import org.alfresco.dataprep.ContentService; import org.alfresco.rest.core.RestProperties; @@ -25,7 +20,10 @@ import org.alfresco.utility.Utility; import org.alfresco.utility.data.DataContent; import org.alfresco.utility.data.DataSite; import org.alfresco.utility.data.DataUser; +import org.alfresco.utility.model.FileModel; import org.alfresco.utility.network.ServerHealth; +import org.apache.chemistry.opencmis.client.api.CmisObject; +import org.apache.chemistry.opencmis.client.api.Session; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -34,6 +32,7 @@ import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.annotations.BeforeSuite; import lombok.Getter; +import static lombok.AccessLevel.PROTECTED; /** * @author meenal bhave @@ -82,8 +81,8 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte try { - dataContent.usingAdmin().deployContentModel("model/music-model.xml"); - dataContent.usingAdmin().deployContentModel("model/finance-model.xml"); + deployCustomModel("model/music-model.xml"); + deployCustomModel("model/finance-model.xml"); } catch (Exception e) { @@ -91,6 +90,114 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte } } + public boolean deployCustomModel(String path) + { + Boolean modelDeployed = false; + + if ((path != null) && (path.endsWith("-model.xml"))) + { + try + { + dataContent.usingAdmin().deployContentModel(path); + modelDeployed = true; + } + catch (Exception e) + { + LOG.warn("Error Loading Custom Model", e); + } + } + return modelDeployed; + } + + public boolean deactivateCustomModel(String fileName) + { + Boolean modelDeactivated = false; + + try + { + FileModel customModel = getCustomModel(fileName); + + // Deactivate the model if found + if (customModel != null) + { + + cmisApi.authenticateUser(dataUser.getAdminUser()).usingResource(customModel).updateProperty("cm:modelActive", false); + + modelDeactivated = true; + } + } + catch (Exception e) + { + LOG.warn("Error Deactivating Custom Model", e); + } + return modelDeactivated; + } + + public boolean deleteCustomModel(String fileName) + { + Boolean modelDeleted = false; + + try + { + FileModel customModel = getCustomModel(fileName); + + // Delete the model if found + if (customModel != null) + { + // cmisApi.authenticateUser(dataUser.getAdminUser()).usingResource(customModel).deleteContent(); + dataContent.usingAdmin().usingResource(customModel).deleteContent(); + restClient.authenticateUser(dataContent.getAdminUser()).withCoreAPI().usingTrashcan().deleteNodeFromTrashcan(customModel); + + modelDeleted = true; + } + else + { + LOG.error("Custom Content Model [{}] is not available under [/Data Dictionary/Models/] location", fileName); + } + } + catch (Exception e) + { + LOG.error("Custom Content Model [{}] is not available under [/Data Dictionary/Models/] location", fileName); + } + + return modelDeleted; + } + + private FileModel getCustomModel(String fileName) + { + FileModel customModel = null; + + try + { + if ((fileName != null) && (fileName.endsWith("-model.xml"))) + + { + Session session = contentService.getCMISSession(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword()); + + CmisObject modelInRepo = session.getObjectByPath(String.format("/Data Dictionary/Models/%s", fileName)); + + if (modelInRepo != null) + { + customModel = new FileModel(modelInRepo.getName()); + customModel.setNodeRef(modelInRepo.getId()); + customModel.setNodeRef(customModel.getNodeRefWithoutVersion()); + customModel.setCmisLocation(String.format("/Data Dictionary/Models/%s", fileName)); + LOG.info("Custom Model file: " + customModel.getCmisLocation()); + } + else + { + LOG.info("Custom Content Model [{}] is not available under [/Data Dictionary/Models/] location", fileName); + } + } + } + catch (Exception e) + { + LOG.warn("Error Getting Custom Model: " + fileName, e); + } + + return customModel; + } + /** * Wait for Solr to finish indexing: Indexing has caught up = true if search returns appropriate results * @@ -99,10 +206,10 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte * @return true (indexing is finished) if search returns appropriate results * @throws Exception */ - public boolean waitForIndexing(String userQuery, Boolean expectedInResults) throws Exception + public boolean waitForIndexing(String userQuery, boolean expectedInResults) throws Exception { - Boolean found = false; - Boolean resultAsExpected = false; + boolean found = false; + boolean resultAsExpected = false; String expectedStatusCode = HttpStatus.OK.toString(); Integer retryCount = 3; @@ -111,17 +218,11 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte queryReq.setQuery(userQuery); query.setQuery(queryReq); - // Using adminUser just to confirm that the content is indexed - SearchResponse response = restClient.authenticateUser(dataUser.getAdminUser()).withSearchAPI().search(query); - // Repeat search until the query results are as expected or Search Retry count is hit for (int searchCount = 1; searchCount <= retryCount; searchCount++) { - if (searchCount > 1) - { - // Wait for the solr indexing. - Utility.waitToLoopTime(properties.getSolrWaitTimeInSeconds(), "Wait For Indexing"); - } + // Using adminUser just to confirm that the content is indexed + SearchResponse response = restClient.authenticateUser(dataUser.getAdminUser()).withSearchAPI().search(query); if (restClient.getStatusCode().matches(expectedStatusCode)) { @@ -135,15 +236,20 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte } // Loop again if result is not as expected: To cater for solr lag: eventual consistency - resultAsExpected = (expectedInResults.equals(found)); + resultAsExpected = (expectedInResults == found); if (resultAsExpected) { break; } + else + { + // Wait for the solr indexing. + Utility.waitToLoopTime(properties.getSolrWaitTimeInSeconds(), "Wait For Indexing"); + } } else { - throw new AuthenticationException("API returned status code:" + restClient.getStatusCode() + " Expected: " + expectedStatusCode); + throw new RuntimeException("API returned status code:" + restClient.getStatusCode() + " Expected: " + expectedStatusCode); } } diff --git a/e2e-test/src/test/java/org/alfresco/service/search/e2e/insightEngine/sql/CustomModelChangesTest.java b/e2e-test/src/test/java/org/alfresco/service/search/e2e/insightEngine/sql/CustomModelChangesTest.java new file mode 100644 index 000000000..8b4b02597 --- /dev/null +++ b/e2e-test/src/test/java/org/alfresco/service/search/e2e/insightEngine/sql/CustomModelChangesTest.java @@ -0,0 +1,126 @@ +/* + * Copyright 2018 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.service.search.e2e.insightEngine.sql; + +import java.util.HashMap; +import java.util.Map; + +import org.alfresco.rest.core.RestResponse; +import org.alfresco.rest.search.SearchSqlRequest; +import org.alfresco.service.search.AbstractSearchServiceE2E; +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.SiteModel; +import org.alfresco.utility.model.TestGroup; +import org.alfresco.utility.model.UserModel; +import org.apache.chemistry.opencmis.commons.PropertyIds; +import org.apache.chemistry.opencmis.commons.enums.VersioningState; +import org.hamcrest.Matchers; +import org.springframework.http.HttpStatus; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * Purpose of this TestClass is to test that the SQLs work after model changes + * + * @author meenal bhave + */ +public class CustomModelChangesTest extends AbstractSearchServiceE2E +{ + protected SiteModel testSite; + + private UserModel testUser; + + private FolderModel testFolder; + + @BeforeClass(alwaysRun = true) + public void setupEnvironment() throws Exception + { + serverHealth.assertServerIsOnline(); + + deployCustomModel("model/flipStatus-model.xml"); + + testSite = dataSite.createPublicRandomSite(); + + // Create test user and add the user as a SiteContributor + testUser = dataUser.createRandomTestUser(); + + dataUser.addUserToSite(testUser, testSite, UserRole.SiteContributor); + + testFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder(); + + // Wait for the file to be indexed + waitForIndexing(testFolder.getName(), true); + } + + @AfterClass(alwaysRun=true) + public void deleteModel() + { + deleteCustomModel("flipStatus-model.xml"); + } + + // SQL works after model is deactivated + @Test(priority = 1, groups = { TestGroup.INSIGHT_10 }) + public void testSqlWorksAfterDeactivatingModel() throws Exception + { + FileModel customFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, "custom content"); + Map properties = new HashMap(); + properties.put(PropertyIds.OBJECT_TYPE_ID, "D:flipFlop:song"); + properties.put(PropertyIds.NAME, customFile.getName()); + properties.put("flipFlop:genre", "Pop"); + properties.put("flipFlop:lyricist", "SomeLyricist"); + + cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(testFolder) + .createFile(customFile, properties, VersioningState.MAJOR) + .assertThat().existsInRepo(); + + // Wait for the file to be indexed + waitForIndexing(customFile.getName(), true); + + // Query custom model fields + SearchSqlRequest sqlRequest = new SearchSqlRequest(); + sqlRequest.setSql("select cm_name, flipFlop_genre, flipFlop_lyricist from alfresco where cm_name = '" + customFile.getName() + "'"); + sqlRequest.setLimit(10); + + RestResponse response = restClient.authenticateUser(testUser).withSearchSqlAPI().searchSql(sqlRequest); + + restClient.assertStatusCodeIs(HttpStatus.OK); + response.assertThat().body("list.pagination.count", Matchers.equalTo(1)); + + // Delete File and Delete from trash + dataContent.usingSite(testSite).usingUser(testUser).usingResource(customFile).deleteContent(); + restClient.withCoreAPI().usingTrashcan().deleteNodeFromTrashcan(customFile); + + // Wait for the file delete transaction to be indexed, until Search API returns no results + Boolean fileFound = waitForIndexing("cm:name:'" + customFile.getName() + "'", false); + Assert.assertTrue(fileFound, "File appears in the search results when deleted from trash"); + + // Query custom model fields: No matching content + response = restClient.authenticateUser(testUser).withSearchSqlAPI().searchSql(sqlRequest); + restClient.assertStatusCodeIs(HttpStatus.OK); + + // Deactivate the Model + deactivateCustomModel("flipStatus-model.xml"); + + fileFound = waitForIndexing("TYPE:'" + "flipFlop:song" + "'", false); + Assert.assertTrue(fileFound, "Indexes are not updated after deactivating a model"); + + // Query OOTB fields: Custom Model Deactivated + sqlRequest = new SearchSqlRequest(); + sqlRequest.setSql("select count(*) as TotalDocuments from alfresco where type = 'cm:content'"); + + response = restClient.authenticateUser(testUser).withSearchSqlAPI().searchSql(sqlRequest); + + restClient.assertStatusCodeIs(HttpStatus.OK); + response.assertThat().body("list.pagination.count", Matchers.equalTo(1)); + } +} diff --git a/e2e-test/src/test/java/org/alfresco/service/search/unit/SetupTest.java b/e2e-test/src/test/java/org/alfresco/service/search/unit/SetupTest.java index c6bcb2978..460dfc476 100644 --- a/e2e-test/src/test/java/org/alfresco/service/search/unit/SetupTest.java +++ b/e2e-test/src/test/java/org/alfresco/service/search/unit/SetupTest.java @@ -92,8 +92,10 @@ public class SetupTest extends AbstractSearchServiceE2E properties.put("music:genre", "pop"); properties.put("music:lyricist", "Me"); - cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(testFolder).createFile(customFile, properties, VersioningState.MAJOR).assertThat() - .existsInRepo(); + cmisApi.authenticateUser(testUser).usingSite(testSite) + .usingResource(testFolder) + .createFile(customFile, properties, VersioningState.MAJOR) + .assertThat().existsInRepo(); } // Test Custom Model: Finance can be used @@ -109,8 +111,10 @@ public class SetupTest extends AbstractSearchServiceE2E properties.put("finance:ReceiptNo", 1); properties.put("finance:ReceiptValue", 30); - cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(testFolder).createFile(customFile, properties, VersioningState.MAJOR).assertThat() - .existsInRepo(); + cmisApi.authenticateUser(testUser).usingSite(testSite) + .usingResource(testFolder) + .createFile(customFile, properties, VersioningState.MAJOR) + .assertThat().existsInRepo(); Assert.assertTrue("New content could not be found", waitForIndexing("cm:name:" + customFile.getName(), true)); } @@ -126,8 +130,8 @@ public class SetupTest extends AbstractSearchServiceE2E RestResponse response = restClient.authenticateUser(testUser).withSearchSqlAPI().searchSql(sqlRequest); - restClient.assertStatusCodeIs(HttpStatus.OK); Assert.assertNotNull(response); + Assert.assertTrue("Check ACS Version is 6.0 or above and if Insight Engine is running. Response received is: " + response.getStatusCode(), HttpStatus.OK.toString().matches(response.getStatusCode())); } // Test sql can be executed via jdbc @@ -146,14 +150,21 @@ public class SetupTest extends AbstractSearchServiceE2E ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest); - while (rs.next()) + if (rs != null) { - // User can see the Public Site created by other user - Assert.assertNotNull(rs.getString("SITE")); - Assert.assertTrue(publicSite.getTitle().equalsIgnoreCase(rs.getString("SITE"))); - - Assert.assertNotNull(rs.getString("CM_OWNER")); - Assert.assertTrue(rs.getString("CM_OWNER").contains(testUser.getUsername())); + while (rs.next()) + { + // User can see the Public Site created by other user + Assert.assertNotNull(rs.getString("SITE")); + Assert.assertTrue(publicSite.getTitle().equalsIgnoreCase(rs.getString("SITE"))); + + Assert.assertNotNull(rs.getString("CM_OWNER")); + Assert.assertTrue(rs.getString("CM_OWNER").contains(testUser.getUsername())); + } + } + else + { + Assert.fail("Result Set is null, Check ACS Version is 6.0 or above and if Insight Engine is running"); } } } diff --git a/e2e-test/src/test/resources/SearchSuite.xml b/e2e-test/src/test/resources/SearchSuite.xml index de86397b9..70393bfca 100644 --- a/e2e-test/src/test/resources/SearchSuite.xml +++ b/e2e-test/src/test/resources/SearchSuite.xml @@ -2,22 +2,32 @@ - - - - - + + + - - - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + diff --git a/e2e-test/src/test/resources/config.properties b/e2e-test/src/test/resources/default.properties similarity index 97% rename from e2e-test/src/test/resources/config.properties rename to e2e-test/src/test/resources/default.properties index 858a868f7..e9ee1447e 100644 --- a/e2e-test/src/test/resources/config.properties +++ b/e2e-test/src/test/resources/default.properties @@ -1,7 +1,7 @@ # Alfresco HTTP Server Settings alfresco.scheme=http alfresco.server=localhost -alfresco.port=8080 +alfresco.port=8081 # sync service related sync.scheme=http