mirror of
https://github.com/Alfresco/SearchServices.git
synced 2026-09-16 18:12:56 +00:00
Merge branch 'fix/Search-1493' into 'master'
Fix/search 1493 See merge request search_discovery/SearchAnalyticsE2ETest!13
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package org.alfresco.service.search;
|
||||
|
||||
/*
|
||||
* Copyright 2018 Alfresco Software, Ltd. All rights reserved.
|
||||
* 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.
|
||||
@@ -13,6 +13,7 @@ import org.alfresco.dataprep.SiteService.Visibility;
|
||||
import org.alfresco.rest.core.RestProperties;
|
||||
import org.alfresco.rest.core.RestWrapper;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.SearchNodeModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.LogFactory;
|
||||
@@ -39,6 +40,8 @@ import org.testng.annotations.BeforeSuite;
|
||||
import lombok.Getter;
|
||||
import static lombok.AccessLevel.PROTECTED;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author meenal bhave
|
||||
*/
|
||||
@@ -102,8 +105,10 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte
|
||||
}
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void beforeClass() throws Exception
|
||||
{
|
||||
public void dataPreparation() throws Exception
|
||||
{
|
||||
serverHealth.assertServerIsOnline();
|
||||
|
||||
adminUserModel = dataUser.getAdminUser();
|
||||
testUser = dataUser.createRandomTestUser("UserSearch");
|
||||
|
||||
@@ -223,42 +228,150 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte
|
||||
return customModel;
|
||||
}
|
||||
|
||||
protected SearchRequest createQuery(String term)
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery(term);
|
||||
query.setQuery(queryReq);
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Helper method which create an http post request to Search API end point.
|
||||
* Executes the given search request without throwing checked exceptions (a {@link RuntimeException} will be thrown in case).
|
||||
* @param query the search request.
|
||||
* @return {@link SearchResponse} response.
|
||||
*
|
||||
*/
|
||||
protected SearchResponse query(SearchRequest query) throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
return restClient.authenticateUser(testUser).withSearchAPI().search(query);
|
||||
}
|
||||
catch (final Exception exception)
|
||||
{
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Solr to finish indexing and search to return appropriate results
|
||||
*
|
||||
* @param userQuery: Search Query
|
||||
* @param contentName that's expected to be included / excluded from the results
|
||||
* @param expectedInResults
|
||||
* @return true if search returns expected results, i.e. is given content is found or excluded from the results
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean waitForContent(String userQuery, String contentName, boolean expectedInResults) throws Exception
|
||||
{
|
||||
boolean resultAsExpected = false;
|
||||
boolean found = !expectedInResults;
|
||||
String expectedStatusCode = HttpStatus.OK.toString();
|
||||
|
||||
// Repeat search until the query results are as expected or Search Retry count is hit
|
||||
for (int searchCount = 1; searchCount <= 6; searchCount++)
|
||||
{
|
||||
SearchRequest searchRequest = createQuery(userQuery);
|
||||
SearchResponse response = query(searchRequest);
|
||||
|
||||
if (restClient.getStatusCode().matches(expectedStatusCode))
|
||||
{
|
||||
List<SearchNodeModel> entries = response.getEntries();
|
||||
if (!entries.isEmpty())
|
||||
{
|
||||
for (SearchNodeModel entry : entries)
|
||||
{
|
||||
found = (contentName.equalsIgnoreCase(entry.getModel().getName()));
|
||||
}
|
||||
}
|
||||
// Loop again if result is not as expected: To cater for solr lag: eventual consistency
|
||||
resultAsExpected = (expectedInResults == found);
|
||||
if (resultAsExpected)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for the solr indexing.
|
||||
Utility.waitToLoopTime(properties.getSolrWaitTimeInSeconds(), "Wait For Indexing. Retry Attempt: " + searchCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("API returned status code:" + restClient.getStatusCode() + " Expected: " + expectedStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
return resultAsExpected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Solr to finish indexing: Indexing has caught up = true if search returns appropriate results
|
||||
*
|
||||
* @param userQuery: string to search for, unique search string will guarantee accurate results
|
||||
* @param userQuery: search query, this can include the fieldname, unique search string will guarantee accurate results
|
||||
* @param expectedInResults, true if entry is expected in the results set
|
||||
* @return true (indexing is finished) if search returns appropriate results
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean waitForIndexing(String userQuery, boolean expectedInResults) throws Exception
|
||||
{
|
||||
boolean found = false;
|
||||
// Use the search query as is: fieldname(s) may or may not be specified within the userQuery
|
||||
return waitForIndexing(null, userQuery, expectedInResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* waitForIndexing method that matches / waits for filename, metadata to be indexed.
|
||||
* @param userQuery
|
||||
* @param expectedInResults
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean waitForMetadataIndexing(String userQuery, boolean expectedInResults) throws Exception
|
||||
{
|
||||
return waitForIndexing("name", userQuery, expectedInResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* waitForIndexing method that matches / waits for content to be indexed, this can take longer than metadata indexing.
|
||||
* Since Metadata is indexed first, use this method where tests, queries need content to be indexed too.
|
||||
* @param userQuery
|
||||
* @param expectedInResults
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public boolean waitForContentIndexing(String userQuery, boolean expectedInResults) throws Exception
|
||||
{
|
||||
return waitForIndexing("cm:content", userQuery, expectedInResults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Solr to finish indexing: Indexing has caught up = true if search returns appropriate results
|
||||
*
|
||||
* @param fieldName: specific field to search for, e.g. name. When specified, the query will become: name:'userQuery'
|
||||
* @param userQuery: search string, unique search string will guarantee accurate results
|
||||
* @param expectedInResults, true if entry is expected in the results set
|
||||
* @return true (indexing is finished) if search returns appropriate results
|
||||
* @throws Exception
|
||||
*/
|
||||
private boolean waitForIndexing(String fieldName, String userQuery, boolean expectedInResults) throws Exception
|
||||
{
|
||||
boolean resultAsExpected = false;
|
||||
String expectedStatusCode = HttpStatus.OK.toString();
|
||||
Integer retryCount = 3;
|
||||
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery(userQuery);
|
||||
query.setQuery(queryReq);
|
||||
String query = (fieldName == null)? userQuery: String.format("%s:'%s'", fieldName, userQuery);
|
||||
|
||||
// Repeat search until the query results are as expected or Search Retry count is hit
|
||||
for (int searchCount = 1; searchCount <= retryCount; searchCount++)
|
||||
for (int searchCount = 1; searchCount <= 3; searchCount++)
|
||||
{
|
||||
// Using adminUser just to confirm that the content is indexed
|
||||
SearchResponse response = restClient.authenticateUser(dataUser.getAdminUser()).withSearchAPI().search(query);
|
||||
SearchRequest searchRequest = createQuery(query);
|
||||
SearchResponse response = query(searchRequest);
|
||||
|
||||
if (restClient.getStatusCode().matches(expectedStatusCode))
|
||||
{
|
||||
if (response.getEntries().size() >= 1)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = false;
|
||||
}
|
||||
boolean found = !response.getEntries().isEmpty();
|
||||
|
||||
// Loop again if result is not as expected: To cater for solr lag: eventual consistency
|
||||
resultAsExpected = (expectedInResults == found);
|
||||
@@ -269,7 +382,7 @@ public abstract class AbstractSearchServiceE2E extends AbstractTestNGSpringConte
|
||||
else
|
||||
{
|
||||
// Wait for the solr indexing.
|
||||
Utility.waitToLoopTime(properties.getSolrWaitTimeInSeconds(), "Wait For Indexing");
|
||||
Utility.waitToLoopTime(properties.getSolrWaitTimeInSeconds(), "Wait For Indexing. Retry Attempt: " + searchCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
+70
-74
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 Alfresco Software, Ltd. All rights reserved.
|
||||
* 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.
|
||||
@@ -10,119 +10,115 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.search.AbstractSearchServiceE2E;
|
||||
import org.alfresco.utility.constants.UserRole;
|
||||
import org.alfresco.utility.data.DataContent;
|
||||
import org.alfresco.utility.data.DataSite;
|
||||
import org.alfresco.utility.model.ContentModel;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Test class tests cascading updates for a child node when parent node is updated
|
||||
*
|
||||
* @author Alessandro Benedetti
|
||||
* @author Meenal Bhave
|
||||
*/
|
||||
public class CascadingTrackerIntegrationTest extends AbstractSearchServiceE2E
|
||||
{
|
||||
@Autowired
|
||||
protected DataSite dataSite;
|
||||
|
||||
@Autowired
|
||||
protected DataContent dataContent;
|
||||
|
||||
private SiteModel testSite;
|
||||
|
||||
private UserModel testUser;
|
||||
|
||||
private FolderModel testFolder;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
serverHealth.assertServerIsOnline();
|
||||
|
||||
testSite = dataSite.createPublicRandomSite();
|
||||
testUser = dataUser.createRandomTestUser();
|
||||
dataUser.addUserToSite(testUser, testSite, UserRole.SiteContributor);
|
||||
}
|
||||
private FolderModel parentFolder, grandParentFolder, childFolder;
|
||||
private FileModel childFile, grandChildFile;
|
||||
|
||||
@Test(groups = { TestGroup.ASS_13 })
|
||||
public void testCascadingTracking_parentFolderRenaming_shouldReIndexChildren() throws Exception
|
||||
@Test(priority = 1, groups = { TestGroup.ASS_13 })
|
||||
public void testChildPathWhenParentRenamed() throws Exception
|
||||
{
|
||||
testFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder();
|
||||
// Create Parent folder
|
||||
parentFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder();
|
||||
|
||||
// Create a file in the parent folder
|
||||
childFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, "custom content");
|
||||
|
||||
FileModel customFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, "custom content");
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(PropertyIds.NAME, customFile.getName());
|
||||
|
||||
cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(testFolder)
|
||||
.createFile(customFile, properties, VersioningState.MAJOR).assertThat().existsInRepo();
|
||||
|
||||
waitForIndexing(customFile.getName(), true);
|
||||
|
||||
String parentQuery = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + testFolder.getName() + "\"";
|
||||
int initialDescendantCount = query(parentQuery).getPagination().getCount();
|
||||
properties.put(PropertyIds.NAME, childFile.getName());
|
||||
properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
|
||||
|
||||
cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(parentFolder)
|
||||
.createFile(childFile, properties, VersioningState.MAJOR).assertThat().existsInRepo();
|
||||
|
||||
// Query to find nodes where Path with original folder name matches
|
||||
String parentQuery = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + parentFolder.getName() + "\"";
|
||||
|
||||
// Rename parent folder
|
||||
String parentNewName = "parentRenamed";
|
||||
parentFolder.setName(parentNewName);
|
||||
|
||||
ContentModel parentNewNameModel = new ContentModel(parentNewName);
|
||||
dataContent.usingUser(testUser).usingResource(parentFolder).renameContent(parentNewNameModel);
|
||||
|
||||
this.dataContent.usingUser(testUser).usingResource(testFolder).renameContent(parentNewNameModel);
|
||||
|
||||
testFolder.setName(parentNewName);
|
||||
waitForIndexing(testFolder.getName(), true);
|
||||
waitForMetadataIndexing(parentNewName, true);
|
||||
|
||||
// Find nodes where Path with new folder name matches
|
||||
String parentQueryAfterRename = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + parentNewName + "\"";
|
||||
int descendantCountOfDismissedName = query(parentQuery).getPagination().getCount();
|
||||
Boolean indexingInProgress = !waitForContent(parentQueryAfterRename, childFile.getName(), true);
|
||||
|
||||
// Query using new parent name: Expect parent folder and child file
|
||||
int descendantCountOfNewName = query(parentQueryAfterRename).getPagination().getCount();
|
||||
|
||||
Assert.assertEquals(initialDescendantCount, descendantCountOfNewName);
|
||||
//Assert.assertThat("New renamed path has not the same descendants as before renaming: " + parentQueryAfterRename,descendantCountOfNewName,is(initialDescendantCount));
|
||||
|
||||
Assert.assertEquals(descendantCountOfDismissedName, 0);
|
||||
//Assert.assertThat("Old path still has descendants: " + parentQuery,descendantCountOfDismissedName,is(0));
|
||||
Assert.assertEquals(descendantCountOfNewName, 2, String.format("Indexing in progress: %s New renamed path has not the same descendants as before renaming: %s", indexingInProgress.toString(), parentQueryAfterRename));
|
||||
|
||||
// Query using old parent name: Expect no descendant after rename
|
||||
int descendantCountOfOriginalName = query(parentQuery).getPagination().getCount();
|
||||
Assert.assertEquals(descendantCountOfOriginalName, 0, "Old path still has descendants: " + parentQuery);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.ASS_13 })
|
||||
public void testCascadingTracking_granParentFolderRenaming_shouldReIndexChildren() throws Exception
|
||||
@Test(priority = 2, groups = { TestGroup.ASS_13 })
|
||||
public void testGrandChildPathWhenGrandParentRenamed() throws Exception
|
||||
{
|
||||
testFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder();
|
||||
// Create grand parent folder
|
||||
grandParentFolder = dataContent.usingSite(testSite).usingUser(testUser).createFolder();
|
||||
|
||||
// Create child folder
|
||||
FolderModel childFolder = dataContent.usingUser(testUser).usingResource(testFolder).createFolder();
|
||||
childFolder = dataContent.usingUser(testUser).usingResource(grandParentFolder).createFolder();
|
||||
|
||||
// Create grandchild file
|
||||
FileModel customFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, "custom content");
|
||||
// Create grand child file
|
||||
grandChildFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, "custom content");
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(PropertyIds.NAME, customFile.getName());
|
||||
|
||||
properties.put(PropertyIds.NAME, grandChildFile.getName());
|
||||
properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
|
||||
|
||||
cmisApi.authenticateUser(testUser).usingSite(testSite).usingResource(childFolder)
|
||||
.createFile(customFile, properties, VersioningState.MAJOR).assertThat().existsInRepo();
|
||||
waitForIndexing(customFile.getName(), true);
|
||||
|
||||
String parentQuery = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + testFolder.getName() + "\"";
|
||||
int initialDescendantCount = query(parentQuery).getPagination().getCount();
|
||||
.createFile(grandChildFile, properties, VersioningState.MAJOR).assertThat().existsInRepo();
|
||||
|
||||
// Edit grand parent folder name
|
||||
String granParentNewName = "granParentRenamed";
|
||||
ContentModel granParentNewNameModel = new ContentModel(granParentNewName);
|
||||
this.dataContent.usingUser(testUser).usingResource(testFolder).renameContent(granParentNewNameModel);
|
||||
|
||||
waitForIndexing(granParentNewName, true);
|
||||
// Wait for file to be indexed
|
||||
waitForMetadataIndexing(grandChildFile.getName(), true);
|
||||
|
||||
String parentQueryAfterRename = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + granParentNewName + "\"";
|
||||
int descendantCountOfDismissedName = query(parentQuery).getPagination().getCount();
|
||||
// Query to find nodes where Path with original folder name matches
|
||||
String parentQuery = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + grandParentFolder.getName() + "\"";
|
||||
|
||||
// Rename grand parent folder
|
||||
String grandParentNewName = "grandParentRenamed";
|
||||
grandParentFolder.setName(grandParentNewName);
|
||||
|
||||
ContentModel grandParentFolderRenamed = new ContentModel(grandParentNewName);
|
||||
dataContent.usingUser(testUser).usingResource(grandParentFolder).renameContent(grandParentFolderRenamed);
|
||||
|
||||
// Find nodes where Path with new folder name matches
|
||||
String parentQueryAfterRename = "NPATH:\"4/Company Home/Sites/" + testSite.getTitle() + "/documentLibrary/" + grandParentNewName + "\"";
|
||||
Boolean indexingInProgress = !waitForContent(parentQueryAfterRename, grandChildFile.getName(), true);
|
||||
|
||||
// Query using new parent name: Expect grand parent, child folder, grand child file
|
||||
int descendantCountOfNewName = query(parentQueryAfterRename).getPagination().getCount();
|
||||
Assert.assertEquals(descendantCountOfNewName, 3, String.format("Indexing in progress: %s New renamed path has not the same descendants as before renaming: %s", indexingInProgress.toString(), parentQueryAfterRename));
|
||||
|
||||
Assert.assertEquals(descendantCountOfNewName, initialDescendantCount);
|
||||
//Assert.assertThat("New renamed path has not the same descendants as before renaming: " + parentQueryAfterRename,descendantCountOfNewName,is(initialDescendantCount));
|
||||
|
||||
Assert.assertEquals(descendantCountOfDismissedName, 0);
|
||||
//Assert.assertThat("Old path still has descendants: " + parentQuery,descendantCountOfDismissedName,is(0));
|
||||
// Query using old parent name: Expect no descendant after rename
|
||||
int descendantCountOfOriginalName = query(parentQuery).getPagination().getCount();
|
||||
Assert.assertEquals(descendantCountOfOriginalName, 0, "Old path still has descendants: " + parentQuery);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user