/*
* (C) Copyright 2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* bdelbosc
*/
package org.nuxeo.elasticsearch.test.rest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import org.codehaus.jackson.JsonNode;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.ecm.automation.AutomationService;
import org.nuxeo.ecm.automation.OperationContext;
import org.nuxeo.ecm.automation.core.operations.services.DocumentPageProviderOperation;
import org.nuxeo.ecm.automation.core.util.Properties;
import org.nuxeo.ecm.automation.jaxrs.io.documents.PaginableDocumentModelListImpl;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.test.annotations.Granularity;
import org.nuxeo.ecm.core.test.annotations.RepositoryConfig;
import org.nuxeo.ecm.core.work.api.WorkManager;
import org.nuxeo.ecm.platform.query.api.PageProvider;
import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
import org.nuxeo.ecm.platform.query.api.PageProviderService;
import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider;
import org.nuxeo.ecm.restapi.server.jaxrs.QueryObject;
import org.nuxeo.ecm.restapi.server.jaxrs.adapters.SearchAdapter;
import org.nuxeo.ecm.restapi.test.BaseTest;
import org.nuxeo.ecm.restapi.test.RestServerFeature;
import org.nuxeo.ecm.restapi.test.RestServerInit;
import org.nuxeo.elasticsearch.api.ElasticSearchAdmin;
import org.nuxeo.elasticsearch.io.marshallers.json.AggregateJsonWriter;
import org.nuxeo.elasticsearch.provider.ElasticSearchNxqlPageProvider;
import org.nuxeo.elasticsearch.test.RepositoryElasticSearchFeature;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.Jetty;
import org.nuxeo.runtime.test.runner.LocalDeploy;
import org.nuxeo.runtime.transaction.TransactionHelper;
import com.sun.jersey.api.client.ClientResponse;
/**
* Test the various ways to get elasticsearch Json output.
*
* @since 5.9.3
*/
@RunWith(FeaturesRunner.class)
@Features({ RestServerFeature.class, RepositoryElasticSearchFeature.class })
@Jetty(port = 18090)
@Deploy({ "org.nuxeo.ecm.platform.tag", "org.nuxeo.ecm.platform.ws" })
@LocalDeploy({ "org.nuxeo.ecm.platform.restapi.test:pageprovider-test-contrib.xml",
"org.nuxeo.ecm.platform.restapi.test:elasticsearch-test-contrib.xml",
"org.nuxeo.elasticsearch.core:pageprovider2-test-contrib.xml",
"org.nuxeo.elasticsearch.core:pageprovider2-coretype-test-contrib.xml",
"org.nuxeo.elasticsearch.core:pageprovider-search-test-contrib.xml",
"org.nuxeo.elasticsearch.core:test-directory-contrib.xml" })
@RepositoryConfig(cleanup = Granularity.METHOD, init = RestServerInit.class)
public class RestESDocumentsTest extends BaseTest {
public static final String QUERY = "select * from Document where " + "ecm:currentLifeCycleState <> 'deleted'";
@Inject
PageProviderService pageProviderService;
@Inject
AutomationService automationService;
@Inject
private SchemaManager schemaManager;
@Test
public void iCanBrowseTheRepoByItsId() throws Exception {
// Given a document
DocumentModel doc = RestServerInit.getNote(0, session);
// When i do a GET Request
ClientResponse response = getResponse(RequestType.GETES, "id/" + doc.getId());
// Then I get the document as Json will all the properties
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
JsonNode node = mapper.readTree(response.getEntityInputStream());
// System.err.println(node.toString());
assertEquals("Note 0", node.get("note:note").getTextValue());
}
@Test
public void iCanPerformESQLPageProviderOnRepository() throws IOException, InterruptedException {
// wait for async jobs
ElasticSearchAdmin esa = Framework.getLocalService(ElasticSearchAdmin.class);
WorkManager wm = Framework.getLocalService(WorkManager.class);
Assert.assertTrue(wm.awaitCompletion(20, TimeUnit.SECONDS));
Assert.assertEquals(0, esa.getPendingWorkerCount());
esa.refresh();
Assert.assertTrue(wm.awaitCompletion(20, TimeUnit.SECONDS));
// Given a repository, when I perform a ESQL pageprovider on it
ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/aggregates_2");
// Then I get document listing as result
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
JsonNode node = mapper.readTree(response.getEntityInputStream());
// Verify results
assertEquals(20, getLogEntries(node).size());
// And verify contributed aggregates
assertEquals("terms", node.get("aggregations").get("coverage").get("type").getTextValue());
}
/**
* Testing the REST_API_SEARCH_ADAPTER page provider when using elasticsearch.override.pageproviders conf variable
* to replace the core page provider by ES generic.
*
* @since 7.4
*/
@Test
@SuppressWarnings("unchecked")
public void isQueryEndpointCanSwitchToES() {
Map<String, Serializable> props = new HashMap<>();
props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) session);
PageProviderDefinition ppdefinition = pageProviderService.getPageProviderDefinition(
SearchAdapter.pageProviderName);
ppdefinition.setPattern(QUERY);
ppdefinition.getProperties().put("maxResults", "1");
PaginableDocumentModelListImpl res = new PaginableDocumentModelListImpl(
(PageProvider<DocumentModel>) pageProviderService.getPageProvider(SearchAdapter.pageProviderName,
ppdefinition, null, null, 10000L, null, props, (Object[]) null),
null);
if (!(res.getProvider() instanceof ElasticSearchNxqlPageProvider)) {
fail("Should be an elastic search page provider");
}
}
@Test
public void iCanPerformESQLPageProviderOperationOnRepository() throws Exception {
OperationContext ctx = new OperationContext(session);
Map<String, Object> params = new HashMap<>();
String providerName = "default_search";
params.put("providerName", providerName);
Map<String, String> namedParameters = new HashMap<>();
namedParameters.put("defaults:dc_nature_agg", "[\"article\"]");
Properties namedProperties = new Properties(namedParameters);
params.put("namedParameters", namedProperties);
PaginableDocumentModelListImpl result = (PaginableDocumentModelListImpl) automationService.run(ctx,
DocumentPageProviderOperation.ID, params);
// test page size
assertEquals(20, result.getPageSize());
assertEquals(11, result.size());
}
/**
* @since 8.10
*/
@Test
public void iCanQueryESQLPageProviderAndFetchAggregateKeys() throws Exception {
// Updating a note automatically creates a version of it
Map<String, String> headers = new HashMap<String, String>();
headers.put("fetch." + AggregateJsonWriter.ENTITY_TYPE, AggregateJsonWriter.FETCH_KEY);
for (int i = 0; i < RestServerInit.MAX_NOTE; i++) {
DocumentModel doc = RestServerInit.getNote(i, session);
doc.setPropertyValue("dc:coverage", "europe/France");
doc.setPropertyValue("dc:subjects", new String[] { "art/cinema" });
doc = session.saveDocument(doc);
}
TransactionHelper.commitOrRollbackTransaction();
TransactionHelper.startTransaction();
// wait for async jobs
ElasticSearchAdmin esa = Framework.getLocalService(ElasticSearchAdmin.class);
WorkManager wm = Framework.getLocalService(WorkManager.class);
Assert.assertTrue(wm.awaitCompletion(20, TimeUnit.SECONDS));
Assert.assertEquals(0, esa.getPendingWorkerCount());
esa.refresh();
Assert.assertTrue(wm.awaitCompletion(20, TimeUnit.SECONDS));
// Given a repository, when I perform a ESQL pageprovider on it
ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/aggregates_3", null, null, null,
headers);
// Then I get document listing as result
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
JsonNode node = mapper.readTree(response.getEntityInputStream());
// And verify contributed aggregates
assertEquals("terms", node.get("aggregations").get("coverage").get("type").getTextValue());
JsonNode bucket = node.get("aggregations").get("coverage").get("buckets").get(0);
int docCount = bucket.get("docCount").getIntValue();
assertEquals(RestServerInit.MAX_NOTE, docCount);
// Check that the key of the bucket which is a l10ncoverage vocabulary entry has been fetch
String keyText = bucket.get("key").getTextValue();
assertEquals("europe/France", keyText);
String fetchedkeyIdText = bucket.get("fetchedKey").get("properties").get("id").getTextValue();
assertEquals("France", fetchedkeyIdText);
// And verify contributed aggregates
assertEquals("terms", node.get("aggregations").get("subjects").get("type").getTextValue());
JsonNode firstBucket = node.get("aggregations").get("subjects").get("buckets").get(0);
docCount = firstBucket.get("docCount").getIntValue();
assertEquals(RestServerInit.MAX_NOTE, docCount);
// Check that the key of the bucket which is a l10nsubjects vocabulary entry has been fetch
keyText = firstBucket.get("key").getTextValue();
assertEquals("art/cinema", keyText);
fetchedkeyIdText = firstBucket.get("fetchedKey").get("properties").get("id").getTextValue();
assertEquals("cinema", fetchedkeyIdText);
}
}