diff --git a/packaging/tests/tas-cmis/pom.xml b/packaging/tests/tas-cmis/pom.xml index 52335eccd9..8011b6e23e 100644 --- a/packaging/tests/tas-cmis/pom.xml +++ b/packaging/tests/tas-cmis/pom.xml @@ -18,7 +18,6 @@ 11 UTF-8 - 3.0.53 1.1.0 3.1.1 2.5.3 @@ -69,7 +68,6 @@ org.alfresco.tas utility - ${tas.utility.version} mysql diff --git a/packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java b/packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java index b253d1bd15..040e8eee85 100644 --- a/packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java +++ b/packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/dsl/QueryExecutor.java @@ -1,5 +1,6 @@ package org.alfresco.cmis.dsl; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; @@ -10,10 +11,10 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; - -import com.google.common.collect.Streams; +import java.util.function.Function; +import java.util.stream.StreamSupport; import org.alfresco.cmis.CmisWrapper; import org.alfresco.utility.LogFactory; @@ -26,6 +27,7 @@ import org.alfresco.utility.model.TestModel; import org.apache.chemistry.opencmis.client.api.ItemIterable; import org.apache.chemistry.opencmis.client.api.QueryResult; import org.apache.chemistry.opencmis.client.api.Session; +import org.apache.chemistry.opencmis.commons.data.PropertyData; import org.slf4j.Logger; import org.testng.Assert; @@ -38,9 +40,9 @@ public class QueryExecutor static Logger LOG = LogFactory.getLogger(); CmisWrapper cmisWrapper; - private long returnedResults = -1; + private long resultCount = -1; private String currentQuery = ""; - private ItemIterable results; + private List results; public QueryExecutor(CmisWrapper cmisWrapper, String query) { @@ -50,28 +52,45 @@ public class QueryExecutor public QueryResultAssertion assertResultsCount() { - returnedResults = executeQuery(currentQuery).getPageNumItems(); + resultCount = executeQuery(currentQuery).getPageNumItems(); return new QueryResultAssertion(); } public QueryResultAssertion assertColumnIsOrdered() { - results = executeQuery(currentQuery); - return new QueryResultAssertion(); + return assertValues(); } public QueryResultAssertion assertColumnValuesRange() { - results = executeQuery(currentQuery); - return new QueryResultAssertion(); + return assertValues(); } public QueryResultAssertion assertValues() { - results = executeQuery(currentQuery); + STEP("Sending query " + currentQuery); + results = StreamSupport.stream(executeQuery(currentQuery).spliterator(), false) + .collect(toList()); + resultCount = results.size(); + STEP("Received results " + results.stream().map(this::resultToString).collect(toList())); return new QueryResultAssertion(); } + /** Try to return a useful string representation of the CMIS query result. */ + private String resultToString(QueryResult result) + { + if (result == null || result.getProperties() == null) + { + return "null"; + } + Optional> idProperty = result.getProperties().stream() + .filter(propertyData -> propertyData.getId().equals("cmis:objectId")) + .findFirst(); + return idProperty.map(PropertyData::getValues) + .map(values -> values.stream().map(Object::toString).collect(joining(","))) + .orElse(result.getProperties().toString()); + } + private ItemIterable executeQuery(String query) { Session session = cmisWrapper.getSession(); @@ -160,18 +179,18 @@ public class QueryExecutor public class QueryResultAssertion { - public QueryResultAssertion equals(long expectedValue) + public QueryResultAssertion hasLength(long expectedValue) { STEP(String.format("Verify that query: '%s' has %d results count returned", currentQuery, expectedValue)); - Assert.assertEquals(returnedResults, expectedValue, showErrorMessage()); + Assert.assertEquals(resultCount, expectedValue, showErrorMessage()); return this; } public QueryResultAssertion isGreaterThan(long expectedValue) { STEP(String.format("Verify that query: '%s' has more than %d results count returned", currentQuery, expectedValue)); - if (expectedValue <= returnedResults) - Assert.fail(String.format("%s expected to have more than %d results, but found %d", showErrorMessage(), expectedValue, returnedResults)); + if (expectedValue <= resultCount) + Assert.fail(String.format("%s expected to have more than %d results, but found %d", showErrorMessage(), expectedValue, resultCount)); return this; } @@ -179,8 +198,8 @@ public class QueryExecutor public QueryResultAssertion isLowerThan(long expectedValue) { STEP(String.format("Verify that query: '%s' has more than %d results count returned", currentQuery, expectedValue)); - if (returnedResults >= expectedValue) - Assert.fail(String.format("%s expected to have less than %d results, but found %d", showErrorMessage(), expectedValue, returnedResults)); + if (resultCount >= expectedValue) + Assert.fail(String.format("%s expected to have less than %d results, but found %d", showErrorMessage(), expectedValue, resultCount)); return this; } @@ -192,7 +211,7 @@ public class QueryExecutor results.forEach((r) -> { columnValues.add(r.getPropertyValueByQueryName(queryName)); }); - List orderedColumnValues = columnValues.stream().sorted().collect(Collectors.toList()); + List orderedColumnValues = columnValues.stream().sorted().collect(toList()); Assert.assertEquals(columnValues, orderedColumnValues, String.format("%s column values expected to be in ascendent order, but found %s", queryName, columnValues.toString())); @@ -207,7 +226,7 @@ public class QueryExecutor results.forEach((r) -> { columnValues.add(r.getPropertyValueByQueryName(queryName)); }); - List reverseOrderedColumnValues = columnValues.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList()); + List reverseOrderedColumnValues = columnValues.stream().sorted(Collections.reverseOrder()).collect(toList()); Assert.assertEquals(columnValues, reverseOrderedColumnValues, String.format("%s column values expected to be in descendent order, but found %s", queryName, columnValues.toString())); @@ -230,18 +249,30 @@ public class QueryExecutor } public QueryResultAssertion isReturningValues(String queryName, Set values) + { + return isReturningValues(queryName, values, false); + } + + public QueryResultAssertion isReturningValues(String queryName, Set values, boolean multivalue) { STEP(String.format("Verify that query: '%s' returns the values from %s for column %s", currentQuery, values, queryName)); - Set resultSet = Streams.stream(results).map(r -> (T) r.getPropertyValueByQueryName(queryName)).collect(toSet()); - Assert.assertEquals(resultSet, values, "Values did not match"); + Function extractValue = (multivalue ? (r -> r.getPropertyMultivalueById(queryName)) : r -> r.getPropertyValueById(queryName)); + Set resultSet = results.stream().map(extractValue).collect(toSet()); + Assert.assertEquals(resultSet, values, "Values did not match - expected " + values + " got " + resultSet); return this; } public QueryResultAssertion isReturningOrderedValues(String queryName, List values) + { + return isReturningOrderedValues(queryName, values, false); + } + + public QueryResultAssertion isReturningOrderedValues(String queryName, List values, boolean multivalue) { STEP(String.format("Verify that query: '%s' returns the values from %s for column %s", currentQuery, values, queryName)); - List resultList = Streams.stream(results).map(r -> (T) r.getPropertyValueByQueryName(queryName)).collect(toList()); + Function extractValue = (multivalue ? (r -> r.getPropertyMultivalueById(queryName)) : r -> r.getPropertyValueById(queryName)); + List resultList = results.stream().map(extractValue).collect(toList()); // Include both lists in assertion message as TestNG does not provide this information. Assert.assertEquals(resultList, values, "Values did not match expected " + values + " but found " + resultList); diff --git a/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/AbstractCmisE2ETest.java b/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/AbstractCmisE2ETest.java index df41d989ae..9083f303da 100644 --- a/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/AbstractCmisE2ETest.java +++ b/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/AbstractCmisE2ETest.java @@ -1,9 +1,21 @@ package org.alfresco.cmis.search; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; + +import static org.alfresco.utility.report.log.Step.STEP; + import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; import org.alfresco.cmis.CmisProperties; +import org.alfresco.cmis.dsl.QueryExecutor.QueryResultAssertion; import org.alfresco.utility.Utility; +import org.alfresco.utility.model.ContentModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -45,32 +57,76 @@ public abstract class AbstractCmisE2ETest extends AbstractE2EFunctionalTest /** * Repeat Elastic Query till results count returns expectedCountResults * @param query CMIS Query to be executed - * @param expectedCountResults Number of results expected + * @param expectedResultsCount Number of results expected * @return true when results count is equals to expectedCountResults */ - protected boolean waitForIndexing(String query, long expectedCountResults) + protected boolean waitForIndexing(String query, long expectedResultsCount) { - - for (int searchCount = 1; searchCount <= SEARCH_MAX_ATTEMPTS; searchCount++) + try { + waitForIndexing(query, execution -> execution.hasLength(expectedResultsCount)); + return true; + } + catch (AssertionError ae) + { + STEP("Received assertion error for query '" + query + "': " + ae); + return false; + } + } + /** + * Repeat Elastic Query until we get the expected results or we hit the retry limit. + * + * @param query CMIS Query to be executed + * @param expectedResults The expected results (unordered). + */ + protected void waitForIndexing(String query, ContentModel... expectedResults) + { + Set expectedNames = Arrays.stream(expectedResults).map(ContentModel::getName).collect(toSet()); + waitForIndexing(query, execution -> execution.isReturningValues("cmis:name", expectedNames)); + } + + /** + * Repeat Elastic Query until we get the expected results in the given order or we hit the retry limit. + * + * @param query CMIS Query to be executed + * @param expectedResults The expected results (ordered). + */ + protected void waitForIndexingOrdered(String query, ContentModel... expectedResults) + { + List expectedNames = Arrays.stream(expectedResults).map(ContentModel::getName).collect(toList()); + waitForIndexing(query, execution -> execution.isReturningOrderedValues("cmis:name", expectedNames)); + } + + /** + * Repeat Elastic Query until we get the expected results or we hit the retry limit. + * + * @param query CMIS Query to be executed + * @param assertionMethod A method that will be called to check the response and which will throw an AssertionError if they aren't what we want. + */ + protected void waitForIndexing(String query, Consumer assertionMethod) + { + int searchCount = 0; + while (true) + { try { - cmisApi.withQuery(query).assertResultsCount().equals(expectedCountResults); - return true; + assertionMethod.accept(cmisApi.withQuery(query).assertValues()); + return; } catch (AssertionError ae) { - LOGGER.info(String.format("WaitForIndexing in Progress: %s", ae)); + searchCount++; + if (searchCount < SEARCH_MAX_ATTEMPTS) + { + LOGGER.info(String.format("WaitForIndexing in Progress: %s", ae)); + Utility.waitToLoopTime(getElasticWaitTimeInSeconds(), "Wait For Indexing"); + } + else + { + throw ae; + } } - - - Utility.waitToLoopTime(getElasticWaitTimeInSeconds(), "Wait For Indexing"); - } - - return false; } - - } diff --git a/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/SearchInFolderTests.java b/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/SearchInFolderTests.java index edd25d9a8f..5ef1738470 100644 --- a/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/SearchInFolderTests.java +++ b/packaging/tests/tas-cmis/src/test/java/org/alfresco/cmis/search/SearchInFolderTests.java @@ -1,12 +1,12 @@ package org.alfresco.cmis.search; +import java.util.List; +import java.util.Set; + import org.alfresco.utility.Utility; -import org.alfresco.utility.data.provider.XMLDataConfig; -import org.alfresco.utility.data.provider.XMLTestDataProvider; import org.alfresco.utility.model.FileModel; import org.alfresco.utility.model.FileType; import org.alfresco.utility.model.FolderModel; -import org.alfresco.utility.model.QueryModel; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -17,6 +17,21 @@ public class SearchInFolderTests extends AbstractCmisE2ETest private FolderModel parentFolder, subFolder1, subFolder2, subFolder3; private FileModel subFile1, subFile2, subFile3, subFile4, subFile5; + /** + * Create test data in the following format: + *
+     * testSite
+     * +- parentFolder
+     *    +- subFile5 (fifthFile.txt: "fifthFile content")
+     *    +- subFolder1
+     *    +- subFolder2
+     *    +- subFolder3 (subFolder)
+     *    +- subFile1 (firstFile.xls)
+     *    +- subFile2 (.pptx)
+     *    +- subFile3 (.txt)
+     *    +- subFile4 (fourthFile.docx: "fourthFileTitle", "fourthFileDescription")
+     * 
+ */ @BeforeClass(alwaysRun = true) public void createTestData() throws Exception { @@ -51,12 +66,164 @@ public class SearchInFolderTests extends AbstractCmisE2ETest dataContent.deleteSite(testSite); } - @Test(dataProviderClass = XMLTestDataProvider.class, dataProvider = "getQueriesData") - @XMLDataConfig(file = "src/test/resources/search-in-folder.xml") - public void executeCMISQuery(QueryModel query) + @Test + public void executeCMISQuery_selectFieldsFromFolder() { - String currentQuery = String.format(query.getValue(), parentFolder.getNodeRef()); + String query = "SELECT cmis:name, cmis:parentId, cmis:path, cmis:allowedChildObjectTypeIds" + + " FROM cmis:folder where IN_FOLDER('%s') AND cmis:name = 'subFolder'"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); cmisApi.authenticateUser(testUser); - Assert.assertTrue(waitForIndexing(currentQuery, query.getResults()), String.format("Result count not as expected for query: %s", currentQuery)); + waitForIndexing(currentQuery, subFolder3); + } + + @Test + public void executeCMISQuery_selectFieldsFromDocument() + { + String query = "SELECT cmis:name, cmis:objectId, cmis:lastModifiedBy, cmis:creationDate, cmis:contentStreamFileName" + + " FROM cmis:document where IN_FOLDER('%s') AND cmis:name = 'fourthFile'"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFile4); + } + + @Test + public void executeCMISQuery_selectParentId() + { + String query = "SELECT cmis:parentId FROM cmis:folder where IN_FOLDER('%s')"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + // Expect to get the same parent for each of the three matches. + String parentId = parentFolder.getNodeRef(); + List expectedParentIds = List.of(parentId, parentId, parentId); + waitForIndexing(currentQuery, execution -> execution.isReturningOrderedValues("cmis:parentId", expectedParentIds)); + } + + @Test + public void executeCMISQuery_inFolder() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s')"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFile1, subFile2, subFile3, subFile4, subFile5); + } + + @Test + public void executeCMISQuery_orderByNameAsc() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT LIKE 'file%%' ORDER BY cmis:name ASC"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFile5, subFile1, subFile4); + } + + @Test + public void executeCMISQuery_orderByNameDesc() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT LIKE 'file%%' ORDER BY cmis:name DESC"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFile4, subFile1, subFile5); + } + + @Test + public void executeCMISQuery_orderByLastModifiedAsc() + { + String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') ORDER BY cmis:lastModificationDate ASC"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFolder1, subFolder2, subFolder3); + } + + @Test + public void executeCMISQuery_orderByLastModifiedDesc() + { + String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') ORDER BY cmis:lastModificationDate DESC"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFolder3, subFolder2, subFolder1); + } + + @Test + public void executeCMISQuery_orderByCreatedBy() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') ORDER BY cmis:createdBy DESC"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + // All the results were created by the same user, so we can't assert anything about the order. + waitForIndexing(currentQuery, subFile5, subFile1, subFile2, subFile3, subFile4); + } + + @Test + public void executeCMISQuery_documentNameNotNull() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name IS NOT NULL"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFile1, subFile2, subFile3, subFile4, subFile5); + } + + @Test + public void executeCMISQuery_folderNameNotNull() + { + String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND cmis:name IS NOT NULL"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFolder1, subFolder2, subFolder3); + } + + @Test + public void executeCMISQuery_nameLike() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name LIKE 'fourthFile'"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFile4); + } + + @Test + public void executeCMISQuery_doubleNegative() + { + String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND NOT(cmis:name NOT IN ('subFolder'))"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexingOrdered(currentQuery, subFolder3); + } + + @Test + public void executeCMISQuery_nameInList() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name IN ('fourthFile', 'fifthFile.txt')"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFile4, subFile5); + } + + @Test + public void executeCMISQuery_nameNotInList() + { + String query = "SELECT * FROM cmis:document where IN_FOLDER('%s') AND cmis:name NOT IN ('fourthFile', 'fifthFile.txt')"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFile1, subFile2, subFile3); + } + + @Test + public void executeCMISQuery_nameDifferentFrom() + { + String query = "SELECT * FROM cmis:folder where IN_FOLDER('%s') AND cmis:name <> 'subFolder'"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + waitForIndexing(currentQuery, subFolder1, subFolder2); + } + + @Test + public void executeCMISQuery_selectSecondaryObjectTypeIds() + { + String query = "SELECT cmis:secondaryObjectTypeIds FROM cmis:folder where IN_FOLDER('%s') AND cmis:name = 'subFolder'"; + String currentQuery = String.format(query, parentFolder.getNodeRef()); + cmisApi.authenticateUser(testUser); + Set> expectedSecondaryObjectTypeIds = Set.of(List.of("P:cm:titled", "P:sys:localized")); + waitForIndexing(currentQuery, execution -> execution.isReturningValues("cmis:secondaryObjectTypeIds", expectedSecondaryObjectTypeIds, true)); + Assert.assertTrue(waitForIndexing(currentQuery, 1), String.format("Result count not as expected for query: %s", currentQuery)); } }