Fix/search 892

This commit is contained in:
Meenal Bhave
2018-08-14 15:19:09 +01:00
parent 30c87eec8c
commit 263495aaf3
6 changed files with 408 additions and 48 deletions
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="http://www.alfresco.org/model/dictionary/1.0" name="flipFlop:flipFlop">
<author>Administrator</author>
<imports>
<import uri="http://www.alfresco.org/model/content/1.0" prefix="cm"/>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
</imports>
<namespaces>
<namespace uri="flipFlop" prefix="flipFlop"/>
</namespaces>
<data-types/>
<constraints/>
<types>
<type name="flipFlop:song">
<title>song</title>
<parent>cm:content</parent>
<properties>
<property name="flipFlop:lyricist">
<title>lyricist</title>
<type>d:text</type>
<mandatory>false</mandatory>
<index enabled="true">
<tokenised>TRUE</tokenised>
<facetable>true</facetable>
</index>
</property>
<property name="flipFlop:artist-singer-male">
<title>artist-singer-male</title>
<type>d:text</type>
<mandatory>false</mandatory>
<index enabled="true">
<tokenised>TRUE</tokenised>
<facetable>false</facetable>
</index>
</property>
<property name="flipFlop:genre">
<title>genre</title>
<type>d:text</type>
<mandatory>false</mandatory>
<multiple>false</multiple>
<index enabled="true">
<tokenised>BOTH</tokenised>
<facetable>true</facetable>
</index>
</property>
<property name="flipFlop:lyrics">
<title>lyrics</title>
<type>d:mltext</type>
<mandatory>false</mandatory>
<index enabled="true">
<tokenised>TRUE</tokenised>
<facetable>false</facetable>
</index>
</property>
<property name="flipFlop:popular">
<title>popular</title>
<type>d:boolean</type>
<mandatory>false</mandatory>
<default>false</default>
<index enabled="true">
<tokenised>TRUE</tokenised>
</index>
</property>
<property name="flipFlop:artist-singer-female">
<title>artist-singer-female</title>
<type>d:text</type>
<mandatory>false</mandatory>
<index enabled="true">
<tokenised>TRUE</tokenised>
<facetable>false</facetable>
</index>
</property>
</properties>
<associations/>
<overrides/>
<mandatory-aspects/>
</type>
</types>
<aspects>
<aspect name="flipFlop:AudioVisual">
<title>AudioVisual</title>
<properties>
<property name="flipFlop:video">
<title>video</title>
<type>d:boolean</type>
<mandatory>false</mandatory>
<default>false</default>
<index enabled="true">
<tokenised>TRUE</tokenised>
</index>
</property>
<property name="flipFlop:audio">
<title>audio</title>
<type>d:boolean</type>
<mandatory>false</mandatory>
<default>true</default>
<index enabled="true">
<tokenised>TRUE</tokenised>
</index>
</property>
</properties>
<associations/>
<overrides/>
<mandatory-aspects/>
</aspect>
</aspects>
</model>
@@ -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);
}
}
@@ -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<String, Object> properties = new HashMap<String, Object>();
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));
}
}
@@ -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");
}
}
}
+25 -15
View File
@@ -2,22 +2,32 @@
<suite name="SearchSuite" verbose="6" preserve-order="true">
<listeners>
<listener class-name="org.alfresco.utility.report.log.LogsListener"></listener>
<listener class-name="org.alfresco.test.FailedTestListener"></listener>
<listener class-name="org.alfresco.utility.report.HtmlReportListener"></listener>
</listeners>
<listeners>
<listener class-name="org.alfresco.utility.report.HtmlReportListener"></listener>
</listeners>
<test name="Smoke">
<classes>
<class name="org.alfresco.service.search.unit.SetupTest" />
</classes>
</test>
<test name="Smoke">
<groups>
<run>
<include name="sanity" />
<include name="ASS_1.0.0" />
<exclude name="InsightEngine_1.0.0" />
</run>
</groups>
<classes>
<class name="org.alfresco.service.search.unit.SetupTest" />
</classes>
</test>
<test name="E2E-InsightEngine">
<classes>
<class name="org.alfresco.service.search.e2e.insightEngine.sql.CustomModelTest" />
</classes>
</test>
<test name="E2E-SearchServices">
<groups>
<run>
<include name="ASS_1.0.0" />
<exclude name="InsightEngine_1.0.0" />
</run>
</groups>
<classes>
</classes>
</test>
</suite>
@@ -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