mirror of
https://github.com/Alfresco/SearchServices.git
synced 2026-09-16 18:12:56 +00:00
Merge branch 'feature/Search-1485' into 'master'
Feature/SEARCH_1485_move_tests_from_tas_restapi_to_e2e See merge request search_discovery/SearchAnalyticsE2ETest!36
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@
|
||||
<name>Search Analytics E2E Tests</name>
|
||||
<description>Test Project to test Search Service and Analytics Features on a complete setup of Alfresco, Share</description>
|
||||
<properties>
|
||||
<tas.rest.api.version>6.0.0.1</tas.rest.api.version>
|
||||
<tas.rest.api.version>6.0.0.3</tas.rest.api.version>
|
||||
<tas.cmis.api.version>6.0.0.0</tas.cmis.api.version>
|
||||
<tas.utility.version>2.0.1</tas.utility.version>
|
||||
<rm.version>2.6.0</rm.version>
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<model xmlns="http://www.alfresco.org/model/dictionary/1.0" name="1:1">
|
||||
<author>Administrator admin user</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>
|
||||
<!--
|
||||
Namespaces declarations.
|
||||
Note that the model defines several URIs that, strictly speaking, are not valid from a formal syntax
|
||||
perspective [1] [2].
|
||||
However, within the scope of this model they act as "a string of characters that unambiguously identifies a
|
||||
particular resource" and therefore, they can be used within the Alfresco Data Model.
|
||||
|
||||
The model providers a set of namespaces (and corresponding types) for testing several combinations of
|
||||
digits, underscores and hyphens.
|
||||
______________
|
||||
[1] https://www.ietf.org/rfc/rfc3986.txt, Section 3
|
||||
[2] https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Generic_syntax
|
||||
-->
|
||||
<namespace uri="1" prefix="1"/>
|
||||
<namespace uri="123" prefix="123"/>
|
||||
<namespace uri="1_2_3" prefix="1_2_3"/>
|
||||
<namespace uri="1-2-3" prefix="1-2-3"/>
|
||||
<namespace uri="1-2_3" prefix="1-2_3"/>
|
||||
</namespaces>
|
||||
<data-types/>
|
||||
<constraints/>
|
||||
<types>
|
||||
<type name="1:song">
|
||||
<title>song</title>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
<property name="1:name">
|
||||
<title>Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
<property name="1:genre">
|
||||
<title>Genre</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
<property name="1:co-producer">
|
||||
<title>Producer</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
<associations/>
|
||||
<overrides/>
|
||||
<mandatory-aspects/>
|
||||
</type>
|
||||
<type name="123:artist">
|
||||
<title>Artist</title>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
<property name="123:name">
|
||||
<title>Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
<property name="123:voice_type">
|
||||
<title>Voice Type</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
<associations/>
|
||||
<overrides/>
|
||||
<mandatory-aspects/>
|
||||
</type>
|
||||
|
||||
<type name="1_2_3:bassist">
|
||||
<title>Bassist</title>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
<property name="1_2_3:name">
|
||||
<title>Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
<associations/>
|
||||
<overrides/>
|
||||
<mandatory-aspects/>
|
||||
</type>
|
||||
<type name="1-2-3:drummer">
|
||||
<title>Drummer</title>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
<property name="1-2-3:name">
|
||||
<title>Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
<associations/>
|
||||
<overrides/>
|
||||
<mandatory-aspects/>
|
||||
</type>
|
||||
<type name="1-2_3:saxophonist">
|
||||
<title>Sax</title>
|
||||
<parent>cm:content</parent>
|
||||
<properties>
|
||||
<property name="1-2_3:name">
|
||||
<title>Name</title>
|
||||
<type>d:text</type>
|
||||
<mandatory>false</mandatory>
|
||||
<index enabled="true">
|
||||
<stored>true</stored>
|
||||
<tokenised>BOTH</tokenised>
|
||||
<facetable>false</facetable>
|
||||
</index>
|
||||
</property>
|
||||
</properties>
|
||||
<associations/>
|
||||
<overrides/>
|
||||
<mandatory-aspects/>
|
||||
</type>
|
||||
</types>
|
||||
<aspects/>
|
||||
</model>
|
||||
+781
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.insightEngine.sql;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalToIgnoringCase;
|
||||
import static org.hamcrest.Matchers.everyItem;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.isIn;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
|
||||
import org.alfresco.rest.core.RestResponse;
|
||||
import org.alfresco.service.search.e2e.searchservices.AbstractSearchTest;
|
||||
import org.alfresco.rest.search.SearchSqlRequest;
|
||||
import org.alfresco.utility.constants.UserRole;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for /sql end point Search API.
|
||||
*
|
||||
* @author Meenal Bhave
|
||||
*/
|
||||
public class SearchSQLAPITest extends AbstractSearchTest
|
||||
{
|
||||
/**
|
||||
* Path selector to get the values of all cm_name entries for returned search results.
|
||||
* <p>
|
||||
* For example it will retrieve the "alfresco.txt" from:
|
||||
* <pre>
|
||||
* {"list": {
|
||||
* "entries": [
|
||||
* {"entry": [{
|
||||
* "label": "cm_name",
|
||||
* "value": "alfresco.txt"
|
||||
* }]},
|
||||
* ...
|
||||
* </pre>
|
||||
*/
|
||||
private static final String CM_NAME_VALUES = "list.entries.collect {it.entry.findAll {it.label == 'cm_name'}}.flatten().value";
|
||||
String sql = "select SITE, CM_OWNER from alfresco group by SITE,CM_OWNER";
|
||||
String[] locales = { "en-US" };
|
||||
String solrFormat = "solr";
|
||||
|
||||
/**
|
||||
* API post:
|
||||
* {
|
||||
* "stmt": "select SITE from alfresco",
|
||||
* "locales" : ["en_US"],
|
||||
* "format" : "solr",
|
||||
* "timezone":"",
|
||||
* "includeMetadata":false
|
||||
* }
|
||||
* Example Response: In Solr Format
|
||||
* {
|
||||
* "result-set":
|
||||
* {
|
||||
* "docs":
|
||||
* [
|
||||
* {
|
||||
* "SITE":
|
||||
* [
|
||||
* "swsdp"
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* "SITE":
|
||||
* [
|
||||
* "swsdp"
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 01)
|
||||
public void testWithSolr() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat(solrFormat);
|
||||
sqlRequest.setLocales(locales);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs", Matchers.notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* API post example:
|
||||
* {
|
||||
* "stmt": "select SITE from alfresco",
|
||||
* "locales" : ["en_US"],
|
||||
* "format" : "json",
|
||||
* "timezone":"",
|
||||
* "includeMetadata":false
|
||||
* }
|
||||
* Example Response: In json Format
|
||||
* {
|
||||
* "list":
|
||||
* {
|
||||
* "pagination":
|
||||
* {
|
||||
"count": 103,
|
||||
"hasMoreItems": false,
|
||||
"totalItems": 103,
|
||||
"skipCount": 0,
|
||||
"maxItems": 1000
|
||||
},
|
||||
* "entries":
|
||||
* [
|
||||
* "entry": [
|
||||
{
|
||||
"label": "SITE",
|
||||
"value": "[\"swsdp\"]"
|
||||
}
|
||||
],
|
||||
"entry": [
|
||||
{
|
||||
"label": "SITE",
|
||||
"value": "[\"swsdp\"]"
|
||||
}
|
||||
]
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 02)
|
||||
public void testWithJson() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(locales);
|
||||
// Format not set
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(locales);
|
||||
sqlRequest.setFormat("json"); // Format json
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(locales);
|
||||
sqlRequest.setFormat("abcd"); // Format any other than solr
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* API post:
|
||||
* {
|
||||
* "stmt": "select SITE from alfresco",
|
||||
* "locales" : ["en_US"],
|
||||
* "format" : "solr",
|
||||
* "timezone":"",
|
||||
* "includeMetadata":true
|
||||
* }
|
||||
* Example Response: In Solr Format: Includes metadata: aliases, fields, isMetadata=true
|
||||
* {
|
||||
* "result-set": {
|
||||
* "docs": [
|
||||
* {
|
||||
* "aliases": {
|
||||
* "SITE": "SITE"
|
||||
* },
|
||||
* "isMetadata": true,
|
||||
* "fields": [
|
||||
* "SITE"
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* "SITE": [
|
||||
* "swsdp"
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* "SITE": [
|
||||
* "swsdp"
|
||||
* ]
|
||||
* },
|
||||
* {
|
||||
* "RESPONSE_TIME": 79,
|
||||
* "EOF": true
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 03)
|
||||
public void testWithSolrIncludeMetadata() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat(solrFormat);
|
||||
sqlRequest.setLocales(locales);
|
||||
sqlRequest.setIncludeMetadata(true);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.SITE", equalToIgnoringCase("SITE"));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].isMetadata", is(true));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].fields[0]", equalToIgnoringCase("SITE"));
|
||||
}
|
||||
|
||||
/**
|
||||
* API post example:
|
||||
* {
|
||||
* "stmt": "select SITE from alfresco limit 2",
|
||||
* "locales" : ["en_US"],
|
||||
* "format" : "json",
|
||||
* "timezone":"",
|
||||
* "includeMetadata":false
|
||||
* }
|
||||
* Example Response: In json Format
|
||||
* {
|
||||
* "list":
|
||||
* {
|
||||
* "pagination":
|
||||
* {
|
||||
"count": 3,
|
||||
"hasMoreItems": false,
|
||||
"totalItems": 3,
|
||||
"skipCount": 0,
|
||||
"maxItems": 1000
|
||||
},
|
||||
* "entries":
|
||||
* [
|
||||
* "entry": [
|
||||
{
|
||||
"label": "aliases",
|
||||
"value": "{\"SITE\":\"SITE\"}"
|
||||
},
|
||||
{
|
||||
"label": "isMetadata",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"label": "fields",
|
||||
"value": "[\"SITE\"]"
|
||||
}
|
||||
]
|
||||
},
|
||||
* "entry": [
|
||||
{
|
||||
"label": "SITE",
|
||||
"value": "[\"swsdp\"]"
|
||||
}
|
||||
],
|
||||
"entry": [
|
||||
{
|
||||
"label": "SITE",
|
||||
"value": "[\"swsdp\"]"
|
||||
}
|
||||
]
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 04)
|
||||
public void testWithJsonIncludeMetadata() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat("");
|
||||
sqlRequest.setLocales(locales);
|
||||
sqlRequest.setIncludeMetadata(true);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", equalToIgnoringCase("aliases"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].value", equalToIgnoringCase("{\"SITE\":\"SITE\",\"cm_owner\":\"CM_OWNER\"}"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][1].label", equalToIgnoringCase("isMetadata"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][1].value", is("true"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][2].label", equalToIgnoringCase("fields"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][2].value", equalToIgnoringCase("[\"SITE\",\"cm_owner\"]"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 05)
|
||||
public void testIncludeMetadataFalse() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat("solr"); // Format solr
|
||||
sqlRequest.setIncludeMetadata(false);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].isMetadata", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].fields", Matchers.nullValue());
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setIncludeMetadata(false);
|
||||
sqlRequest.setFormat("json"); // Format json
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", not("aliases"));
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setIncludeMetadata(false); // Format not set
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", not("aliases"));
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat(solrFormat); // IncludeMetadata = false when not specified
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].isMetadata", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].fields", Matchers.nullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 06)
|
||||
public void testLocales() throws Exception
|
||||
{
|
||||
String[] noLocales = {}; // Not specified
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(noLocales);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
String[] singleLocale = { "en-Uk" };
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(singleLocale);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
String[] multipleLocales = { "en-US", "ja" };
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(multipleLocales);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 07)
|
||||
public void testTimezone() throws Exception
|
||||
{
|
||||
String timezone = ""; // Not specified
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setTimezone(timezone);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
timezone = "UTC"; // UTC
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setTimezone(timezone);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
timezone = "false"; // Invalid timezone is ignored
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setTimezone(timezone);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 8)
|
||||
public void testAggregateSQL() throws Exception
|
||||
{
|
||||
String agSql = "select count(*) FROM alfresco where TYPE='cm:content'";
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(agSql);
|
||||
|
||||
RestResponse response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.entries", Matchers.notNullValue());
|
||||
response.assertThat().body("list.entries.entry[0][0].value", not("0"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 9)
|
||||
public void testLimit() throws Exception
|
||||
{
|
||||
Integer defaultLimit = 1000;
|
||||
|
||||
Integer limit = null; // Limit defaults to the default setting when null
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLimit(limit);
|
||||
|
||||
RestResponse response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.pagination.maxItems", Matchers.equalTo(defaultLimit));
|
||||
|
||||
limit = 0; // Limit defaults to the default setting when 0
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLimit(limit);
|
||||
|
||||
response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.pagination.maxItems", Matchers.equalTo(defaultLimit));
|
||||
|
||||
limit = 100; // Limit is applied correctly, with maxItems = limit
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLimit(limit);
|
||||
|
||||
response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.pagination.maxItems", Matchers.equalTo(limit));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 10)
|
||||
public void testAuthenticationError() throws Exception
|
||||
{
|
||||
UserModel dummyUser = dataUser.createRandomTestUser("UserSearchDummy");
|
||||
dummyUser.setPassword("incorrect-password");
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(locales);
|
||||
|
||||
restClient.authenticateUser(dummyUser).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 11)
|
||||
public void testPermissions() throws Exception
|
||||
{
|
||||
UserModel userNoPerm = dataUser.createRandomTestUser("UserSearchNoPerm");
|
||||
UserModel userPerm = dataUser.createRandomTestUser("UserSearchPerm");
|
||||
|
||||
dataUser.addUserToSite(userPerm, siteModel, UserRole.SiteContributor);
|
||||
|
||||
String siteSQL = "select SITE, CM_OWNER from alfresco where SITE='" + siteModel.getId() + "'";
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(siteSQL);
|
||||
|
||||
// 0 results expected for query as User does not have access to the private site
|
||||
restClient.authenticateUser(userNoPerm).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("list.pagination.count", is(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.totalItems", is(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.hasMoreItems", is(false));
|
||||
restClient.onResponse().assertThat().body("list.entries", empty());
|
||||
|
||||
// Results expected for query as User does has access to the private site
|
||||
restClient.authenticateUser(userPerm).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().body("list.pagination.count", greaterThan(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.totalItems", greaterThan(0));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", equalToIgnoringCase("SITE"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].value", equalToIgnoringCase("[\"" + siteModel.getId() + "\"]"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 12)
|
||||
public void testErrors() throws Exception
|
||||
{
|
||||
String incorrectSQL = ""; // Missing SQL
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Required stmt parameter is missing"));
|
||||
|
||||
incorrectSQL = "select SITE from unknownTable"; // Wrong table name
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
// restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Table 'unknownTable' not found"));
|
||||
|
||||
incorrectSQL = "select Column1 from alfresco"; // Wrong ColumnName
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Column 'Column1' not found"));
|
||||
|
||||
incorrectSQL = "select SITE alfresco"; // BAD SQL Grammar: from missing
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Unable to execute the query"));
|
||||
|
||||
incorrectSQL = "select SITE, CM_OWNER from alfresco group by SITE"; // BAD SQL Grammar: CM_OWNER is not being grouped
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Expression 'CM_OWNER' is not being grouped"));
|
||||
|
||||
incorrectSQL = "delete SITE from alfresco"; // BAD SQL Grammar
|
||||
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(incorrectSQL);
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("error.briefSummary", Matchers.containsString("Was expecting one of"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.NOT_INSIGHT_ENGINE }, priority = 13)
|
||||
public void testErrorForSQLAPIWithASS() throws Exception
|
||||
{
|
||||
String acsVersion = serverHealth.getAlfrescoVersion();
|
||||
HttpStatus expectedStatus = HttpStatus.OK;
|
||||
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setLocales(locales);
|
||||
|
||||
// Set expected result based on ACS Version and ASS Version
|
||||
if (!acsVersion.startsWith("6"))
|
||||
{
|
||||
expectedStatus = HttpStatus.NOT_FOUND;
|
||||
}
|
||||
else
|
||||
{
|
||||
expectedStatus = HttpStatus.BAD_REQUEST;
|
||||
}
|
||||
|
||||
restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(sqlRequest);
|
||||
restClient.assertStatusCodeIs(expectedStatus);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 14)
|
||||
public void testSelectStar() throws Exception
|
||||
{
|
||||
// Select * with Limit, json format
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select * from alfresco");
|
||||
sqlRequest.setLimit(1);
|
||||
|
||||
RestResponse response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.pagination.maxItems", Matchers.equalTo(1));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", equalToIgnoringCase("PATH"));
|
||||
|
||||
// Select * with Limit, solr format: Also covered in JDBC
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select * from alfresco");
|
||||
sqlRequest.setFormat("solr");
|
||||
sqlRequest.setIncludeMetadata(true);
|
||||
sqlRequest.setLimit(1);
|
||||
|
||||
response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_name", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_created", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_creator", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_modified", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_modifier", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_owner", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.OWNER", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.TYPE", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.LID", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.DBID", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_title", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_description", Matchers.notNullValue());
|
||||
|
||||
// This type of assertion is required because of a '.' in the field name
|
||||
Assert.assertTrue(response.getResponse().body().jsonPath().get("result-set.docs[0].aliases").toString().contains("cm_content.size=cm_content.size"));
|
||||
Assert.assertTrue(response.getResponse().body().jsonPath().get("result-set.docs[0].aliases").toString().contains("cm_content.mimetype=cm_content.mimetype"));
|
||||
Assert.assertTrue(response.getResponse().body().jsonPath().get("result-set.docs[0].aliases").toString().contains("cm_content.encoding=cm_content.encoding"));
|
||||
Assert.assertTrue(response.getResponse().body().jsonPath().get("result-set.docs[0].aliases").toString().contains("cm_content.locale=cm_content.locale"));
|
||||
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_lockOwner", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.SITE", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.PARENT", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.PATH", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.PRIMARYPARENT", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.ASPECT", Matchers.notNullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.QNAME", Matchers.notNullValue());
|
||||
|
||||
// Test that cm_content and any other random field does not appear in the response
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.cm_content", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].aliases.RandomNonExistentField", Matchers.nullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 15)
|
||||
public void testDistinct() throws Exception
|
||||
{
|
||||
// Select distinct site: json format
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select distinct Site from alfresco");
|
||||
sqlRequest.setLimit(10);
|
||||
|
||||
RestResponse response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
response.assertThat().body("list.pagination.maxItems", Matchers.equalTo(10));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", equalToIgnoringCase("site"));
|
||||
|
||||
// Select distinct cm_name: solr format
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select distinct cm_name from alfresco limit 5");
|
||||
sqlRequest.setFormat("solr");
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.notNullValue());
|
||||
}
|
||||
|
||||
/** Check that a filter query can affect which results are included. */
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_11 }, priority = 16)
|
||||
public void testFilterQuery() throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
String siteSQL = "select SITE, CM_OWNER from alfresco where SITE='" + siteModel.getId() + "'";
|
||||
sqlRequest.setSql(siteSQL);
|
||||
// Add a filter query to only include results from inside the site (i.e. all results).
|
||||
String[] filterQuery = { "SITE:'" + siteModel.getId() + "'" };
|
||||
sqlRequest.setFilterQuery(filterQuery);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.pagination.count", greaterThan(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.totalItems", greaterThan(0));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].label", equalToIgnoringCase("SITE"));
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0][0].value", equalToIgnoringCase("[\"" + siteModel.getId() + "\"]"));
|
||||
|
||||
// Now try instead removing everything from the site (i.e. all results).
|
||||
String[] inverseFilterQuery = { "-SITE:'" + siteModel.getId() + "'" };
|
||||
sqlRequest.setFilterQuery(inverseFilterQuery);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.pagination.count", is(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.totalItems", is(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.hasMoreItems", is(false));
|
||||
restClient.onResponse().assertThat().body("list.entries", empty());
|
||||
}
|
||||
|
||||
/** Check that the combination of multiple filter queries produce the intersection of results. */
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_11 }, priority = 17)
|
||||
public void testCombiningFilterQueries() throws Exception
|
||||
{
|
||||
String siteSQL = "select cm_name from alfresco where SITE='" + siteModel.getId() + "'";
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(siteSQL);
|
||||
// Add a filter query to only include results from inside the site (i.e. all results).
|
||||
String[] filterQueries = { "-cm_name:'cars'", "-cm_name:'pangram'" };
|
||||
sqlRequest.setFilterQuery(filterQueries);
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.pagination.count", greaterThan(0));
|
||||
restClient.onResponse().assertThat().body("list.pagination.totalItems", greaterThan(0));
|
||||
// Check that pangram.txt and cars.txt were both filtered out.
|
||||
restClient.onResponse().assertThat()
|
||||
.body(CM_NAME_VALUES, everyItem(not(isIn(asList("pangram.txt", "cars.txt")))));
|
||||
}
|
||||
|
||||
/** Check that an empty list of filter queries doesn't remove anything from the results. */
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_11 }, priority = 18)
|
||||
public void testEmptyFilterQuery() throws Exception
|
||||
{
|
||||
String siteSQL = "select cm_name from alfresco where SITE='" + siteModel.getId() + "'";
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(siteSQL);
|
||||
// Add an empty list of filter queries.
|
||||
sqlRequest.setFilterQuery(new String[]{});
|
||||
|
||||
searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
// Check that the cm_names of all nodes in the site are returned.
|
||||
restClient.onResponse().assertThat()
|
||||
.body(CM_NAME_VALUES, containsInAnyOrder("documentLibrary", SEARCH_DATA_SAMPLE_FOLDER, "pangram.txt", "cars.txt", "alfresco.txt", unique_searchString + ".txt"));
|
||||
}
|
||||
}
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.insightEngine.sql;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.rest.core.RestResponse;
|
||||
import org.alfresco.service.search.e2e.searchservices.AbstractSearchTest;
|
||||
import org.alfresco.rest.search.SearchSqlJDBCRequest;
|
||||
import org.alfresco.rest.search.SearchSqlRequest;
|
||||
import org.alfresco.utility.model.FileModel;
|
||||
import org.alfresco.utility.model.FileType;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
import org.hamcrest.Matchers;
|
||||
|
||||
/**
|
||||
* Tests for /sql end point Search API: Phrase Searching.
|
||||
*
|
||||
* @author Meenal Bhave
|
||||
*/
|
||||
public class SearchSQLPhraseTest extends AbstractSearchTest
|
||||
{
|
||||
FileModel fileBanana, fileYellowBanana, fileBigYellowBanana, fileBigBananaBoat, fileYellowBananaBigBoat, fileBigYellowBoat;
|
||||
|
||||
List expectedContent = new ArrayList<String>();
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void dataPreparation() throws Exception
|
||||
{
|
||||
super.dataPreparation();
|
||||
|
||||
// Create files with different phrases
|
||||
fileBanana = new FileModel(unique_searchString + "-1.txt", "banana", "phrase searching", FileType.TEXT_PLAIN, "banana");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileBanana);
|
||||
|
||||
fileYellowBanana = new FileModel(unique_searchString + "-2.txt", "yellow banana", "phrase searching", FileType.TEXT_PLAIN, "yellow banana");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileYellowBanana);
|
||||
|
||||
fileBigYellowBanana = new FileModel(unique_searchString + "-3.txt", "big yellow banana", "phrase searching", FileType.TEXT_PLAIN, "big yellow banana");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileBigYellowBanana);
|
||||
|
||||
fileBigBananaBoat = new FileModel(unique_searchString + "-4.txt", "big boat", "phrase searching", FileType.TEXT_PLAIN, "big boat");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileBigBananaBoat);
|
||||
|
||||
fileYellowBananaBigBoat = new FileModel(unique_searchString + "-5.txt", "yellow banana big boat", "phrase searching", FileType.TEXT_PLAIN, "yellow banana big boat");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileYellowBananaBigBoat);
|
||||
|
||||
fileBigYellowBoat = new FileModel(unique_searchString + "-6.txt", "big yellow boat", "phrase searching", FileType.TEXT_PLAIN, "big yellow boat");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(fileBigYellowBoat);
|
||||
|
||||
waitForIndexing(fileBigYellowBoat.getName(), true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 1)
|
||||
public void testPhraseQueries() throws Exception
|
||||
{
|
||||
// yellow banana: 5 results expected
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select cm_content from alfresco where cm_content = '(yellow banana)'");
|
||||
sqlRequest.setLimit(10);
|
||||
|
||||
RestResponse response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
|
||||
// Check Result count matches
|
||||
response.assertThat().body("list.pagination.count", Matchers.equalTo(expectedContent.size()));
|
||||
|
||||
// Check Results match
|
||||
Collection<Map<String, String>> actualContent = response.getResponse().body().jsonPath().get("list.entries.entry.value");
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
|
||||
// yellow banana big boat: 6 results expected
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select cm_content from alfresco where cm_content = '(yellow banana big boat)'");
|
||||
sqlRequest.setLimit(10);
|
||||
|
||||
response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigBananaBoat.getContent()));
|
||||
|
||||
// Check Result count matches
|
||||
response.assertThat().body("list.pagination.count", Matchers.equalTo(expectedContent.size()));
|
||||
|
||||
// Check Results match
|
||||
actualContent = response.getResponse().body().jsonPath().get("list.entries.entry.value");
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
|
||||
// yellow banana big boat: 4 results expected
|
||||
sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql("select cm_content from alfresco where cm_content = '(big boat)'");
|
||||
sqlRequest.setLimit(10);
|
||||
|
||||
response = searchSql(sqlRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigBananaBoat.getContent()));
|
||||
|
||||
// Check Result count matches
|
||||
response.assertThat().body("list.pagination.count", Matchers.equalTo(expectedContent.size()));
|
||||
|
||||
// Check Results match
|
||||
actualContent = response.getResponse().body().jsonPath().get("list.entries.entry.value");
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 2)
|
||||
public void testPhraseQueriesViaJDBC() throws Exception
|
||||
{
|
||||
// yellow banana: 5 results expected
|
||||
SearchSqlJDBCRequest sqlRequest = new SearchSqlJDBCRequest();
|
||||
String sql = "select cm_content from alfresco where cm_content = '(yellow banana)'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
|
||||
Integer i = 0;
|
||||
List actualContent = new ArrayList<String>();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("cm_content"));
|
||||
actualContent.add(Arrays.asList(rs.getString("cm_content")));
|
||||
i++;
|
||||
}
|
||||
|
||||
Assert.assertTrue(i == expectedContent.size());
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
|
||||
// yellow banana big boat: 6 results expected
|
||||
sql = "select cm_content from alfresco where cm_content = '(yellow banana big boat)'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigBananaBoat.getContent()));
|
||||
|
||||
i = 0;
|
||||
actualContent = new ArrayList<String>();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("cm_content"));
|
||||
actualContent.add(Arrays.asList(rs.getString("cm_content")));
|
||||
i++;
|
||||
}
|
||||
|
||||
Assert.assertTrue(i == expectedContent.size());
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
|
||||
// big boat: 4 results expected
|
||||
sql = "select cm_content from alfresco where cm_content = '(big boat)'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
// Set Expected Result
|
||||
expectedContent = new ArrayList<String>();
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBanana.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileYellowBananaBigBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigYellowBoat.getContent()));
|
||||
expectedContent.add(Arrays.asList(fileBigBananaBoat.getContent()));
|
||||
|
||||
i = 0;
|
||||
actualContent = new ArrayList<String>();
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("cm_content"));
|
||||
actualContent.add(Arrays.asList(rs.getString("cm_content")));
|
||||
i++;
|
||||
}
|
||||
|
||||
Assert.assertTrue(i == expectedContent.size());
|
||||
Assert.assertTrue(actualContent.containsAll(expectedContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
Assert.assertTrue(expectedContent.containsAll(actualContent), String.format("Phrase Search Results expected: %s Actual: %s", expectedContent.toString(), actualContent.toString()));
|
||||
}
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.insightEngine.sql;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.dataprep.SiteService.Visibility;
|
||||
import org.alfresco.rest.requests.search.SearchSQLJDBC;
|
||||
import org.alfresco.service.search.e2e.searchservices.AbstractSearchTest;
|
||||
import org.alfresco.rest.search.SearchSqlJDBCRequest;
|
||||
import org.alfresco.utility.data.RandomData;
|
||||
import org.alfresco.utility.model.SiteModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.Assert;
|
||||
|
||||
/**
|
||||
* Search SQL end point test via JDBC.
|
||||
* @author MSuzuki
|
||||
* @author Meenal Bhave
|
||||
*
|
||||
*/
|
||||
public class SearchSQLViaJDBCTest extends AbstractSearchTest
|
||||
{
|
||||
List<String> sites = new ArrayList<String>();
|
||||
SearchSQLJDBC searchSql;
|
||||
SearchSqlJDBCRequest sqlRequest = new SearchSqlJDBCRequest();
|
||||
|
||||
@AfterMethod(alwaysRun=true)
|
||||
public void cleanUp() throws SQLException
|
||||
{
|
||||
restClient.withSearchSqlViaJDBC().clearSearchQuery(sqlRequest);
|
||||
sqlRequest = new SearchSqlJDBCRequest();
|
||||
sites = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority=01)
|
||||
public void testQueryPublicSite() throws SQLException
|
||||
{
|
||||
|
||||
SiteModel publicSite = new SiteModel(RandomData.getRandomName("SiteSearch"));
|
||||
publicSite.setVisibility(Visibility.PUBLIC);
|
||||
|
||||
publicSite = dataSite.usingUser(adminUserModel).createSite(publicSite);
|
||||
|
||||
String sql = "select SITE,CM_OWNER from alfresco where SITE ='" + publicSite.getTitle() + "' group by SITE,CM_OWNER";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
|
||||
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(adminUserModel.getUsername()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority=02)
|
||||
public void testQueryMyCreatedPrivateSite() throws SQLException
|
||||
{
|
||||
String sql = "select distinct SITE from alfresco where SITE ='" + siteModel.getTitle() + "'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// User can see Own Private Site
|
||||
Assert.assertNotNull(rs.getString("SITE"));
|
||||
Assert.assertTrue(siteModel.getTitle().equalsIgnoreCase(rs.getString("SITE")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority=03)
|
||||
public void testQueryPrivateSiteWithSuperUser() throws SQLException
|
||||
{
|
||||
String sql = "select distinct SITE from alfresco where SITE ='" + siteModel.getTitle() + "'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(adminUserModel);
|
||||
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Super user can see Private Site created by other user
|
||||
Assert.assertNotNull(rs.getString("SITE"));
|
||||
Assert.assertTrue(siteModel.getTitle().equalsIgnoreCase(rs.getString("SITE")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority=04)
|
||||
public void testQueryPrivateSiteWithSimpleUser() throws SQLException
|
||||
{
|
||||
UserModel managerUser = dataUser.createRandomTestUser("UserSearchMgr");
|
||||
|
||||
String sql = "select SITE from alfresco where SITE = '" + siteModel.getTitle() + "'";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(managerUser);
|
||||
|
||||
// Non admin user can NOT see Private Site created by other user
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertFalse(rs.next());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority=05)
|
||||
public void testQueryErrorReturned() throws SQLException
|
||||
{
|
||||
String expectedError = "Column 'SITE1' not found";
|
||||
|
||||
String sql = "select SITE1 from alfresco";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
// Appropriate error is retrieved when SQL is incorrect
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
|
||||
String error = sqlRequest.getErrorDetails();
|
||||
Assert.assertNotNull(error);
|
||||
Assert.assertTrue(error.contains(expectedError), "Error shown: " + error + " Error expected: " + expectedError);
|
||||
|
||||
// Record set is null
|
||||
Assert.assertNull(rs);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 06)
|
||||
public void testQuerySelectStar() throws SQLException
|
||||
{
|
||||
// Select * query with limit clause
|
||||
String sql = "select * from alfresco limit 5";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
// Select * with limit clause works: No error is retrieved
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("PATH"));
|
||||
Assert.assertNotNull(rs.getString("DBID"));
|
||||
Assert.assertNotNull(rs.getString("cm_name"));
|
||||
}
|
||||
|
||||
// Select * query Without limit clause: No error is retrieved
|
||||
sql = "select * from alfresco";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(userModel);
|
||||
|
||||
// No error is retrieved when SQL is incorrect
|
||||
rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("PATH"));
|
||||
Assert.assertNotNull(rs.getString("DBID"));
|
||||
Assert.assertNotNull(rs.getString("cm_name"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.INSIGHT_10 }, priority = 07)
|
||||
public void testQuerySelectDistinct() throws SQLException
|
||||
{
|
||||
// Select distinct query with limit clause
|
||||
String sql = "select distinct cm_name from alfresco limit 5";
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setAuthUser(adminUserModel);
|
||||
|
||||
// Select distinct with limit clause works: No error is retrieved
|
||||
ResultSet rs = restClient.withSearchSqlViaJDBC().executeQueryViaJDBC(sqlRequest);
|
||||
Assert.assertNotNull(rs);
|
||||
Assert.assertNull(sqlRequest.getErrorDetails());
|
||||
|
||||
while (rs.next())
|
||||
{
|
||||
// Field values are retrieved
|
||||
Assert.assertNotNull(rs.getString("cm_name"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.insightEngine.sql;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.alfresco.service.search.e2e.searchservices.AbstractSearchTest;
|
||||
import org.alfresco.utility.constants.UserRole;
|
||||
import org.alfresco.utility.data.CustomObjectTypeProperties;
|
||||
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.TestGroup;
|
||||
import org.alfresco.utility.report.Bug;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
import org.alfresco.rest.RestTest;
|
||||
|
||||
/**
|
||||
* Tests for /sql end point Search API when a custom model contains identifiers that need to be quoted in queries.
|
||||
* While it seems there is not an ANSI standard for naming database objects, on the other side the most popular
|
||||
* databases don't like columns starting with a number.
|
||||
* In those cases, the column identifier need to be quoted. How to quote a given object identifier (a column name, in
|
||||
* this case) depends on the specific database lexicon: Oracle uses double quotes ("), MySQL uses back quotes(`).
|
||||
*
|
||||
* At time of writing, the lexicon used by the /sql endpoint is MySql so queries that use column names starting with
|
||||
* a number need to be quoted with back quotes.
|
||||
*
|
||||
*/
|
||||
public class SearchSQLWithQuotedIdentifiers extends AbstractSearchTest
|
||||
{
|
||||
|
||||
private String songName;
|
||||
private String genre;
|
||||
private String coProducer;
|
||||
|
||||
private String artistName;
|
||||
private String voiceType;
|
||||
|
||||
private String bassistName;
|
||||
private String drummerName;
|
||||
private String saxophonistName;
|
||||
|
||||
private FileModel file5;
|
||||
|
||||
/**
|
||||
* Setup fixture for this test case.
|
||||
* Overrides the superlayer method because the data preparation requires a bit different preconditions.
|
||||
* The method uses a transient test site created in the {@link RestTest#checkServerHealth()} and on top of that:
|
||||
*
|
||||
* <ul>
|
||||
* <li>It adds a user which is added to the site as contributor</li>
|
||||
* <li>
|
||||
* It deploys a custom model which declares a set of prefixes composed by a combination of digits, hyphens
|
||||
* and underscores. Those prefixes are associated with four entities (song, artist, bassist, drummer and
|
||||
* sax) with their corresponding attributes.
|
||||
* </li>
|
||||
* <li>
|
||||
* It creates a folder with 5 files associated with the types declared in the model.
|
||||
* That allows those files to have a value for the properties/attributes included in the model definition.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @see RestTest#checkServerHealth()
|
||||
* @throws Exception hopefully never, otherwise the test fails.
|
||||
*/
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void localDataPreparation() throws Exception
|
||||
{
|
||||
songName = "The Dry Cleaner from Des Moines ";
|
||||
genre = "Jazz, vocal jazz ";
|
||||
coProducer = "Roberta Joan Mitchell ";
|
||||
|
||||
artistName = "Joni Mitchell " + UUID.randomUUID();
|
||||
voiceType = "Blue Mezzo (1965-1984) / Cloudy Contralto (1985-present) ";
|
||||
|
||||
bassistName = "Jaco Pastorius";
|
||||
drummerName = "Peter Erskine";
|
||||
saxophonistName = "Wayne Shorter";
|
||||
|
||||
dataContent.usingAdmin().deployContentModel("model/search-1063-model.xml");
|
||||
|
||||
dataUser.addUserToSite(userModel, siteModel, UserRole.SiteContributor);
|
||||
|
||||
testSite = siteModel;
|
||||
|
||||
FolderModel testFolder = dataContent.usingSite(testSite).usingUser(userModel).createFolder();
|
||||
|
||||
file = FileModel.getRandomFileModel(FileType.TEXT_PLAIN);
|
||||
file2 = FileModel.getRandomFileModel(FileType.TEXT_PLAIN);
|
||||
file3 = FileModel.getRandomFileModel(FileType.TEXT_PLAIN);
|
||||
file4 = FileModel.getRandomFileModel(FileType.TEXT_PLAIN);
|
||||
file5 = FileModel.getRandomFileModel(FileType.TEXT_PLAIN);
|
||||
|
||||
dataContent.usingUser(userModel)
|
||||
.usingResource(testFolder)
|
||||
.createCustomContent(
|
||||
file,
|
||||
"D:1:song",
|
||||
new CustomObjectTypeProperties()
|
||||
.addProperty("1:name", songName)
|
||||
.addProperty("1:genre", genre)
|
||||
.addProperty("1:co-producer", coProducer));
|
||||
|
||||
dataContent.usingUser(userModel)
|
||||
.usingResource(testFolder)
|
||||
.createCustomContent(
|
||||
file2,
|
||||
"D:123:artist",
|
||||
new CustomObjectTypeProperties()
|
||||
.addProperty("123:name", artistName)
|
||||
.addProperty("123:voice_type", voiceType));
|
||||
|
||||
dataContent.usingUser(userModel)
|
||||
.usingResource(testFolder)
|
||||
.createCustomContent(
|
||||
file3,
|
||||
"D:1_2_3:bassist",
|
||||
new CustomObjectTypeProperties()
|
||||
.addProperty("1_2_3:name", bassistName));
|
||||
|
||||
dataContent.usingUser(userModel)
|
||||
.usingResource(testFolder)
|
||||
.createCustomContent(
|
||||
file4,
|
||||
"D:1-2-3:drummer",
|
||||
new CustomObjectTypeProperties()
|
||||
.addProperty("1-2-3:name", drummerName));
|
||||
|
||||
ContentModel content =
|
||||
dataContent.usingUser(userModel)
|
||||
.usingResource(testFolder)
|
||||
.createCustomContent(
|
||||
file5,
|
||||
"D:1-2_3:saxophonist",
|
||||
new CustomObjectTypeProperties()
|
||||
.addProperty("1-2_3:name", saxophonistName));
|
||||
|
||||
waitForIndexing(content.getName(), true);
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
@Bug(id = "SEARCH-1063")
|
||||
public void prefixIsComposedByOneNumber() throws Exception
|
||||
{
|
||||
executeSqlAsSolr("select cm_name, `1_name`, `1_genre`, `1_co-producer` from alfresco where TYPE='1:song' and SITE='" + testSite.getId() + "'");
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.equalTo(file.getName()));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1_name", Matchers.equalTo(songName));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1_genre", Matchers.equalTo(genre));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1_co-producer", Matchers.equalTo(coProducer));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
@Bug(id = "SEARCH-1063")
|
||||
public void prefixIsComposedByMultipleNumbers() throws Exception
|
||||
{
|
||||
executeSqlAsSolr("select cm_name, `123_name`, `123_voice_type` from alfresco where TYPE='123:artist' and SITE='" + testSite.getId() + "'");
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.equalTo(file2.getName()));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].123_name", Matchers.equalTo(artistName));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].123_voice_type", Matchers.equalTo(voiceType));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
@Bug(id = "SEARCH-1063")
|
||||
public void prefixIncludesUnderscore() throws Exception
|
||||
{
|
||||
executeSqlAsSolr("select cm_name, `1_2_3_name` from alfresco where TYPE='1_2_3:bassist' and SITE='" + testSite.getId() + "'");
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.equalTo(file3.getName()));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1_2_3_name", Matchers.equalTo(bassistName));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
@Bug(id = "SEARCH-1063")
|
||||
public void prefixIncludesHyphen() throws Exception
|
||||
{
|
||||
executeSqlAsSolr("select cm_name, `1-2-3_name` from alfresco where TYPE='1-2-3:drummer' and SITE='" + testSite.getId() + "'");
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.equalTo(file4.getName()));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1-2-3_name", Matchers.equalTo(drummerName));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
@Bug(id = "SEARCH-1063")
|
||||
public void prefixIncludesHyphenAndUnderscore() throws Exception
|
||||
{
|
||||
executeSqlAsSolr("select cm_name, `1-2_3_name` from alfresco where TYPE='1-2_3:saxophonist' and SITE='" + testSite.getId() + "'");
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].cm_name", Matchers.equalTo(file5.getName()));
|
||||
restClient.onResponse().assertThat().body("result-set.docs[0].1-2_3_name", Matchers.equalTo(saxophonistName));
|
||||
}
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import org.alfresco.dataprep.SiteService.Visibility;
|
||||
import org.alfresco.rest.core.RestResponse;
|
||||
import org.alfresco.rest.search.RestRequestHighlightModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.rest.search.SearchSqlRequest;
|
||||
import org.alfresco.utility.Utility;
|
||||
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.springframework.http.HttpStatus;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.alfresco.rest.RestTest;
|
||||
|
||||
import javax.naming.AuthenticationException;
|
||||
|
||||
/**
|
||||
* Abstract Search test class that contains useful methods
|
||||
* such as:
|
||||
* <ul>
|
||||
* <li>Preparing the data to index.
|
||||
* <li>Preparing search requests.
|
||||
*
|
||||
* @author Michael Suzuki
|
||||
* @author Meenal Bhave
|
||||
*
|
||||
*/
|
||||
public class AbstractSearchTest extends RestTest
|
||||
{
|
||||
|
||||
protected static final String SEARCH_DATA_SAMPLE_FOLDER = "FolderSearch";
|
||||
protected UserModel userModel, adminUserModel;
|
||||
protected SiteModel siteModel;
|
||||
protected UserModel searchedUser;
|
||||
protected FileModel file, file2, file3, file4;
|
||||
|
||||
protected static String unique_searchString;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void dataPreparation() throws Exception
|
||||
{
|
||||
adminUserModel = dataUser.getAdminUser();
|
||||
userModel = dataUser.createRandomTestUser("UserSearch");
|
||||
|
||||
siteModel = new SiteModel(RandomData.getRandomName("SiteSearch"));
|
||||
siteModel.setVisibility(Visibility.PRIVATE);
|
||||
|
||||
siteModel = dataSite.usingUser(userModel).createSite(siteModel);
|
||||
|
||||
unique_searchString = siteModel.getTitle().replace("SiteSearch", "Unique");
|
||||
|
||||
/*
|
||||
* Create the following file structure for preconditions :
|
||||
* |- folder
|
||||
* |-- pangram.txt
|
||||
* |-- cars.txt
|
||||
* |-- alfresco.txt
|
||||
* |-- <uniqueFileName>
|
||||
*/
|
||||
|
||||
FolderModel folder = new FolderModel(SEARCH_DATA_SAMPLE_FOLDER);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createFolder(folder);
|
||||
|
||||
//Create files
|
||||
String title = "Title: " + unique_searchString;
|
||||
String description = "Description: File is created for search tests by Author: " + unique_searchString + " . ";
|
||||
|
||||
file = new FileModel("pangram.txt", "pangram" + title, description, FileType.TEXT_PLAIN, description + " The quick brown fox jumps over the lazy dog");
|
||||
|
||||
file2 = new FileModel("cars.txt", "cars" + title, description, FileType.TEXT_PLAIN, "The landrover discovery is not a sports car ");
|
||||
|
||||
file3 = new FileModel("alfresco.txt", "alfresco", "alfresco", FileType.TEXT_PLAIN, "Alfresco text file for search ");
|
||||
|
||||
file4 = new FileModel(unique_searchString + ".txt", "uniquee" + title, description, FileType.TEXT_PLAIN, "Unique text file for search ");
|
||||
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file2);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file3);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file4);
|
||||
|
||||
waitForMetadataIndexing(file4.getName(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which create an http post request to Search API end point.
|
||||
* @param term String search term
|
||||
* @return {@link SearchResponse} response.
|
||||
* @throws Exception if error
|
||||
*
|
||||
*/
|
||||
protected SearchResponse query(String term) throws Exception
|
||||
{
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setLanguage("afts");
|
||||
queryReq.setQuery(term);
|
||||
SearchRequest query = new SearchRequest(queryReq);
|
||||
return restClient.authenticateUser(userModel).withSearchAPI().search(query);
|
||||
}
|
||||
/**
|
||||
* Helper method which create an http post request to Search API end point.
|
||||
*
|
||||
* @return {@link SearchResponse} response.
|
||||
* @throws Exception if error
|
||||
*
|
||||
*/
|
||||
protected SearchResponse query(RestRequestQueryModel queryReq, RestRequestHighlightModel highlight) throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest(queryReq);
|
||||
query.setHighlight(highlight);
|
||||
return restClient.authenticateUser(userModel).withSearchAPI().search(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)
|
||||
{
|
||||
try
|
||||
{
|
||||
return restClient.authenticateUser(userModel).withSearchAPI().search(query);
|
||||
}
|
||||
catch (final Exception exception)
|
||||
{
|
||||
throw new RuntimeException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes an SQL Query using "solr" as output format.
|
||||
*
|
||||
* @param sql the SQL statement.
|
||||
*/
|
||||
protected RestResponse executeSqlAsSolr(String sql) throws Exception
|
||||
{
|
||||
SearchSqlRequest sqlRequest = new SearchSqlRequest();
|
||||
sqlRequest.setSql(sql);
|
||||
sqlRequest.setFormat("solr");
|
||||
return searchSql(sqlRequest);
|
||||
}
|
||||
|
||||
protected SearchRequest createQuery(String term)
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery(term);
|
||||
query.setQuery(queryReq);
|
||||
return query;
|
||||
}
|
||||
|
||||
protected SearchRequest carsQuery()
|
||||
{
|
||||
return createQuery("cars");
|
||||
}
|
||||
|
||||
protected RestResponse searchSql(SearchSqlRequest searchSqlRequest) throws Exception
|
||||
{
|
||||
return restClient.authenticateUser(userModel).withSearchSqlAPI().searchSql(searchSqlRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for Solr to finish indexing: Indexing has caught up = true if search returns appropriate 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
|
||||
{
|
||||
// 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();
|
||||
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 <= 3; searchCount++)
|
||||
{
|
||||
SearchRequest searchRequest = createQuery(query);
|
||||
SearchResponse response = query(searchRequest);
|
||||
|
||||
if (restClient.getStatusCode().matches(expectedStatusCode))
|
||||
{
|
||||
boolean found = !response.getEntries().isEmpty();
|
||||
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new AuthenticationException("API returned status code:" + restClient.getStatusCode() + " Expected: " + expectedStatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
return resultAsExpected;
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonObject;
|
||||
|
||||
import org.alfresco.dataprep.SiteService.Visibility;
|
||||
import org.alfresco.rest.search.FacetFieldBucket;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.RestResultBucketsModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
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.TestGroup;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Faceted search test with FacetFields
|
||||
* @author Meenal Bhave
|
||||
*
|
||||
*/
|
||||
public class FacetFieldsSearchTest extends AbstractSearchTest
|
||||
{
|
||||
private UserModel userWithNoAccess, userCanAccessTextFile;
|
||||
private SiteModel testSite;
|
||||
private FolderModel testFolder;
|
||||
private FileModel textFile, htmlFile;
|
||||
private String fname;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
serverHealth.assertServerIsOnline();
|
||||
|
||||
fname = unique_searchString + "facet";
|
||||
|
||||
testSite = new SiteModel(RandomData.getRandomName("SiteSearch"));
|
||||
testSite.setVisibility(Visibility.PRIVATE);
|
||||
|
||||
testSite = dataSite.usingUser(userModel).createSite(testSite);
|
||||
|
||||
// Create another user who would not have access to the Private Site created by userModel
|
||||
userWithNoAccess = dataUser.createRandomTestUser("UserSearch2");
|
||||
userCanAccessTextFile = dataUser.createRandomTestUser("UserSearch3");
|
||||
|
||||
// Create a folder and a file as test User
|
||||
testFolder = new FolderModel(fname);
|
||||
dataContent.usingUser(userModel).usingSite(testSite).createFolder(testFolder);
|
||||
|
||||
textFile = new FileModel(fname + "-1.txt", fname, fname, FileType.TEXT_PLAIN, fname + " file for search ");
|
||||
dataContent.usingUser(userModel).usingSite(testSite).createContent(textFile);
|
||||
|
||||
htmlFile = new FileModel(fname + "-2.html", FileType.HTML, fname + " file 2 for search ");
|
||||
dataContent.usingUser(userModel).usingSite(testSite).createContent(htmlFile);
|
||||
|
||||
// Set Node Permissions to allow access for user for text File
|
||||
JsonObject userPermission = Json.createObjectBuilder()
|
||||
.add("permissions", Json.createObjectBuilder().add("isInheritanceEnabled", false)
|
||||
.add("locallySet",Json.createObjectBuilder().add("authorityId", userCanAccessTextFile.getUsername())
|
||||
.add("name", "SiteConsumer").add("accessStatus", "ALLOWED")))
|
||||
.build();
|
||||
String putBody = userPermission.toString();
|
||||
|
||||
restClient.authenticateUser(userModel).withCoreAPI().usingNode(textFile).updateNode(putBody);
|
||||
|
||||
// Wait for the file to be indexed
|
||||
waitForIndexing(htmlFile.getName(), true);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 })
|
||||
public void testSearchFacetFieldsBucketExcludedWhenMinCount2() throws Exception
|
||||
{
|
||||
// Create Query with FacetFields: Site and Content MimeType
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("name:" + fname);
|
||||
query.setQuery(queryReq);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
|
||||
facets.add(new RestRequestFacetFieldModel("SITE", "SEARCH.FACET_FIELDS.SITE", 0)); // MinCount = 0
|
||||
facets.add(new RestRequestFacetFieldModel("cm:content.mimetype", "Mimetype", 2)); // MinCount = 2
|
||||
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
// Search query using user who created site
|
||||
SearchResponse response = query(query);
|
||||
|
||||
// Expect MimeType bucket with size 1 is excluded as minCount = 2 won't be reached
|
||||
Assert.assertEquals(response.getContext().getFacetsFields().size(), 1);
|
||||
|
||||
// Expect SITE bucket is included and MinCount defaults to 1
|
||||
RestResultBucketsModel facetFieldList = response.getContext().getFacetsFields().get(0);
|
||||
Assert.assertEquals(facetFieldList.getLabel(), "SEARCH.FACET_FIELDS.SITE");
|
||||
Assert.assertEquals(facetFieldList.getBuckets().size(), 1);
|
||||
|
||||
FacetFieldBucket bucket1 = facetFieldList.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is(testSite.getId());
|
||||
bucket1.assertThat().field("filterQuery").contains(testSite.getId());
|
||||
bucket1.assertThat().field("count").is(3); // One folder and 2 files created above
|
||||
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 })
|
||||
public void testSearchWithFacetFieldsMinCountChecks() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("name:" + fname);
|
||||
query.setQuery(queryReq);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
|
||||
// MinCount not set
|
||||
facets.add(new RestRequestFacetFieldModel("SITE", "SEARCH.FACET_FIELD1.SITE", null)); // MinCount Not set
|
||||
facets.add(new RestRequestFacetFieldModel("cm:content.mimetype", "SEARCH.FACET_FIELD2.Mimetype", 1)); // MinCount = 1
|
||||
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
// Search query using user who created site
|
||||
SearchResponse response = query(query);
|
||||
|
||||
// Expect 2 Facet buckets to be retrieved: MinCount when not set defaults to 1
|
||||
List<RestResultBucketsModel> facetFieldBucketsList = response.getContext().getFacetsFields();
|
||||
Assert.assertEquals(facetFieldBucketsList.size(), 2, "FacetField");
|
||||
|
||||
RestResultBucketsModel facetFieldList = facetFieldBucketsList.get(0);
|
||||
Assert.assertEquals(facetFieldList.getLabel(), "SEARCH.FACET_FIELD1.SITE");
|
||||
|
||||
FacetFieldBucket bucket1 = facetFieldList.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is(testSite.getId());
|
||||
bucket1.assertThat().field("filterQuery").contains(testSite.getId());
|
||||
bucket1.assertThat().field("count").is(3);
|
||||
|
||||
// MimeType bucket will be shown with 2 buckets
|
||||
facetFieldList = facetFieldBucketsList.get(1);
|
||||
Assert.assertEquals(facetFieldList.getLabel(), "SEARCH.FACET_FIELD2.Mimetype");
|
||||
Assert.assertEquals(facetFieldList.getBuckets().size(), 2);
|
||||
|
||||
bucket1 = facetFieldList.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is("text/html");
|
||||
bucket1.assertThat().field("filterQuery").contains("text/html");
|
||||
bucket1.assertThat().field("count").is(1);
|
||||
bucket1.assertThat().field("display").is("HTML");
|
||||
|
||||
bucket1 = facetFieldList.getBuckets().get(1);
|
||||
bucket1.assertThat().field("label").is("text/plain");
|
||||
bucket1.assertThat().field("filterQuery").contains("text/plain");
|
||||
bucket1.assertThat().field("count").is(1);
|
||||
bucket1.assertThat().field("display").is("Plain Text");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 })
|
||||
public void testSearchWithFacetFieldsNoFacetsWhenNoAccess() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("name:" + fname);
|
||||
query.setQuery(queryReq);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
|
||||
facets.add(new RestRequestFacetFieldModel("SITE", "SEARCH.FACET_FIELD1.SITE", null)); // MinCount Not set
|
||||
facets.add(new RestRequestFacetFieldModel("cm:content.mimetype", "SEARCH.FACET_FIELD2.Mimetype", 1)); // MinCount = 1
|
||||
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
// Search query using other user
|
||||
SearchResponse response = restClient.authenticateUser(userWithNoAccess).withSearchAPI().search(query);
|
||||
|
||||
// User has No access to matching content hence no buckets expected
|
||||
Assert.assertNull(response.getContext().getFacetsFields());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 })
|
||||
public void testSearchWithFacetFieldsOnlyFacetsWhereAccess() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("name:" + fname);
|
||||
query.setQuery(queryReq);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
|
||||
facets.add(new RestRequestFacetFieldModel("SITE", "SEARCH.FACET_FIELD1.SITE", null)); // MinCount Not set
|
||||
facets.add(new RestRequestFacetFieldModel("cm:content.mimetype", "SEARCH.FACET_FIELD2.Mimetype", 1)); // MinCount = 1
|
||||
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
// Search query using user that can access 1 text file
|
||||
SearchResponse response = restClient.authenticateUser(userCanAccessTextFile).withSearchAPI().search(query);
|
||||
|
||||
List<RestResultBucketsModel> facetFieldBucketsList = response.getContext().getFacetsFields();
|
||||
Assert.assertEquals(facetFieldBucketsList.size(), 2);
|
||||
|
||||
// Check FacetField 1
|
||||
RestResultBucketsModel facetFieldList = facetFieldBucketsList.get(0);
|
||||
|
||||
// User has granular permissions to content within this private site, so expect the Site bucket
|
||||
Assert.assertEquals(facetFieldList.getLabel(), "SEARCH.FACET_FIELD1.SITE");
|
||||
|
||||
FacetFieldBucket bucket1 = facetFieldList.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is(testSite.getId());
|
||||
bucket1.assertThat().field("filterQuery").contains(testSite.getId());
|
||||
bucket1.assertThat().field("count").is(1);
|
||||
|
||||
// Expect MimeType bucket shows only 1 bucket where user has access to content
|
||||
facetFieldList = facetFieldBucketsList.get(1);
|
||||
Assert.assertEquals(facetFieldList.getLabel(), "SEARCH.FACET_FIELD2.Mimetype");
|
||||
Assert.assertEquals(facetFieldList.getBuckets().size(), 1);
|
||||
|
||||
// User has access to text file alone, so expect bucket for text/plain and not for html content.
|
||||
bucket1 = facetFieldList.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is("text/plain");
|
||||
bucket1.assertThat().field("label").isNot("text/html");
|
||||
bucket1.assertThat().field("filterQuery").contains("text/plain");
|
||||
bucket1.assertThat().field("count").is(1);
|
||||
bucket1.assertThat().field("display").is("Plain Text");
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import org.alfresco.rest.model.RestErrorModel;
|
||||
import org.alfresco.rest.search.FacetInterval;
|
||||
import org.alfresco.rest.search.RestGenericBucketModel;
|
||||
import org.alfresco.rest.search.RestGenericFacetResponseModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetIntervalsModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetSetModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Faceted Intervals Search Test
|
||||
* @author Gethin James
|
||||
*/
|
||||
public class FacetIntervalSearchTest extends AbstractSearchTest
|
||||
{
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check facet intervals mandatory fields")
|
||||
public void checkingFacetsMandatoryErrorMessages()throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetIntervalsModel facetIntervalsModel = new RestRequestFacetIntervalsModel();
|
||||
FacetInterval facetInterval = new FacetInterval(null, null, null);
|
||||
facetIntervalsModel.setIntervals(Arrays.asList(facetInterval));
|
||||
query.setFacetIntervals(facetIntervalsModel);
|
||||
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "facetIntervals intervals field"));
|
||||
facetInterval.setField("created");
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_COLLECTION, "facetIntervals intervals sets"));
|
||||
|
||||
RestRequestFacetSetModel restFacetSetModel = new RestRequestFacetSetModel();
|
||||
restFacetSetModel.setLabel("theRest");
|
||||
facetInterval.setSets(Arrays.asList(restFacetSetModel));
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "facetIntervals intervals created sets start"));
|
||||
|
||||
restFacetSetModel.setStart("A");
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "facetIntervals intervals created sets end"));
|
||||
|
||||
restFacetSetModel.setEnd("B");
|
||||
RestRequestFacetSetModel duplicate = new RestRequestFacetSetModel();
|
||||
facetInterval.setSets(Arrays.asList(restFacetSetModel,duplicate));
|
||||
duplicate.setLabel("theRest");
|
||||
duplicate.setStart("A");
|
||||
duplicate.setEnd("C");
|
||||
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary("duplicate set interval label [theRest=2]");
|
||||
|
||||
facetInterval.setSets(Arrays.asList(restFacetSetModel));
|
||||
facetInterval.setLabel("thesame");
|
||||
FacetInterval duplicateLabel = new FacetInterval("creator", "thesame", Arrays.asList(duplicate));
|
||||
facetIntervalsModel.setIntervals(Arrays.asList(facetInterval, duplicateLabel));
|
||||
query.setFacetIntervals(facetIntervalsModel);
|
||||
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary("duplicate interval label [thesame=2]");
|
||||
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check basic facet intervals search api")
|
||||
public void searchWithBasicInterval()throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetIntervalsModel facetIntervalsModel = new RestRequestFacetIntervalsModel();
|
||||
RestRequestFacetSetModel restRequestFacetSetModel = new RestRequestFacetSetModel();
|
||||
restRequestFacetSetModel.setStart("a");
|
||||
restRequestFacetSetModel.setEnd("user");
|
||||
restRequestFacetSetModel.setLabel("aUser");
|
||||
|
||||
RestRequestFacetSetModel restFacetSetModel = new RestRequestFacetSetModel();
|
||||
restFacetSetModel.setStart("user");
|
||||
restFacetSetModel.setEnd("z");
|
||||
restFacetSetModel.setStartInclusive(false);
|
||||
restFacetSetModel.setLabel("theRest");
|
||||
|
||||
FacetInterval facetInterval = new FacetInterval("creator", null, Arrays.asList(restRequestFacetSetModel, restFacetSetModel));
|
||||
facetIntervalsModel.setIntervals(Arrays.asList(facetInterval));
|
||||
query.setFacetIntervals(facetIntervalsModel);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
Assert.assertEquals(facetResponseModel.getBuckets().size(), 2);
|
||||
bucket.assertThat().field("label").is("aUser");
|
||||
bucket.assertThat().field("filterQuery").is("creator:[\"a\" TO \"user\"]");
|
||||
bucket.getMetrics().get(0).assertThat().field("type").is("count");
|
||||
bucket.getMetrics().get(0).assertThat().field("value").contains("{count=");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(1);
|
||||
|
||||
bucket.assertThat().field("label").is("theRest");
|
||||
bucket.assertThat().field("filterQuery").is("creator:<\"user\" TO \"z\"]");
|
||||
bucket.getMetrics().get(0).assertThat().field("type").is("count");
|
||||
bucket.getMetrics().get(0).assertThat().field("value").is("{count=0}");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check date facet intervals search api")
|
||||
public void searchWithDates() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetIntervalsModel facetIntervalsModel = new RestRequestFacetIntervalsModel();
|
||||
RestRequestFacetSetModel restRequestFacetSetModel = new RestRequestFacetSetModel();
|
||||
restRequestFacetSetModel.setStart("*");
|
||||
restRequestFacetSetModel.setEnd("2016");
|
||||
restRequestFacetSetModel.setEndInclusive(false);
|
||||
restRequestFacetSetModel.setLabel("Before2016");
|
||||
|
||||
RestRequestFacetSetModel restFacetSetModel = new RestRequestFacetSetModel();
|
||||
restFacetSetModel.setStart("2016");
|
||||
restFacetSetModel.setEnd("now");
|
||||
restFacetSetModel.setLabel("From2016");
|
||||
|
||||
FacetInterval facetInterval = new FacetInterval("cm:modified", "modified", Arrays.asList(restRequestFacetSetModel, restFacetSetModel));
|
||||
facetIntervalsModel.setIntervals(Arrays.asList(facetInterval));
|
||||
query.setFacetIntervals(facetIntervalsModel);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
facetResponseModel.assertThat().field("label").is("modified");
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
Assert.assertEquals(facetResponseModel.getBuckets().size(), 2);
|
||||
|
||||
bucket.assertThat().field("label").is("From2016");
|
||||
bucket.assertThat().field("filterQuery").is("cm:modified:[\"2016\" TO \"now\"]");
|
||||
bucket.getMetrics().get(0).assertThat().field("type").is("count");
|
||||
bucket.getMetrics().get(0).assertThat().field("value").contains("{count=");
|
||||
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(1);
|
||||
|
||||
bucket.assertThat().field("label").is("Before2016");
|
||||
bucket.assertThat().field("filterQuery").is("cm:modified:[\"*\" TO \"2016\">");
|
||||
bucket.getMetrics().get(0).assertThat().field("type").is("count");
|
||||
bucket.getMetrics().get(0).assertThat().field("value").is("{count=0}");
|
||||
}
|
||||
|
||||
}
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.rest.model.RestErrorModel;
|
||||
import org.alfresco.rest.model.RestRequestRangesModel;
|
||||
import org.alfresco.rest.search.RestGenericBucketModel;
|
||||
import org.alfresco.rest.search.RestGenericFacetResponseModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Faceted Range Search Query for numeric range
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "name:A*"
|
||||
* },
|
||||
* "range": {
|
||||
* "field": "content.size",
|
||||
* "start": "0",
|
||||
* "end": "400",
|
||||
* "gap": "100"
|
||||
* }
|
||||
* }
|
||||
* Date range query:
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "name:A*"
|
||||
* },
|
||||
* "range": {
|
||||
* "field": "created",
|
||||
* "start": "2015-09-29T10:45:15.729Z",
|
||||
* "end": "2016-09-29T10:45:15.729Z",
|
||||
* "gap": "+100DAY"
|
||||
* }
|
||||
* }
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class FacetRangeSearchTest extends AbstractSearchTest
|
||||
{
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check facet intervals mandatory fields")
|
||||
public void checkingFacetsMandatoryErrorMessages()
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "field"));
|
||||
ranges.clear();
|
||||
facetRangeModel.setField("content.size");
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "start"));
|
||||
facetRangeModel.setStart("0");
|
||||
ranges.clear();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "end"));
|
||||
facetRangeModel.setEnd("400");
|
||||
query.setRanges(ranges);
|
||||
ranges.clear();
|
||||
ranges.add(facetRangeModel);
|
||||
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "gap"));
|
||||
|
||||
facetRangeModel.setGap("100");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check basic facet range search api")
|
||||
public void searchWithRange()
|
||||
{
|
||||
SearchRequest query = createQuery("* AND SITE:'" + siteModel.getId() + "'");
|
||||
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("content.size");
|
||||
facetRangeModel.setStart("0");
|
||||
facetRangeModel.setEnd("200");
|
||||
facetRangeModel.setGap("20");
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
bucket.assertThat().field("label").is("[20 - 40)");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"20\" TO \"40\">");
|
||||
Map<String,String> metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 2, "Unexpected count for first bucket.");
|
||||
Map<String, String> info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"20");
|
||||
assertEquals(info.get("end"),"40");
|
||||
Assert.assertNull(info.get("count"));
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"false");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(1);
|
||||
bucket.assertThat().field("label").is("[40 - 120)");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"40\" TO \"120\">");
|
||||
metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for second bucket.");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"40");
|
||||
assertEquals(info.get("end"),"120");
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"false");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(2);
|
||||
bucket.assertThat().field("label").is("[120 - 200]");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"120\" TO \"200\"]");
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for third bucket.");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"120");
|
||||
assertEquals(info.get("end"),"200");
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check date facet intervals search api")
|
||||
public void searchWithRangeHardend()
|
||||
{
|
||||
SearchRequest query = createQuery("* AND SITE:'" + siteModel.getId() + "'");
|
||||
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("content.size");
|
||||
facetRangeModel.setStart("0");
|
||||
facetRangeModel.setEnd("200");
|
||||
facetRangeModel.setGap("20");
|
||||
facetRangeModel.setHardend(true);
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
bucket.assertThat().field("label").is("[20 - 40)");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"20\" TO \"40\">");
|
||||
Map<String,String> metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 2, "Unexpected count for first bucket.");
|
||||
Map<String, String> info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"20");
|
||||
assertEquals(info.get("end"),"40");
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"false");
|
||||
Assert.assertNull(info.get("count"));
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(1);
|
||||
bucket.assertThat().field("label").is("[40 - 120)");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"40\" TO \"120\">");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"40");
|
||||
assertEquals(info.get("end"),"120");
|
||||
metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for second bucket.");
|
||||
Assert.assertNull(info.get("count"));
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"false");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(2);
|
||||
bucket.assertThat().field("label").is("[120 - 200]");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:[\"120\" TO \"200\"]");
|
||||
metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for third bucket.");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"120");
|
||||
assertEquals(info.get("end"),"200");
|
||||
Assert.assertNull(info.get("count"));
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
}
|
||||
|
||||
/** This test relies on a document created in 2015 existing, probably part of the sample site. */
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_121 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check date facet intervals search api")
|
||||
public void searchDateRange()
|
||||
{
|
||||
SearchRequest query = createQuery("name:A*");
|
||||
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("created");
|
||||
facetRangeModel.setStart("2015-09-29T10:45:15.729Z");
|
||||
facetRangeModel.setEnd("2016-09-29T10:45:15.729Z");
|
||||
facetRangeModel.setGap("+280DAY");
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
List<RestGenericBucketModel> buckets = facetResponseModel.getBuckets();
|
||||
assertThat(buckets.size(),is(1));
|
||||
|
||||
RestGenericBucketModel bucket = buckets.get(0);
|
||||
bucket.assertThat().field("label").is("[2015-09-29T10:45:15.729Z - 2017-04-11T10:45:15.729Z]");
|
||||
bucket.assertThat().field("filterQuery").is("created:[\"2015-09-29T10:45:15.729Z\" TO \"2017-04-11T10:45:15.729Z\"]");
|
||||
bucket.getMetrics().get(0).assertThat().field("value").is("{count=1}");
|
||||
Map<String, String> info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"2015-09-29T10:45:15.729Z");
|
||||
assertEquals(info.get("end"),"2017-04-11T10:45:15.729Z");
|
||||
Assert.assertNull(info.get("count"),"1");
|
||||
assertEquals(info.get("startInclusive"),"true");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check date facet intervals search api")
|
||||
public void searchDateAndSizeRanges()
|
||||
{
|
||||
SearchRequest query = createQuery("* AND SITE:'" + siteModel.getId() + "'");
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("created");
|
||||
facetRangeModel.setStart("2015-09-29T10:45:15.729Z");
|
||||
facetRangeModel.setEnd("2016-09-29T10:45:15.729Z");
|
||||
facetRangeModel.setGap("+280DAY");
|
||||
ranges.add(facetRangeModel);
|
||||
RestRequestRangesModel facetCountRangeModel = new RestRequestRangesModel();
|
||||
facetCountRangeModel.setField("content.size");
|
||||
facetCountRangeModel.setStart("0");
|
||||
facetCountRangeModel.setEnd("500");
|
||||
facetCountRangeModel.setGap("200");
|
||||
ranges.add(facetCountRangeModel);
|
||||
query.setRanges(ranges);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Check basic facet range search api")
|
||||
public void searchWithRangeAndIncludeUpperBound()
|
||||
{
|
||||
SearchRequest query = createQuery("* AND SITE:'" + siteModel.getId() + "'");
|
||||
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("content.size");
|
||||
facetRangeModel.setStart("0");
|
||||
facetRangeModel.setEnd("200");
|
||||
facetRangeModel.setGap("20");
|
||||
List<String> include = new ArrayList<>();
|
||||
include.add("upper");
|
||||
facetRangeModel.setInclude(include);
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<>();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
SearchResponse response = query(query);
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
bucket.assertThat().field("label").is("(20 - 40]");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:<\"20\" TO \"40\"]");
|
||||
Map<String,String> metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 2, "Unexpected count for first bucket.");
|
||||
Map<String, String> info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"20");
|
||||
assertEquals(info.get("end"),"40");
|
||||
Assert.assertNull(info.get("count"));
|
||||
assertEquals(info.get("startInclusive"),"false");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(1);
|
||||
bucket.assertThat().field("label").is("(40 - 120]");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:<\"40\" TO \"120\"]");
|
||||
metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for second bucket.");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"40");
|
||||
assertEquals(info.get("end"),"120");
|
||||
assertEquals(info.get("startInclusive"),"false");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
|
||||
bucket = facetResponseModel.getBuckets().get(2);
|
||||
bucket.assertThat().field("label").is("(120 - 200]");
|
||||
bucket.assertThat().field("filterQuery").is("content.size:<\"120\" TO \"200\"]");
|
||||
metric = (Map<String, String>) bucket.getMetrics().get(0).getValue();
|
||||
assertEquals(Integer.valueOf(metric.get("count")).intValue(), 1, "Unexpected count for third bucket.");
|
||||
info = (Map<String, String>) bucket.getBucketInfo();
|
||||
assertEquals(info.get("start"),"120");
|
||||
assertEquals(info.get("end"),"200");
|
||||
assertEquals(info.get("startInclusive"),"false");
|
||||
assertEquals(info.get("endInclusive"),"true");
|
||||
}
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.search.FacetFieldBucket;
|
||||
import org.alfresco.rest.search.FacetQuery;
|
||||
import org.alfresco.rest.search.RestGenericBucketModel;
|
||||
import org.alfresco.rest.search.RestGenericFacetResponseModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.RestResultBucketsModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.testng.Assert;
|
||||
import org.testng.TestException;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Faceted search test.
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class FacetedSearchTest extends AbstractSearchTest
|
||||
{
|
||||
|
||||
/**
|
||||
* Perform the below facet query.
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "cars",
|
||||
* "language": "afts"
|
||||
* },
|
||||
* "facetQueries": [
|
||||
* {"query": "content.size:[o TO 102400]", "label": "small"},
|
||||
* {"query": "content.size:[102400 TO 1048576]", "label": "medium"},
|
||||
* {"query": "content.size:[1048576 TO 16777216]", "label": "large"}
|
||||
* ],
|
||||
* "facetFields": {"facets": [{"field": "'content.size'"}]}
|
||||
* }
|
||||
*
|
||||
* Expected response
|
||||
* {"list": {
|
||||
* "entries": [... All the results],
|
||||
* "pagination": {
|
||||
* "maxItems": 100,
|
||||
* "hasMoreItems": false,
|
||||
* "totalItems": 61,
|
||||
* "count": 61,
|
||||
* "skipCount": 0
|
||||
* },
|
||||
* "facetsFields": [
|
||||
* {
|
||||
* "type": "query",
|
||||
* "label": "foo",
|
||||
* "buckets": [
|
||||
* {
|
||||
* "label": "small",
|
||||
* "filterQuery": "content.size:[0 TO 102400]",
|
||||
* "display": 1
|
||||
* },
|
||||
* {
|
||||
* "label": "large",
|
||||
* "filterQuery": "content.size:[1048576 TO 16777216]",
|
||||
* "metrics": [
|
||||
* {
|
||||
* "type": "count",
|
||||
* "value": {
|
||||
* "count": 0
|
||||
* }
|
||||
* }
|
||||
* ]
|
||||
* },
|
||||
* }}
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.SEARCH,
|
||||
TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION, description = "Checks facet queries for the Search api")
|
||||
public void searchWithQueryFaceting() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cars");
|
||||
query.setQuery(queryReq);
|
||||
|
||||
List<FacetQuery> facets = new ArrayList<FacetQuery>();
|
||||
facets.add(new FacetQuery("content.size:[0 TO 102400]", "small"));
|
||||
facets.add(new FacetQuery("content.size:[102400 TO 1048576]", "medium"));
|
||||
facets.add(new FacetQuery("content.size:[1048576 TO 16777216]", "large"));
|
||||
query.setFacetQueries(facets);
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("'content.size'"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(true);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
|
||||
response.assertThat().entriesListIsNotEmpty();
|
||||
response.getContext().assertThat().field("facetQueries").isNotEmpty();
|
||||
|
||||
FacetFieldBucket facet = response.getContext().getFacetQueries().get(0);
|
||||
facet.assertThat().field("label").contains("small").and().field("count").isGreaterThan(0);
|
||||
facet.assertThat().field("label").contains("small").and().field("filterQuery").is("content.size:[0 TO 102400]");
|
||||
response.getContext().getFacetQueries().get(1).assertThat().field("label").contains("large")
|
||||
.and().field("count").isLessThan(1)
|
||||
.and().field("filterQuery").is("content.size:[1048576 TO 16777216]");
|
||||
response.getContext().getFacetQueries().get(2).assertThat().field("label").contains("medium")
|
||||
.and().field("count").isLessThan(1)
|
||||
.and().field("filterQuery").is("content.size:[102400 TO 1048576]");
|
||||
//We don't expect to see the FacetFields if group is being used.
|
||||
Assert.assertNull(response.getContext().getFacetsFields());
|
||||
Assert.assertNull(response.getContext().getFacets());
|
||||
}
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH , TestGroup.ASS_1})
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH ,TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks facet queries for the Search api")
|
||||
/**
|
||||
* * Perform a group by faceting, below test groups the facet by group name foo.
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "cars",
|
||||
* "language": "afts"
|
||||
* },
|
||||
* "facetQueries": [
|
||||
* {"query": "content.size:[o TO 102400]", "label": "small","group":"foo"},
|
||||
* {"query": "content.size:[102400 TO 1048576]", "label": "medium","group":"foo"},
|
||||
* {"query": "content.size:[1048576 TO 16777216]", "label": "large","group":"foo"}
|
||||
* ],
|
||||
* "facetFields": {"facets": [{"field": "'content.size'"}]}
|
||||
* }
|
||||
*
|
||||
* Expected response
|
||||
* {"list": {
|
||||
* "entries": [... All the results],
|
||||
* "pagination": {
|
||||
* "maxItems": 100,
|
||||
* "hasMoreItems": false,
|
||||
* "totalItems": 61,
|
||||
* "count": 61,
|
||||
* "skipCount": 0
|
||||
* },
|
||||
* "context": {
|
||||
* "consistency": {"lastTxId": 512},
|
||||
* //Added below as part of SEARCH-374
|
||||
* "facets": [
|
||||
* { "label": "foo",
|
||||
* "buckets": [
|
||||
* { "label": "small", "count": 61, "filterQuery": "content.size:[o TO 102400]"},
|
||||
* { "label": "large", "count": 0, "filterQuery": "content.size:[1048576 TO 16777216]"},
|
||||
* { "label": "medium", "count": 61, "filterQuery": "content.size:[102400 TO 1048576]"}
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* }}
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void searchQueryFacetingWithGroup() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cars");
|
||||
query.setQuery(queryReq);
|
||||
|
||||
List<FacetQuery> facets = new ArrayList<FacetQuery>();
|
||||
facets.add(new FacetQuery("content.size:[0 TO 102400]", "small", "foo"));
|
||||
facets.add(new FacetQuery("content.size:[102400 TO 1048576]", "medium", "foo"));
|
||||
facets.add(new FacetQuery("content.size:[1048576 TO 16777216]", "large", "foo"));
|
||||
query.setFacetQueries(facets);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("'content.size'"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
|
||||
// We don't expect to see the FacetQueries if group is being used.
|
||||
Assert.assertTrue(response.getContext().getFacetQueries() == null);
|
||||
// Validate the facet field structure is correct.
|
||||
Assert.assertFalse(response.getContext().getFacets().isEmpty());
|
||||
Assert.assertEquals(response.getContext().getFacets().get(0).getLabel(), "foo");
|
||||
|
||||
RestGenericBucketModel bucket = response.getContext().getFacets().get(0).getBuckets().get(0);
|
||||
bucket.assertThat().field("label").isNotEmpty();
|
||||
Assert.assertEquals(bucket.getMetrics().get(0).getType(), "count");
|
||||
Assert.assertNotEquals(bucket.getMetrics().get(0).getValue(), "");
|
||||
bucket.assertThat().field("filterQuery").isNotEmpty();
|
||||
response.getContext().getFacets().get(0).getBuckets().forEach(action -> {
|
||||
switch (action.getLabel())
|
||||
{
|
||||
case "small":
|
||||
Assert.assertEquals(action.getFilterQuery(), "content.size:[0 TO 102400]");
|
||||
break;
|
||||
case "medium":
|
||||
Assert.assertEquals(action.getFilterQuery(), "content.size:[102400 TO 1048576]");
|
||||
break;
|
||||
case "large":
|
||||
Assert.assertEquals(action.getFilterQuery(), "content.size:[1048576 TO 16777216]");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new TestException("Unexpected value returned");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH , TestGroup.ASS_1})
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH ,TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks facet queries for the Search api")
|
||||
/**
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "*"
|
||||
* },
|
||||
* "facetFields": {
|
||||
* "facets": [{"field": "cm:mimetype"},{"field": "modifier"}]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public void searchWithFactedFields() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery(unique_searchString);
|
||||
query.setQuery(queryReq);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
facets.add(new RestRequestFacetFieldModel("cm:mimetype"));
|
||||
facets.add(new RestRequestFacetFieldModel("modifier"));
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
|
||||
Assert.assertFalse(response.getContext().getFacetsFields().isEmpty());
|
||||
Assert.assertNull(response.getContext().getFacetQueries());
|
||||
Assert.assertNull(response.getContext().getFacets());
|
||||
|
||||
RestResultBucketsModel model = response.getContext().getFacetsFields().get(0);
|
||||
Assert.assertEquals(model.getLabel(), "modifier");
|
||||
|
||||
model.assertThat().field("label").is("modifier");
|
||||
FacetFieldBucket bucket1 = model.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is(userModel.getUsername());
|
||||
bucket1.assertThat().field("display").is(userModel.getUsername() + " FirstName LN-" + userModel.getUsername());
|
||||
bucket1.assertThat().field("filterQuery").is("modifier:\"" + userModel.getUsername() + "\"");
|
||||
bucket1.assertThat().field("count").is(1);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH , TestGroup.ASS_1})
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH ,TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks facet queries for the Search api")
|
||||
/**
|
||||
* Test that items returned are in the format of generic facets.
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "*"
|
||||
* },
|
||||
* "facetFields": {
|
||||
* "facets": [{"field": "cm:mimetype"},{"field": "modifier"}]
|
||||
* },
|
||||
* "facetFormat":"V2"
|
||||
* }
|
||||
*/
|
||||
public void searchWithFactedFieldsFacetFormatV2() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery(unique_searchString);
|
||||
query.setQuery(queryReq);
|
||||
query.setFacetFormat("V2");
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> facets = new ArrayList<RestRequestFacetFieldModel>();
|
||||
facets.add(new RestRequestFacetFieldModel("cm:mimetype"));
|
||||
facets.add(new RestRequestFacetFieldModel("modifier"));
|
||||
facetFields.setFacets(facets);
|
||||
query.setFacetFields(facetFields);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
|
||||
Assert.assertNull(response.getContext().getFacetsFields());
|
||||
Assert.assertNull(response.getContext().getFacetQueries());
|
||||
Assert.assertFalse(response.getContext().getFacets().isEmpty());
|
||||
RestGenericFacetResponseModel model = response.getContext().getFacets().get(0);
|
||||
Assert.assertEquals(model.getLabel(), "modifier");
|
||||
|
||||
model.assertThat().field("label").is("modifier");
|
||||
RestGenericBucketModel bucket1 = model.getBuckets().get(0);
|
||||
bucket1.assertThat().field("label").is(userModel.getUsername());
|
||||
bucket1.assertThat().field("display").is(userModel.getUsername() + " FirstName LN-" + userModel.getUsername());
|
||||
bucket1.assertThat().field("filterQuery").is("modifier:\"" + userModel.getUsername() + "\"");
|
||||
bucket1.assertThat().field("metrics").is("[{entry=null, type=count, value={count=1}}]");
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import org.alfresco.rest.search.SearchNodeModel;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.FileModel;
|
||||
import org.alfresco.utility.model.FileType;
|
||||
import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Search end point Public API test with finger print.
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class FingerPrintTest extends AbstractSearchTest
|
||||
{
|
||||
private FileModel file1, file2, file3, file4;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void indexSimilarFile() throws Exception
|
||||
{
|
||||
|
||||
/*
|
||||
* Create the following file structure in the same Site : In addition to the preconditions created in dataPreparation
|
||||
* |- folder
|
||||
* |-- pangram-banana.txt
|
||||
* |-- pangram-taco.txt
|
||||
* |-- pangram-cat.txt
|
||||
* |-- dog.txt
|
||||
*/
|
||||
|
||||
FolderModel folder = new FolderModel("The quick brown fox jumps over");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createFolder(folder);
|
||||
|
||||
file1 = new FileModel("pangram-banana.txt", FileType.TEXT_PLAIN, "The quick brown fox jumps over the lazy banana");
|
||||
file2 = new FileModel("pangram-taco.txt", FileType.TEXT_PLAIN, "The quick brown fox jumps over the lazy dog that ate the taco");
|
||||
file3 = new FileModel("pangram-cat.txt", FileType.TEXT_PLAIN, "The quick brown fox jumps over the lazy cat");
|
||||
file4 = new FileModel("dog.txt", FileType.TEXT_PLAIN, "The quick brown fox ate the lazy dog");
|
||||
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file1);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file2);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file3);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).usingResource(folder).createContent(file4);
|
||||
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
// Additional wait implemented to remove inconsistent failures. Ref: Search-1438 for details
|
||||
waitForIndexing("FINGERPRINT:" + file2.getNodeRefWithoutVersion(), true);
|
||||
waitForIndexing("FINGERPRINT:" + file3.getNodeRefWithoutVersion(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search similar document based on document finger print.
|
||||
* The data prep should have loaded 2 files which one is similar
|
||||
* to the files loaded as part of this test.
|
||||
* Note that for fingerprint to work it need a 5 word sequence.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
public void search() throws Exception
|
||||
{
|
||||
String uuid = file1.getNodeRefWithoutVersion();
|
||||
Assert.assertNotNull(uuid);
|
||||
String fingerprint = String.format("FINGERPRINT:%s", uuid);
|
||||
SearchResponse response = query(fingerprint);
|
||||
int count = response.getEntries().size();
|
||||
Assert.assertTrue(count > 1);
|
||||
for (SearchNodeModel m : response.getEntries())
|
||||
{
|
||||
String match = m.getModel().getName();
|
||||
switch (match)
|
||||
{
|
||||
case "pangram.txt":
|
||||
break;
|
||||
case "pangram-banana.txt":
|
||||
break;
|
||||
case "pangram-taco.txt":
|
||||
break;
|
||||
case "pangram-cat.txt":
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Not a match to an expected file: " + m.getModel().getName());
|
||||
}
|
||||
m.getModel().assertThat().field("name").isNot("dog.txt");
|
||||
m.getModel().assertThat().field("name").isNot("cars.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
public void searchSimilar() throws Exception
|
||||
{
|
||||
String uuid = file2.getNodeRefWithoutVersion();
|
||||
Assert.assertNotNull(uuid);
|
||||
|
||||
// In the response entity there is a score of each doc, change below threshold to bring more like or less.
|
||||
String fingerprint = String.format("FINGERPRINT:%s_68", uuid);
|
||||
SearchResponse response = query(fingerprint);
|
||||
|
||||
int count = response.getEntries().size();
|
||||
Assert.assertTrue(count > 1);
|
||||
|
||||
for (SearchNodeModel m : response.getEntries())
|
||||
{
|
||||
switch (m.getModel().getName())
|
||||
{
|
||||
case "pangram.txt":
|
||||
break;
|
||||
case "pangram-taco.txt":
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Not a match to an expected file: " + m.getModel().getName());
|
||||
}
|
||||
m.getModel().assertThat().field("name").isNot("pangram-banana.txt");
|
||||
m.getModel().assertThat().field("name").isNot("pangram-cat.txt");
|
||||
m.getModel().assertThat().field("name").isNot("dog.txt");
|
||||
m.getModel().assertThat().field("name").isNot("cars.txt");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
public void searchSimilar67Percent() throws Exception
|
||||
{
|
||||
String uuid = file2.getNodeRefWithoutVersion();
|
||||
Assert.assertNotNull(uuid);
|
||||
String fingerprint = String.format("FINGERPRINT:%s_68", uuid);
|
||||
SearchResponse response = query(fingerprint);
|
||||
int count = response.getEntries().size();
|
||||
Assert.assertTrue(count > 1);
|
||||
for (SearchNodeModel m : response.getEntries())
|
||||
{
|
||||
switch (m.getModel().getName())
|
||||
{
|
||||
case "pangram.txt":
|
||||
break;
|
||||
case "pangram-taco.txt":
|
||||
break;
|
||||
case "pangram-cat.txt":
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Not a match to an expected file: " + m.getModel().getName());
|
||||
}
|
||||
m.getModel().assertThat().field("name").isNot("pangram-banana.txt");
|
||||
m.getModel().assertThat().field("name").isNot("dog.txt");
|
||||
m.getModel().assertThat().field("name").isNot("cars.txt");
|
||||
}
|
||||
}
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.model.RestErrorModel;
|
||||
import org.alfresco.rest.model.RestRequestRangesModel;
|
||||
import org.alfresco.rest.search.Pagination;
|
||||
import org.alfresco.rest.search.RestGenericBucketModel;
|
||||
import org.alfresco.rest.search.RestGenericFacetResponseModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestPivotModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Faceted search test.
|
||||
* @author Gethin James
|
||||
*
|
||||
*/
|
||||
public class PivotFacetedSearchTest extends AbstractSearchTest
|
||||
{
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with pivot using Search api")
|
||||
public void searchWithPivotingErrors() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("'creator'"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel pivots = new RestRequestPivotModel();
|
||||
pivotModelList.add(pivots);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "pivot key"));
|
||||
|
||||
pivots.setKey("none_like_this");
|
||||
|
||||
query(query);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST)
|
||||
.assertLastError().containsSummary("invalid argument was received")
|
||||
.containsSummary("Pivot parameter none_like_this does not reference");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks with pivot using Search api")
|
||||
public void searchWithPivoting() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("creator"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
response.getContext().assertThat().field("facetsFields").isNotNull();
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel pivots = new RestRequestPivotModel();
|
||||
pivots.setKey("creator");
|
||||
pivotModelList.add(pivots);
|
||||
query.setPivots(pivotModelList);
|
||||
response = query(query);
|
||||
|
||||
//Pivot key has matched facet field so there is no longer a facet fields response
|
||||
assertPivotResponse(response, "creator", null);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks nested pivot using Search api")
|
||||
public void searchWithNestedPivoting() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
RestRequestFacetFieldModel restRequestFacetFieldModel = new RestRequestFacetFieldModel("SITE");
|
||||
restRequestFacetFieldModel.setLabel("site");
|
||||
list.add(restRequestFacetFieldModel);
|
||||
list.add(new RestRequestFacetFieldModel("creator"));
|
||||
list.add(new RestRequestFacetFieldModel("modifier"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel sitepivots = new RestRequestPivotModel();
|
||||
sitepivots.setKey("site");
|
||||
RestRequestPivotModel creatorpivot = new RestRequestPivotModel();
|
||||
creatorpivot.setKey("creator");
|
||||
RestRequestPivotModel modifierpivot = new RestRequestPivotModel();
|
||||
modifierpivot.setKey("modifier");
|
||||
sitepivots.setPivots(Arrays.asList(creatorpivot, modifierpivot));
|
||||
pivotModelList.add(sitepivots);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST)
|
||||
.assertLastError().containsSummary("invalid argument was received")
|
||||
.containsSummary("Currently only 1 nested pivot is supported, you have 2");
|
||||
|
||||
pivotModelList = new ArrayList<>();
|
||||
sitepivots = new RestRequestPivotModel();
|
||||
sitepivots.setKey("site");
|
||||
sitepivots.setPivots(Arrays.asList(modifierpivot));
|
||||
pivotModelList.add(sitepivots);
|
||||
pivotModelList.add(creatorpivot);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
response = query(query);
|
||||
assertPivotResponse(response, "SITE", "site");
|
||||
|
||||
RestGenericFacetResponseModel siteResponse = response.getContext().getFacets().get(0);
|
||||
RestGenericBucketModel bucket = siteResponse.getBuckets().get(0);
|
||||
RestGenericFacetResponseModel modifiedResponse = bucket.getFacets().get(0);
|
||||
modifiedResponse.assertThat().field("type").is("pivot");
|
||||
modifiedResponse.assertThat().field("label").is("modifier");
|
||||
|
||||
RestGenericFacetResponseModel creatorResponse = response.getContext().getFacets().get(1);
|
||||
creatorResponse.assertThat().field("type").is("pivot");
|
||||
creatorResponse.assertThat().field("label").is("creator");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks range pivots using Search api")
|
||||
public void searchWithRangePivoting() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
String endDate = LocalDateTime.now()
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")); //the car document is created at runtime, so to include it in range facets end date must be now
|
||||
|
||||
Pagination pagination = new Pagination();
|
||||
pagination.setMaxItems(2);
|
||||
query.setPaging(pagination);
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("creator"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
|
||||
RestRequestRangesModel facetRangeModel = new RestRequestRangesModel();
|
||||
facetRangeModel.setField("created");
|
||||
facetRangeModel.setStart("2015-09-29T10:45:15.729Z");
|
||||
facetRangeModel.setEnd(endDate);
|
||||
facetRangeModel.setGap("+280DAY");
|
||||
facetRangeModel.setLabel("aRange");
|
||||
List<RestRequestRangesModel> ranges = new ArrayList<RestRequestRangesModel>();
|
||||
ranges.add(facetRangeModel);
|
||||
query.setRanges(ranges);
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel creatorpivot = new RestRequestPivotModel();
|
||||
creatorpivot.setKey("creator");
|
||||
RestRequestPivotModel rangepivot = new RestRequestPivotModel();
|
||||
rangepivot.setKey("aRange");
|
||||
creatorpivot.setPivots(Arrays.asList(rangepivot));
|
||||
pivotModelList.add(creatorpivot);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(1);
|
||||
facetResponseModel.assertThat().field("type").is("pivot");
|
||||
facetResponseModel.assertThat().field("label").is("creator");
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
RestGenericFacetResponseModel rangeResponse = bucket.getFacets().get(0);
|
||||
rangeResponse.assertThat().field("type").is("range");
|
||||
}
|
||||
|
||||
private void assertPivotResponse(SearchResponse response, String field, String alabel) throws Exception
|
||||
{
|
||||
String label = alabel!=null?alabel:field;
|
||||
response.getContext().assertThat().field("facetsFields").isNull();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
facetResponseModel.assertThat().field("type").is("pivot");
|
||||
facetResponseModel.assertThat().field("label").is(label);
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
bucket.assertThat().field("label").isNotEmpty();
|
||||
bucket.assertThat().field("filterQuery").is(field+":\""+bucket.getLabel()+"\"");
|
||||
Assert.assertEquals("count", bucket.getMetrics().get(0).getType());
|
||||
Assert.assertTrue(bucket.getMetrics().get(0).getValue().toString().contains("{count="));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks with pivot using Search api and a label as a key")
|
||||
public void searchWithPivotingUsingLabel() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
RestRequestFacetFieldModel creatorFacetFieldModel = new RestRequestFacetFieldModel("creator");
|
||||
creatorFacetFieldModel.setLabel("create");
|
||||
list.add(creatorFacetFieldModel);
|
||||
RestRequestFacetFieldModel restRequestFacetFieldModel = new RestRequestFacetFieldModel("modifier");
|
||||
restRequestFacetFieldModel.setLabel("aLabel");
|
||||
list.add(restRequestFacetFieldModel);
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
RestRequestPivotModel pivots = new RestRequestPivotModel();
|
||||
pivots.setKey("create");
|
||||
RestRequestPivotModel pivotmod = new RestRequestPivotModel();
|
||||
pivotmod.setKey("aLabel");
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
pivotModelList.add(pivots);
|
||||
pivotModelList.add(pivotmod);
|
||||
query.setPivots(pivotModelList);
|
||||
SearchResponse response = query(query);
|
||||
assertPivotResponse(response, "creator", "create");
|
||||
|
||||
//Now check the nesting
|
||||
RestGenericFacetResponseModel labelResponseModel = response.getContext().getFacets().get(1);
|
||||
labelResponseModel.assertThat().field("type").is("pivot");
|
||||
labelResponseModel.assertThat().field("label").isNotEmpty();
|
||||
labelResponseModel.assertThat().field("label").is("aLabel");
|
||||
RestGenericBucketModel bucket = labelResponseModel.getBuckets().get(0);
|
||||
bucket.assertThat().field("filterQuery").is("modifier:\""+bucket.getLabel()+"\"");
|
||||
Assert.assertEquals("count", bucket.getMetrics().get(0).getType());
|
||||
Assert.assertTrue(bucket.getMetrics().get(0).getValue().toString().contains("{count="));
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.search.FacetFieldBucket;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.RestResultBucketsModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests the search functionality using an ancestor path.
|
||||
* Using the category as an example, it is a node that is located
|
||||
* in root/rootCategory/classifiable. We now provide the ability to search by path
|
||||
* so that we can return all the child elements of our target path.
|
||||
* A search on root/rootCategory/classifiable should return Regions, Languages
|
||||
* as they are the child elements of the given path.
|
||||
*
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class SearchAPATHTest extends AbstractSearchTest
|
||||
{
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
/**
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "name:*"
|
||||
* },
|
||||
* "facetFields": {
|
||||
* "facets": [
|
||||
* {"field": "APATH", "prefix": "0" }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* Expected result
|
||||
* entries[],
|
||||
* "pagination": {
|
||||
* "maxItems": 100,
|
||||
* "hasMoreItems": true,
|
||||
* "totalItems": 914,
|
||||
* "count": 100,
|
||||
* "skipCount": 0
|
||||
* },
|
||||
* "context": {
|
||||
* "facetsFields": [{
|
||||
* "buckets": [
|
||||
* {
|
||||
* "count": 913,
|
||||
* "label": "0/5c09534f-3ca2-4272-bc25-064a7c1762b4"
|
||||
* },
|
||||
* {
|
||||
* "count": 2,
|
||||
* "label": "0/"
|
||||
* }
|
||||
* ],
|
||||
* "label": "APATH"
|
||||
* }],
|
||||
* "consistency": {"lastTxId": 89}
|
||||
* }
|
||||
*}}
|
||||
*
|
||||
*/
|
||||
public void searchLevel0() throws Exception
|
||||
{
|
||||
SearchRequest searchQuery = searchRequestWithAPATHFacet("name:*", "0");
|
||||
SearchResponse response = query(searchQuery);
|
||||
|
||||
List<FacetFieldBucket> buckets = getBuckets(response);
|
||||
Assert.assertEquals(2, buckets.size());
|
||||
|
||||
buckets.forEach(bucket -> bucket.assertThat().field("label").contains("0/"));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
public void searchLevel0andIncludeSubLevel1() throws Exception
|
||||
{
|
||||
SearchRequest searchQuery = searchRequestWithAPATHFacet("name:*", "1/");
|
||||
SearchResponse response = query(searchQuery);
|
||||
|
||||
List<FacetFieldBucket> buckets = getBuckets(response);
|
||||
Assert.assertEquals(4, buckets.size());
|
||||
|
||||
getFirstBucket(response).assertThat().field("label").contains("1/");
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_1})
|
||||
public void searchLevel2() throws Exception
|
||||
{
|
||||
String queryString = "name:cars";
|
||||
|
||||
SearchRequest l1Request = searchRequestWithAPATHFacet(queryString, "1/");
|
||||
SearchResponse l1Response = query(l1Request);
|
||||
|
||||
String l2Prefix = getFirstBucket(l1Response).getLabel().replaceFirst("^1/", "2/");
|
||||
|
||||
SearchRequest l2Request = searchRequestWithAPATHFacet(queryString, l2Prefix);
|
||||
SearchResponse l2Response = query(l2Request);
|
||||
|
||||
FacetFieldBucket bucket = getFirstBucket(l2Response);
|
||||
bucket.assertThat().field("label").contains(l2Prefix);
|
||||
|
||||
String l3Prefix = bucket.getLabel().replaceFirst("^2/", "3/");
|
||||
|
||||
SearchRequest l3Request = searchRequestWithAPATHFacet(queryString, l3Prefix);
|
||||
SearchResponse l3response = query(l3Request);
|
||||
|
||||
List<FacetFieldBucket> buckets = getBuckets(l3response);
|
||||
Assert.assertEquals(1, buckets.size());
|
||||
|
||||
getFirstBucket(l3response).assertThat().field("label").contains(l3Prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SearchRequest} for this test case.
|
||||
*
|
||||
* @param queryString the query string.
|
||||
* @param facetPrefix the facet prefix.
|
||||
* @return a new {@link SearchRequest} for this test case.
|
||||
*/
|
||||
private SearchRequest searchRequestWithAPATHFacet(String queryString, String facetPrefix)
|
||||
{
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
|
||||
RestRequestQueryModel query = new RestRequestQueryModel();
|
||||
query.setQuery(queryString);
|
||||
searchRequest.setQuery(query);
|
||||
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
facetFields.setFacets(Collections.singletonList(new RestRequestFacetFieldModel("APATH", facetPrefix)));
|
||||
searchRequest.setFacetFields(facetFields);
|
||||
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the first bucket from the given response.
|
||||
*
|
||||
* @param response the results of a query execution.
|
||||
* @return the first bucket included in the search response.
|
||||
*/
|
||||
private FacetFieldBucket getFirstBucket(SearchResponse response)
|
||||
{
|
||||
return getBuckets(response).iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the buckets from the given response.
|
||||
* The method also makes sure the buckets list is not empty in the input response.
|
||||
*
|
||||
* @param response the results of a query execution.
|
||||
* @return the getBuckets included in the search response.
|
||||
*/
|
||||
private List<FacetFieldBucket> getBuckets(SearchResponse response)
|
||||
{
|
||||
List<RestResultBucketsModel> facetFields = response.getContext().getFacetsFields();
|
||||
Assert.assertNotNull(facetFields);
|
||||
Assert.assertFalse(facetFields.isEmpty());
|
||||
|
||||
List<FacetFieldBucket> buckets = facetFields.iterator().next().getBuckets();
|
||||
Assert.assertNotNull(buckets);
|
||||
Assert.assertFalse(buckets.isEmpty());
|
||||
|
||||
return buckets;
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.search.ResponseHighLightModel;
|
||||
import org.alfresco.rest.search.RestRequestFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestHighlightModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.report.Bug;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Search high lighting test.
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class SearchHighLightTest extends AbstractSearchTest
|
||||
{
|
||||
@Test(groups={TestGroup.SEARCH,TestGroup.REST_API})
|
||||
@Bug(id = "TAS-3220")
|
||||
public void searchWithHighLight() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file2.getContent(), true);
|
||||
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:content:cars");
|
||||
queryReq.setUserQuery("cars");
|
||||
|
||||
RestRequestHighlightModel highlight = new RestRequestHighlightModel();
|
||||
highlight.setPrefix("¿");
|
||||
highlight.setPostfix("?");
|
||||
highlight.setMergeContiguous(true);
|
||||
List<RestRequestFieldsModel> fields = new ArrayList<RestRequestFieldsModel>();
|
||||
fields.add(new RestRequestFieldsModel("cm:content"));
|
||||
highlight.setFields(fields);
|
||||
SearchResponse nodes = query(queryReq, highlight);
|
||||
nodes.assertThat().entriesListIsNotEmpty();
|
||||
ResponseHighLightModel hl = nodes.getEntryByIndex(0).getSearch().getHighlight().get(0);
|
||||
hl.assertThat().field("snippets").contains( "The landrover discovery is not a sports ¿car?");
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH,TestGroup.REST_API})
|
||||
public void searchNonIndexedData() throws Exception
|
||||
{
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:title");
|
||||
queryReq.setUserQuery("zoro");
|
||||
|
||||
RestRequestHighlightModel highlight = new RestRequestHighlightModel();
|
||||
highlight.setPrefix("¿");
|
||||
highlight.setPostfix("?");
|
||||
highlight.setMergeContiguous(true);
|
||||
List<RestRequestFieldsModel> fields = new ArrayList<RestRequestFieldsModel>();
|
||||
fields.add(new RestRequestFieldsModel("cm:title"));
|
||||
highlight.setFields(fields);
|
||||
SearchResponse nodes = query(queryReq, highlight);
|
||||
nodes.assertThat().entriesListDoesNotContain("highlight");
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import org.alfresco.rest.model.RestRequestSpellcheckModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.FileModel;
|
||||
import org.alfresco.utility.model.FileType;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Search end point Public API test with spell checking enabled.
|
||||
* @author Michael Suzuki
|
||||
* @author Meenal Bhave
|
||||
*/
|
||||
public class SearchSpellCheckTest extends AbstractSearchTest
|
||||
{
|
||||
|
||||
/**
|
||||
* Perform the below query
|
||||
* {
|
||||
* "spellcheck" : { },
|
||||
* "query" : {
|
||||
* "userQuery" : "alfrezco",
|
||||
* "query" : "cm:title:alfrezco"
|
||||
* }
|
||||
* to yeild the following result.
|
||||
* {
|
||||
* "list": {
|
||||
* "pagination": {
|
||||
* "count": 22,
|
||||
* "hasMoreItems": false,
|
||||
* "totalItems": 22,
|
||||
* "skipCount": 0,
|
||||
* "maxItems": 100
|
||||
* },
|
||||
* "context": {
|
||||
* "spellCheck": {
|
||||
* "type": "searchInsteadFor",
|
||||
* "suggestions": [
|
||||
* "alfresco"
|
||||
* ]
|
||||
* }
|
||||
* },
|
||||
* "entries": [...]
|
||||
* }
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n}, priority=1)
|
||||
public void testSearchMissSpelled() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
|
||||
// Name
|
||||
SearchRequest searchReq = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:name:alfrezco");
|
||||
queryReq.setUserQuery("alfrezco");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
assertResponse(query(searchReq));
|
||||
|
||||
// Title
|
||||
queryReq.setQuery("cm:title:alfrezco");
|
||||
queryReq.setUserQuery("alfrezco");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
assertResponse(query(searchReq));
|
||||
|
||||
// Description
|
||||
queryReq.setQuery("cm:description:alfrezco");
|
||||
queryReq.setUserQuery("alfrezco");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
assertResponse(query(searchReq));
|
||||
|
||||
// Content
|
||||
queryReq.setQuery("cm:content:alfrezco");
|
||||
queryReq.setUserQuery("alfrezco");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
assertResponse(query(searchReq));
|
||||
}
|
||||
|
||||
private void assertResponse(SearchResponse nodes) throws Exception
|
||||
{
|
||||
nodes.assertThat().entriesListIsNotEmpty();
|
||||
nodes.getContext().assertThat().field("spellCheck").isNotEmpty();
|
||||
nodes.getContext().getSpellCheck().assertThat().field("suggestions").contains("alfresco");
|
||||
nodes.getContext().getSpellCheck().assertThat().field("type").is("searchInsteadFor");
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform alternative way by setting the value in spellcheck object.
|
||||
*
|
||||
* {
|
||||
* "query": {
|
||||
* "query": "cm:title:alfrezco",
|
||||
* "language": "afts"
|
||||
* },
|
||||
* "spellcheck": {"query": "alfrezco"}
|
||||
* }
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n}, priority=2)
|
||||
public void testSearchMissSpelledVersion2() throws Exception
|
||||
{
|
||||
SearchRequest searchReq = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:title:alfrezco");
|
||||
searchReq.setQuery(queryReq);
|
||||
|
||||
RestRequestSpellcheckModel spellCheck = new RestRequestSpellcheckModel();
|
||||
spellCheck.setQuery("alfrezco");
|
||||
searchReq.setSpellcheck(spellCheck);
|
||||
assertResponse(query(searchReq));
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n}, priority=3)
|
||||
public void testSearchWithSpellcheckerAndCorrectSpelling() throws Exception
|
||||
{
|
||||
SearchRequest searchReq = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:title:alfresco");
|
||||
queryReq.setUserQuery("alfresco");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
SearchResponse res = query(searchReq);
|
||||
Assert.assertNull(res.getContext().getSpellCheck());
|
||||
res.assertThat().entriesListIsNotEmpty();
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n}, priority=4)
|
||||
public void testSpellCheckType() throws Exception
|
||||
{
|
||||
// Create a file with mis-spelt name, expect spellcheck type = didYouMean
|
||||
FileModel file = new FileModel(unique_searchString + "-1.txt", "uniquee" + "uniquee", "uniquee", FileType.TEXT_PLAIN, "Unique text file for search ");
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(file);
|
||||
|
||||
waitForIndexing(file.getName(), true);
|
||||
|
||||
// Search
|
||||
SearchRequest searchReq = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("cm:title:uniquee");
|
||||
queryReq.setUserQuery("uniquee");
|
||||
searchReq.setQuery(queryReq);
|
||||
searchReq.setSpellcheck(new RestRequestSpellcheckModel());
|
||||
SearchResponse nodes = query(searchReq);
|
||||
|
||||
nodes.assertThat().entriesListIsNotEmpty();
|
||||
nodes.getContext().assertThat().field("spellCheck").isNotEmpty();
|
||||
nodes.getContext().getSpellCheck().assertThat().field("suggestions").contains("unique");
|
||||
nodes.getContext().getSpellCheck().assertThat().field("type").is("didYouMean");
|
||||
}
|
||||
}
|
||||
+314
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.reverse;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.testng.AssertJUnit.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.rest.model.body.RestNodeLockBodyModel;
|
||||
import org.alfresco.rest.search.RestRequestFilterQueryModel;
|
||||
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.model.FileModel;
|
||||
import org.alfresco.utility.model.FileType;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Search end point Public API test.
|
||||
* @author Michael Suzuki
|
||||
*
|
||||
*/
|
||||
public class SearchTest extends AbstractSearchTest
|
||||
{
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file4.getContent(), true);
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API})
|
||||
public void searchOnIndexedData() throws Exception
|
||||
{
|
||||
SearchResponse nodes = query("cm:content:" + unique_searchString);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
nodes.assertThat().entriesListIsNotEmpty();
|
||||
|
||||
SearchNodeModel entity = nodes.getEntryByIndex(0);
|
||||
entity.assertThat().field("search").contains("score");
|
||||
entity.getSearch().assertThat().field("score").isNotEmpty();
|
||||
Assert.assertEquals(entity.getName(),"pangram.txt");
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH,TestGroup.REST_API})
|
||||
public void searchNonIndexedData() throws Exception
|
||||
{
|
||||
SearchResponse nodes = query("yeti");
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
nodes.assertThat().entriesListIsEmpty();
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks its possible to include the original request in the response")
|
||||
public void searchWithRequest() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("fox");
|
||||
query.setQuery(queryReq);
|
||||
query.setIncludeRequest(true);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
response.getContext().assertThat().field("request").isNotEmpty();
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Tests a search request containing a sort clause.")
|
||||
public void searchWithOneSortClause() throws Exception
|
||||
{
|
||||
// Tests the ascending order first
|
||||
List<String> expectedOrder = asList("alfresco.txt", "cars.txt", "pangram.txt");
|
||||
|
||||
SearchRequest searchRequest = createQuery("cm_name:alfresco\\.txt cm_name:cars\\.txt cm_name:pangram\\.txt");
|
||||
searchRequest.addSortClause("FIELD", "name", true);
|
||||
|
||||
RestRequestFilterQueryModel filters = new RestRequestFilterQueryModel();
|
||||
filters.setQuery("SITE:'" + siteModel.getId() + "'");
|
||||
searchRequest.setFilterQueries(filters);
|
||||
|
||||
SearchResponse responseWithAscendingOrder = query(searchRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
assertEquals(
|
||||
expectedOrder,
|
||||
responseWithAscendingOrder.getEntries().stream()
|
||||
.map(SearchNodeModel::getModel)
|
||||
.map(SearchNodeModel::getName)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// Reverts the expected order...
|
||||
reverse(expectedOrder);
|
||||
|
||||
// ...and test the descending order
|
||||
searchRequest.getSort().clear();
|
||||
searchRequest.addSortClause("FIELD", "name", false);
|
||||
|
||||
SearchResponse responseWithDescendingOrder = query(searchRequest);
|
||||
assertEquals(
|
||||
expectedOrder,
|
||||
responseWithDescendingOrder.getEntries().stream()
|
||||
.map(SearchNodeModel::getModel)
|
||||
.map(SearchNodeModel::getName)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the query execution with two sort clauses.
|
||||
* The first clause has always the same value for all matches so the test makes sure the request is correctly
|
||||
* processed and the returned order is determined by the second clause.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Tests a search request containing a sort clause.")
|
||||
public void searchWithTwoSortClauses() throws Exception
|
||||
{
|
||||
// Tests the ascending order first
|
||||
List<String> expectedOrder = asList("alfresco.txt", "cars.txt", "pangram.txt");
|
||||
|
||||
SearchRequest searchRequest = createQuery("cm_name:alfresco\\.txt cm_name:cars\\.txt cm_name:pangram\\.txt");
|
||||
searchRequest.addSortClause("FIELD", "name", true);
|
||||
searchRequest.addSortClause("FIELD", "createdByUser.id", true);
|
||||
|
||||
RestRequestFilterQueryModel filters = new RestRequestFilterQueryModel();
|
||||
filters.setQuery("SITE:'" + siteModel.getId() + "'");
|
||||
searchRequest.setFilterQueries(filters);
|
||||
|
||||
SearchResponse responseWithAscendingOrder = query(searchRequest);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
assertEquals(
|
||||
expectedOrder,
|
||||
responseWithAscendingOrder.getEntries().stream()
|
||||
.map(SearchNodeModel::getModel)
|
||||
.map(SearchNodeModel::getName)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// Reverts the expected order...
|
||||
reverse(expectedOrder);
|
||||
|
||||
// ...and test the descending order
|
||||
searchRequest.getSort().clear();
|
||||
searchRequest.addSortClause("FIELD", "name", false);
|
||||
searchRequest.addSortClause("FIELD", "createdByUser.id", true);
|
||||
|
||||
SearchResponse responseWithDescendingOrder = query(searchRequest);
|
||||
assertEquals(
|
||||
expectedOrder,
|
||||
responseWithDescendingOrder.getEntries().stream()
|
||||
.map(SearchNodeModel::getModel)
|
||||
.map(SearchNodeModel::getName)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ACS_61n }) @TestRail(section = {
|
||||
TestGroup.REST_API, TestGroup.SEARCH,
|
||||
TestGroup.ACS_61n }, executionType = ExecutionType.REGRESSION, description = "Checks the \"include\" request parameter support the 'permissions' option") public void searchQuery_includePermissions_shouldReturnNodeWithPermissionsInformation()
|
||||
throws Exception
|
||||
{
|
||||
String query = "fox";
|
||||
String include = "permissions";
|
||||
|
||||
SearchRequest retrievalQueryIncludingPermissionsInformation = createQuery(query);
|
||||
retrievalQueryIncludingPermissionsInformation.setInclude(singletonList(include));
|
||||
|
||||
query(retrievalQueryIncludingPermissionsInformation);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.entries[0].entry.permissions", notNullValue());
|
||||
|
||||
SearchRequest retrievalQueryNotIncludingLockInformation = createQuery(query);
|
||||
|
||||
query(retrievalQueryNotIncludingLockInformation);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.entries[0].entry.permissions", nullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ACS_61n })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ACS_61n }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks the \"include\" request parameter support the 'isLocked' option")
|
||||
public void searchQuery_includeIsLocked_shouldReturnNodeWithLockInformation() throws Exception {
|
||||
String query = "fox";
|
||||
String include = "isLocked";
|
||||
|
||||
SearchRequest retrievalQueryIncludingLockInformation = createQuery(query);
|
||||
retrievalQueryIncludingLockInformation.setInclude(singletonList(include));
|
||||
|
||||
query(retrievalQueryIncludingLockInformation);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.entries[0].entry.isLocked", equalTo(false));
|
||||
|
||||
RestNodeLockBodyModel lockBodyModel = new RestNodeLockBodyModel();
|
||||
lockBodyModel.setLifetime("EPHEMERAL");
|
||||
lockBodyModel.setTimeToExpire(20);
|
||||
lockBodyModel.setType("FULL");
|
||||
restClient.authenticateUser(userModel).withCoreAPI().usingNode(file).usingParams("include=isLocked").lockNode(lockBodyModel);
|
||||
|
||||
query(retrievalQueryIncludingLockInformation);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.entries[0].entry.isLocked", equalTo(true));
|
||||
|
||||
SearchRequest retrievalQueryNotIncludingLockInformation = createQuery(query);
|
||||
|
||||
query(retrievalQueryNotIncludingLockInformation);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
restClient.onResponse().assertThat().body("list.entries[0].entry.isLocked", nullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ACS_61n })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ACS_61n }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks the \"include\" request parameter does not support the 'notValid' option")
|
||||
public void searchQuery_includeInvalid_shouldReturnBadResponse() throws Exception
|
||||
{
|
||||
String query = "fox";
|
||||
String notValidInclude = "notValid";
|
||||
SearchRequest permissionsRetrieval = createQuery(query);
|
||||
permissionsRetrieval.setInclude(singletonList(notValidInclude));
|
||||
|
||||
query(permissionsRetrieval);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
restClient.onResponse()
|
||||
.assertThat()
|
||||
.body("error.briefSummary", containsString("An invalid argument was received "+notValidInclude));
|
||||
}
|
||||
|
||||
// Test that when fields parameter is set, only restricted fields appear in the response
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
public void searchWithFields() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("alfresco");
|
||||
query.setQuery(queryReq);
|
||||
|
||||
// Restrict to fields: parentId
|
||||
List<String> fields = new ArrayList<>();
|
||||
fields.add("parentId");
|
||||
query.setFields(fields);
|
||||
|
||||
query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
// Only Field parentId is included in the response
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0].parentId", Matchers.notNullValue());
|
||||
// Usual Fields such as 'name, id' aren't included in the response
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0].name", Matchers.nullValue());
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0].id", Matchers.nullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API })
|
||||
public void searchSpecialCharacters() throws Exception
|
||||
{
|
||||
// Create a file with Special Characters
|
||||
String specialCharfileName = "è¥äæ§ç§-åæ.pdf";
|
||||
FileModel file = new FileModel(specialCharfileName, "è¥äæ§ç§-忬¯¸" + "è¥äæ§ç§-忬¯¸", "è¥äæ§ç§-忬¯¸", FileType.TEXT_PLAIN,
|
||||
"Text file with Special Characters: " + specialCharfileName);
|
||||
dataContent.usingUser(userModel).usingSite(siteModel).createContent(file);
|
||||
|
||||
waitForIndexing(file.getName(), true);
|
||||
|
||||
// Search
|
||||
SearchRequest searchReq = createQuery("name:'" + specialCharfileName + "'");
|
||||
SearchResponse nodes = query(searchReq);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
nodes.assertThat().entriesListIsNotEmpty();
|
||||
|
||||
restClient.onResponse().assertThat().body("list.entries.entry[0].name", Matchers.equalToIgnoringCase(specialCharfileName));
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import org.alfresco.rest.exception.EmptyRestModelCollectionException;
|
||||
import org.alfresco.rest.search.RestInstanceModel;
|
||||
import org.alfresco.rest.search.RestShardInfoModel;
|
||||
import org.alfresco.rest.search.RestShardInfoModelCollection;
|
||||
import org.alfresco.rest.search.RestShardModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Shard info end point REST API test.
|
||||
*
|
||||
* @author Tuna Aksoy
|
||||
*/
|
||||
public class ShardInfoTest extends AbstractSearchTest
|
||||
{
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n})
|
||||
public void getShardInfoWithAdminAuthority() throws JsonProcessingException, EmptyRestModelCollectionException
|
||||
{
|
||||
RestShardInfoModelCollection info = restClient.authenticateUser(dataUser.getAdminUser()).withShardInfoAPI().getInfo();
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
info.assertThat().entriesListIsNotEmpty();
|
||||
assertEquals(info.getPagination().getTotalItems().intValue(), 2);
|
||||
|
||||
List<String> stores = Arrays.asList("workspace://SpacesStore", "archive://SpacesStore");
|
||||
List<String> baseUrls = Arrays.asList("/solr/alfresco", "/solr/archive");
|
||||
|
||||
List<RestShardInfoModel> entries = info.getEntries();
|
||||
for (RestShardInfoModel shardInfoModel : entries)
|
||||
{
|
||||
RestShardInfoModel model = shardInfoModel.getModel();
|
||||
assertEquals(model.getTemplate(), "rerank");
|
||||
assertEquals(model.getMode(), "MASTER");
|
||||
assertEquals(model.getShardMethod(), "DB_ID");
|
||||
assertTrue(model.getHasContent());
|
||||
stores.contains(model.getStores());
|
||||
List<RestShardModel> shards = model.getShards();
|
||||
assertNotNull(shards);
|
||||
RestShardModel shard = shards.iterator().next();
|
||||
assertNotNull(shard);
|
||||
List<RestInstanceModel> instances = shard.getInstances();
|
||||
assertNotNull(instances);
|
||||
RestInstanceModel instance = instances.iterator().next();
|
||||
assertNotNull(instance);
|
||||
baseUrls.contains(instance.getBaseUrl());
|
||||
// TODO: Ideally Solr Host and Port should be Parameterised
|
||||
assertEquals(instance.getHost(), "search");
|
||||
assertEquals(instance.getPort().intValue(), 8983);
|
||||
assertEquals(instance.getState(), "ACTIVE");
|
||||
assertEquals(instance.getMode(), "MASTER");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(groups={TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ACS_60n})
|
||||
public void getShardInfoWithoutAdminAuthority() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(dataUser.createRandomTestUser()).withShardInfoAPI().getInfo();
|
||||
restClient.assertStatusCodeIs(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.rest.model.RestErrorModel;
|
||||
import org.alfresco.rest.search.Pagination;
|
||||
import org.alfresco.rest.search.RestGenericBucketModel;
|
||||
import org.alfresco.rest.search.RestGenericFacetResponseModel;
|
||||
import org.alfresco.rest.search.RestGenericMetricModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldModel;
|
||||
import org.alfresco.rest.search.RestRequestFacetFieldsModel;
|
||||
import org.alfresco.rest.search.RestRequestFilterQueryModel;
|
||||
import org.alfresco.rest.search.RestRequestPivotModel;
|
||||
import org.alfresco.rest.search.RestRequestQueryModel;
|
||||
import org.alfresco.rest.search.RestRequestStatsModel;
|
||||
import org.alfresco.rest.search.SearchRequest;
|
||||
import org.alfresco.rest.search.SearchResponse;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.testrail.ExecutionType;
|
||||
import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Stats search test.
|
||||
* @author Gethin James
|
||||
*
|
||||
*/
|
||||
public class StatsSearchTest extends AbstractSearchTest
|
||||
{
|
||||
@BeforeClass(alwaysRun = true)
|
||||
public void setupEnvironment() throws Exception
|
||||
{
|
||||
waitForContentIndexing(file2.getContent(), true);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with stats using Search api")
|
||||
public void searchWithBasicStats() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
Pagination pagination = new Pagination();
|
||||
pagination.setMaxItems(2);
|
||||
List<RestRequestStatsModel> statsModels = new ArrayList<>();
|
||||
RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
|
||||
statsModels.add(statsModel1);
|
||||
query.setStats(statsModels);
|
||||
query.setPaging(pagination);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError()
|
||||
.containsSummary(String.format(RestErrorModel.MANDATORY_PARAM, "stats field"));
|
||||
|
||||
statsModel1.setField("DBID");
|
||||
response = query(query);
|
||||
//8 metrics by default for a numeric field
|
||||
Set<String> metricTypes = assertStatsFacetedResponse(response, "DBID", 8);
|
||||
assertTrue(metricTypes.containsAll(Arrays.asList("missing", "countValues", "sum","min","max", "sumOfSquares", "mean", "stddev")));
|
||||
|
||||
statsModel1.setField("creator");
|
||||
response = query(query);
|
||||
//4 metrics by default for a string field
|
||||
metricTypes = assertStatsFacetedResponse(response, "creator", 4);
|
||||
assertTrue(metricTypes.containsAll(Arrays.asList("missing", "countValues", "min","max")));
|
||||
|
||||
statsModel1.setField("modified");
|
||||
response = query(query);
|
||||
//8 metrics by default for a date field
|
||||
metricTypes = assertStatsFacetedResponse(response, "modified", 8);
|
||||
assertTrue(metricTypes.containsAll(Arrays.asList("missing", "countValues", "sum","min","max", "sumOfSquares", "mean", "stddev")));
|
||||
|
||||
statsModel1.setField("modifier");
|
||||
statsModel1.setMin(false);
|
||||
statsModel1.setMax(false);
|
||||
statsModel1.setMissing(false);
|
||||
response = query(query);
|
||||
metricTypes = assertStatsFacetedResponse(response, "modifier", 1);
|
||||
assertFalse(metricTypes.containsAll(Arrays.asList("missing", "min","max")));
|
||||
|
||||
statsModel1.setField("DBID");
|
||||
statsModel1.setMin(true);
|
||||
statsModel1.setMax(true);
|
||||
statsModel1.setCountValues(false);
|
||||
statsModel1.setMissing(false);
|
||||
statsModel1.setSum(false);
|
||||
statsModel1.setSumOfSquares(false);
|
||||
statsModel1.setMean(false);
|
||||
statsModel1.setStddev(false);
|
||||
response = query(query);
|
||||
metricTypes = assertStatsFacetedResponse(response, "DBID", 2);
|
||||
assertTrue(metricTypes.containsAll(Arrays.asList("min","max")));
|
||||
assertFalse(metricTypes.containsAll(Arrays.asList("missing", "countValues", "sum","sumOfSquares", "mean", "stddev")));
|
||||
|
||||
statsModel1.setField("modifier");
|
||||
statsModel1.setMin(false);
|
||||
statsModel1.setMax(false);
|
||||
statsModel1.setCountDistinct(true);
|
||||
statsModel1.setDistinctValues(true);
|
||||
statsModel1.setCardinality(true);
|
||||
response = query(query);
|
||||
metricTypes = assertStatsFacetedResponse(response, "modifier", 3);
|
||||
assertTrue(metricTypes.containsAll(Arrays.asList("countDistinct", "distinctValues", "cardinality")));
|
||||
|
||||
statsModel1.setField("DBID");
|
||||
statsModel1.setPercentiles(Arrays.asList(1,75,99,99.9));
|
||||
statsModel1.setCountDistinct(false);
|
||||
statsModel1.setDistinctValues(false);
|
||||
statsModel1.setCardinality(false);
|
||||
response = query(query);
|
||||
assertStatsFacetedResponse(response, "DBID", 1);
|
||||
RestGenericMetricModel percMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
|
||||
assertEquals(percMetric.getType(),"percentiles");
|
||||
Map<?, ?> percVal = (Map<?, ?>) percMetric.getValue();
|
||||
Map<?, ?> percentiles = (Map<?, ?>) percVal.get("percentiles");
|
||||
assertEquals(percentiles.size(),4);
|
||||
assertTrue(percentiles.keySet().containsAll(Arrays.asList("1.0","75.0","99.0","99.9")));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with stats labels using Search api")
|
||||
public void searchWithStatsLabel() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
Pagination pagination = new Pagination();
|
||||
pagination.setMaxItems(2);
|
||||
List<RestRequestStatsModel> statsModels = new ArrayList<>();
|
||||
RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
|
||||
statsModel1.setField("modified");
|
||||
statsModel1.setLabel("DateChanged");
|
||||
statsModels.add(statsModel1);
|
||||
query.setStats(statsModels);
|
||||
query.setPaging(pagination);
|
||||
SearchResponse response = query(query);
|
||||
assertStatsFacetedResponse(response, "DateChanged", 8);
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with stats fitlers using Search api")
|
||||
public void searchWithStatsFilters() throws Exception
|
||||
{
|
||||
SearchRequest query = new SearchRequest();
|
||||
RestRequestQueryModel queryReq = new RestRequestQueryModel();
|
||||
queryReq.setQuery("content.mimetype:text/plain");
|
||||
query.setQuery(queryReq);
|
||||
List<RestRequestStatsModel> statsModels = new ArrayList<>();
|
||||
RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
|
||||
statsModel1.setField("creator");
|
||||
statsModel1.setMin(false);
|
||||
statsModel1.setMax(false);
|
||||
statsModel1.setMissing(false);
|
||||
statsModels.add(statsModel1);
|
||||
query.setFilterQueries(new RestRequestFilterQueryModel("cars", Arrays.asList("justCars")));
|
||||
query.setStats(statsModels);
|
||||
SearchResponse response = query(query);
|
||||
assertStatsFacetedResponse(response, "creator", 1);
|
||||
RestGenericMetricModel countMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
|
||||
Integer count = response.getPagination().getTotalItems();
|
||||
Map<?, ?> metricCount = (Map<?, ?>) countMetric.getValue();
|
||||
assertEquals(count, metricCount.get("countValues"));
|
||||
|
||||
statsModel1.setExcludeFilters(Arrays.asList("justCars"));
|
||||
response = query(query);
|
||||
assertStatsFacetedResponse(response, "creator", 1);
|
||||
countMetric = response.getContext().getFacets().get(0).getBuckets().get(0).getMetrics().get(0);
|
||||
count = response.getEntries().size();
|
||||
metricCount = (Map<?, ?>) countMetric.getValue();
|
||||
assertTrue((Integer)metricCount.get("countValues") > count, "With the exclude filter there will be more documents than returned");
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with stats with Pivot using Search api")
|
||||
public void searchWithStatsAndMutlilevelPivot() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
Pagination pagination = new Pagination();
|
||||
pagination.setMaxItems(1);
|
||||
query.setPaging(pagination);
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
RestRequestFacetFieldModel b0 = new RestRequestFacetFieldModel("SITE");
|
||||
b0.setLabel("b0");
|
||||
list.add(b0);
|
||||
list.add(new RestRequestFacetFieldModel("created"));
|
||||
RestRequestFacetFieldModel b2 = new RestRequestFacetFieldModel("modifier");
|
||||
b2.setLabel("b2");
|
||||
list.add(b2);
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel pivots = new RestRequestPivotModel();
|
||||
pivots.setKey("b0");
|
||||
RestRequestPivotModel pivotn = new RestRequestPivotModel();
|
||||
pivotn.setKey("created");
|
||||
RestRequestPivotModel pivot2 = new RestRequestPivotModel();
|
||||
pivot2.setKey("aNumber");
|
||||
|
||||
pivotn.setPivots(Arrays.asList(pivot2));
|
||||
pivots.setPivots(Arrays.asList(pivotn));
|
||||
pivotModelList.add(pivots);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
List<RestRequestStatsModel> statsModels = new ArrayList<>();
|
||||
RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
|
||||
statsModels.add(statsModel1);
|
||||
query.setStats(statsModels);
|
||||
statsModel1.setField("DBID");
|
||||
statsModel1.setLabel("aNumber");
|
||||
|
||||
SearchResponse response = query(query);
|
||||
response.getContext().assertThat().field("facetsFields").isNotNull();
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
assertEquals(response.getContext().getFacetsFields().size(), 1, "There should be 1 facet field for modifier");
|
||||
assertEquals(response.getContext().getFacets().size(), 2, "There should be 1 pivot facet with stats on the end and a high level stats facet");
|
||||
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
facetResponseModel.assertThat().field("type").is("pivot");
|
||||
facetResponseModel.assertThat().field("label").is("b0");
|
||||
|
||||
//pivot created
|
||||
RestGenericFacetResponseModel created = facetResponseModel.getBuckets().get(0).getFacets().get(0);
|
||||
created.assertThat().field("type").is("pivot");
|
||||
created.assertThat().field("label").is("created");
|
||||
//Another nested stats
|
||||
assertEquals(created.getBuckets().get(0).getMetrics().size(), 9, "Metrics are on the end of a pivot bucket");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 })
|
||||
@TestRail(section = {TestGroup.REST_API, TestGroup.SEARCH, TestGroup.ASS_1 },
|
||||
executionType = ExecutionType.REGRESSION,
|
||||
description = "Checks errors with stats with Pivot using Search api")
|
||||
public void searchWithStatsAndPivot() throws Exception
|
||||
{
|
||||
SearchRequest query = carsQuery();
|
||||
|
||||
Pagination pagination = new Pagination();
|
||||
pagination.setMaxItems(2);
|
||||
query.setPaging(pagination);
|
||||
RestRequestFacetFieldsModel facetFields = new RestRequestFacetFieldsModel();
|
||||
List<RestRequestFacetFieldModel> list = new ArrayList<>();
|
||||
list.add(new RestRequestFacetFieldModel("creator"));
|
||||
facetFields.setFacets(list);
|
||||
query.setFacetFields(facetFields);
|
||||
query.setIncludeRequest(false);
|
||||
|
||||
SearchResponse response = query(query);
|
||||
response.getContext().assertThat().field("facetsFields").isNotNull();
|
||||
|
||||
List<RestRequestPivotModel> pivotModelList = new ArrayList<>();
|
||||
RestRequestPivotModel pivots = new RestRequestPivotModel();
|
||||
pivots.setKey("creator");
|
||||
RestRequestPivotModel pivotn = new RestRequestPivotModel();
|
||||
pivotn.setKey("numericId");
|
||||
|
||||
pivots.setPivots(Arrays.asList(pivotn));
|
||||
pivotModelList.add(pivots);
|
||||
query.setPivots(pivotModelList);
|
||||
|
||||
List<RestRequestStatsModel> statsModels = new ArrayList<>();
|
||||
RestRequestStatsModel statsModel1 = new RestRequestStatsModel();
|
||||
statsModels.add(statsModel1);
|
||||
query.setStats(statsModels);
|
||||
statsModel1.setField("DBID");
|
||||
statsModel1.setLabel("numericId");
|
||||
|
||||
response = query(query);
|
||||
|
||||
response.getContext().assertThat().field("facets").isNotEmpty();
|
||||
assertEquals(response.getContext().getFacets().size(), 2, "There should be 1 pivot facet with stats on the end and a high level stats facet");
|
||||
RestGenericFacetResponseModel facetResponseModel = response.getContext().getFacets().get(0);
|
||||
facetResponseModel.assertThat().field("type").is("pivot");
|
||||
facetResponseModel.assertThat().field("label").is("creator");
|
||||
assertEquals(facetResponseModel.getBuckets().get(0).getMetrics().size(), 9, "Metrics are on the end of a pivot bucket");
|
||||
RestGenericFacetResponseModel statsFacet = response.getContext().getFacets().get(1);
|
||||
statsFacet.assertThat().field("type").is("stats");
|
||||
statsFacet.assertThat().field("label").is("numericId");
|
||||
|
||||
}
|
||||
|
||||
private Set<String> assertStatsFacetedResponse(SearchResponse response, String label, int metricsCount) throws Exception
|
||||
{
|
||||
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);
|
||||
RestGenericBucketModel bucket = facetResponseModel.getBuckets().get(0);
|
||||
List<RestGenericMetricModel> metrics = bucket.getMetrics();
|
||||
assertEquals(metrics.size(),metricsCount);
|
||||
return metrics.stream().map(m -> m.getType()).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.alfresco.service.search.e2e.searchservices.solr;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import javax.json.JsonArrayBuilder;
|
||||
|
||||
import org.alfresco.rest.core.JsonBodyGenerator;
|
||||
import org.alfresco.rest.model.RestTextResponse;
|
||||
import org.alfresco.service.search.e2e.searchservices.AbstractSearchTest;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for solr/alfresco Solr API.
|
||||
*
|
||||
* @author Meenal Bhave
|
||||
*/
|
||||
public class SearchSolrAPITest extends AbstractSearchTest
|
||||
{
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_112 }, priority = 01)
|
||||
public void testGetSolrConfig() throws Exception
|
||||
{
|
||||
RestTextResponse response = restClient.authenticateUser(adminUserModel).withSolrAPI().getConfig();
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().content(Matchers.containsString("config"));
|
||||
Assert.assertNotNull(response.getJsonValueByPath("config.requestHandler"));
|
||||
Assert.assertNotNull(response.getJsonObjectByPath("config.requestHandler"));
|
||||
|
||||
// TODO: Following asserts fail with error:
|
||||
/*
|
||||
* java.lang.IllegalStateException: Expected response body to be verified as JSON, HTML or XML but content-type 'text/plain' is not supported out of the box.
|
||||
* Try registering a custom parser using: RestAssured.registerParser("text/plain", <parser type>);
|
||||
*/
|
||||
|
||||
// response.assertThat().body("config.requestHandler", Matchers.notNullValue());
|
||||
// restClient.onResponse().assertThat().body("config.requestHandler",Matchers.notNullValue());
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_112 }, priority = 02)
|
||||
public void testEditSolrConfig() throws Exception
|
||||
{
|
||||
String expectedError = "solrconfig editing is not enabled due to disable.configEdit";
|
||||
|
||||
JsonArrayBuilder argsArray = JsonBodyGenerator.defineJSONArray();
|
||||
argsArray.add("ANYARGS");
|
||||
|
||||
String postBody = JsonBodyGenerator.defineJSON()
|
||||
.add("add-listener", JsonBodyGenerator.defineJSON()
|
||||
.add("event", "postCommit")
|
||||
.add("name", "newlistener")
|
||||
.add("class", "solr.RunExecutableListener")
|
||||
.add("exe", "ANYCOMMAND")
|
||||
.add("dir", "/usr/bin/")
|
||||
.add("args", argsArray)).build().toString();
|
||||
|
||||
// RestTextResponse response =
|
||||
restClient.authenticateUser(adminUserModel).withSolrAPI().postConfig(postBody);
|
||||
restClient.assertStatusCodeIs(HttpStatus.FORBIDDEN);
|
||||
|
||||
restClient.onResponse().assertThat().content(Matchers.containsString(expectedError));
|
||||
|
||||
// TODO: Following asserts fail with error:
|
||||
/*
|
||||
* java.lang.IllegalStateException: Expected response body to be verified as JSON, HTML or XML but content-type 'text/plain' is not supported out of the box.
|
||||
* Try registering a custom parser using: RestAssured.registerParser("text/plain", <parser type>);
|
||||
*/
|
||||
|
||||
// response.assertThat().body("error.msg", Matchers.contains(expectedError));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_112 }, priority = 03)
|
||||
public void testGetSolrConfigOverlay() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(adminUserModel).withSolrAPI().getConfigOverlay();
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().content(Matchers.containsString("overlay"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_112 }, priority = 04)
|
||||
public void testGetSolrConfigParams() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(adminUserModel).withSolrAPI().getConfigParams();
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
|
||||
restClient.onResponse().assertThat().content(Matchers.containsString("response"));
|
||||
}
|
||||
|
||||
@Test(groups = { TestGroup.SEARCH, TestGroup.REST_API, TestGroup.ASS_112 }, priority = 05)
|
||||
public void testGetSolrSelect() throws Exception
|
||||
{
|
||||
String queryParams = "{!xmlparser v='<!DOCTYPE a SYSTEM \"http://localhost:4444/executed\"><a></a>'}";
|
||||
|
||||
String encodedQueryParams = URLEncoder.encode(queryParams, "UTF-8");
|
||||
|
||||
restClient.authenticateUser(dataContent.getAdminUser()).withParams(encodedQueryParams).withSolrAPI().getSelectQuery();
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST);
|
||||
String errorMsg = "No QueryObjectBuilder defined for node a in {q={!xmlparser";
|
||||
Assert.assertTrue(restClient.onResponse().getResponse().body().xmlPath().getString("response").contains(errorMsg));
|
||||
}
|
||||
}
|
||||
@@ -2,38 +2,71 @@
|
||||
|
||||
<suite name="SearchSuite" verbose="6" preserve-order="true">
|
||||
|
||||
<listeners>
|
||||
<listener class-name="org.alfresco.utility.report.HtmlReportListener"></listener>
|
||||
</listeners>
|
||||
<listeners>
|
||||
<listener class-name="org.alfresco.utility.report.log.LogsListener"/>
|
||||
<listener class-name="org.alfresco.utility.report.HtmlReportListener"/>
|
||||
</listeners>
|
||||
|
||||
<test name="Smoke">
|
||||
<groups>
|
||||
<run>
|
||||
<include name="sanity" />
|
||||
<include name="ASS_1.0.0" />
|
||||
<exclude name="InsightEngine_1.0.0" />
|
||||
</run>
|
||||
</groups>
|
||||
<test name="SearchFaceted">
|
||||
<classes>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.FacetIntervalSearchTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.FacetRangeSearchTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.PivotFacetedSearchTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.FacetedSearchTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.FacetFieldsSearchTest"/>
|
||||
</classes>
|
||||
</test>
|
||||
|
||||
<test name="SearchFeatures">
|
||||
<classes>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.FingerPrintTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.SearchAPATHTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.SearchHighLightTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.SearchSpellCheckTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.SearchTest"/>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.StatsSearchTest"/>
|
||||
</classes>
|
||||
</test>
|
||||
|
||||
<test name="SearchPrivateAPIs">
|
||||
<classes>
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.ShardInfoTest"/>
|
||||
</classes>
|
||||
</test>
|
||||
|
||||
<test name="SolrAPIs">
|
||||
<classes>
|
||||
<class name="org.alfresco.service.search.unit.SetupTest" />
|
||||
<class name="org.alfresco.service.search.e2e.searchservices.solr.SearchSolrAPITest" />
|
||||
</classes>
|
||||
</test>
|
||||
|
||||
<test name="E2E-SearchServices">
|
||||
<groups>
|
||||
<run>
|
||||
<include name="ASS_1.0.0" />
|
||||
<include name="ASS_1.4.0" />
|
||||
<exclude name="InsightEngine_1.0.0" />
|
||||
<exclude name="InsightEngine_1.1.0" />
|
||||
</run>
|
||||
</groups>
|
||||
<packages>
|
||||
<package name="org.alfresco.service.search.e2e.searchservices" />
|
||||
<package name="org.alfresco.service.search.e2e.searchservices.tracker" />
|
||||
</packages>
|
||||
<classes>
|
||||
</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-SearchServices">
|
||||
<groups>
|
||||
<run>
|
||||
<include name="ASS_1.0.0" />
|
||||
<include name="ASS_1.4.0" />
|
||||
<exclude name="InsightEngine_1.0.0" />
|
||||
<exclude name="InsightEngine_1.1.0" />
|
||||
</run>
|
||||
</groups>
|
||||
<packages>
|
||||
<package name="org.alfresco.service.search.e2e.searchservices" />
|
||||
<package name="org.alfresco.service.search.e2e.searchservices.tracker" />
|
||||
</packages>
|
||||
<classes>
|
||||
</classes>
|
||||
</test>
|
||||
</suite>
|
||||
|
||||
@@ -8,26 +8,61 @@ sync.scheme=http
|
||||
sync.server=localhost
|
||||
sync.port=9090
|
||||
|
||||
# solr service related
|
||||
solr.port=8083
|
||||
|
||||
|
||||
#CMIS Related: Set CMIS binding to 'browser' or 'atom'
|
||||
cmis.binding=browser
|
||||
cmis.basePath=/alfresco/api/-default-/public/cmis/versions/1.1/${cmis.binding}
|
||||
|
||||
#Solr Indexing Time
|
||||
solrWaitTimeInSeconds=20
|
||||
|
||||
#RM Specific
|
||||
rest.rmPath=alfresco/api/-default-/public/gs/versions/1
|
||||
|
||||
# Administrator Credentials
|
||||
# Solr Server Settings
|
||||
solr.scheme=http
|
||||
solr.server=localhost
|
||||
solr.port=8083
|
||||
|
||||
#Solr Indexing Time
|
||||
solrWaitTimeInSeconds=20
|
||||
|
||||
# credentials
|
||||
admin.user=admin
|
||||
admin.password=admin
|
||||
|
||||
# in containers we cannot access directly JMX, so we will use http://jolokia.org agent
|
||||
# disabling this we will use direct JMX calls to server
|
||||
jmx.useJolokiaAgent=false
|
||||
|
||||
# Server Health section
|
||||
# in ServerHealth#isServerReachable() - could also be shown.
|
||||
# enable this option to view if on server there are tenants or not
|
||||
serverHealth.showTenants=false
|
||||
|
||||
# TEST MANAGEMENT SECTION - Test Rail
|
||||
#
|
||||
# (currently supporting Test Rail v5.2.1.3472 integration)
|
||||
#
|
||||
# Example of configuration:
|
||||
# ------------------------------------------------------
|
||||
# if testManagement.enabled=true we enabled TestRailExecutorListener (if used in your suite xml file)
|
||||
# testManagement.updateTestExecutionResultsOnly=true (this will just update the results of a test: no step will be updated - good for performance)
|
||||
# testManagement.endPoint=https://alfresco.testrail.com/
|
||||
# testManagement.username=<username>
|
||||
# testManagement.apiKey=<api-key>
|
||||
# testManagement.project=<id-of-your-project
|
||||
# testManagement.testRun=<test-run-name>
|
||||
# testManagement.includeOnlyTestCasesExecuted=true #if you want to include in your run ONLY the test cases that you run, then set this value to false
|
||||
# testManagement.rateLimitInSeconds=1 #is the default rate limit after what minimum time, should we upload the next request. http://docs.gurock.com/testrail-api2/introduction #Rate Limit
|
||||
# testManagement.suiteId=23 (the id of the Master suite)
|
||||
# ------------------------------------------------------
|
||||
testManagement.enabled=false
|
||||
testManagement.endPoint=https://alfresco.testrail.com/
|
||||
testManagement.username=tas.alfresco@gmail.com
|
||||
testManagement.apiKey=EYpY7.fV0AoMGWbmyuVC-k5u.nzwHy6a.QWzJq8.S
|
||||
testManagement.project=7
|
||||
testManagement.includeOnlyTestCasesExecuted=true
|
||||
testManagement.rateLimitInSeconds=1
|
||||
testManagement.testRun=MyTestRunInTestRail
|
||||
testManagement.suiteId=12
|
||||
|
||||
# The location of the reports path
|
||||
reports.path=./target/reports
|
||||
|
||||
|
||||
@@ -12,4 +12,16 @@ log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
|
||||
log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
|
||||
|
||||
# TestRail particular log file
|
||||
# Direct log messages to a log file
|
||||
log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.testrailLog.File=./reports/alfresco-testrail.log
|
||||
log4j.appender.testrailLog.MaxBackupIndex=10
|
||||
log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.category.testrail=INFO, testrailLog
|
||||
log4j.additivity.testrail=false
|
||||
Reference in New Issue
Block a user