/* * (C) Copyright 2013 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: * dmetzler */ package org.nuxeo.ecm.restapi.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.io.IOException; import java.util.Arrays; import java.util.List; import javax.inject.Inject; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.node.ArrayNode; import org.junit.Test; import org.junit.runner.RunWith; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.event.EventService; import org.nuxeo.ecm.core.test.CoreFeature; import org.nuxeo.ecm.core.test.annotations.Granularity; import org.nuxeo.ecm.core.test.annotations.RepositoryConfig; import org.nuxeo.ecm.restapi.server.jaxrs.QueryObject; import org.nuxeo.ecm.restapi.server.jaxrs.adapters.ChildrenAdapter; import org.nuxeo.ecm.restapi.server.jaxrs.adapters.PageProviderAdapter; import org.nuxeo.ecm.restapi.server.jaxrs.adapters.SearchAdapter; import org.nuxeo.runtime.api.Framework; 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.google.common.base.Joiner; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.core.util.MultivaluedMapImpl; /** * Test the various ways to query for document lists. * * @since 5.7.2 */ @RunWith(FeaturesRunner.class) @Features(RestServerFeature.class) @Jetty(port = 18090) @LocalDeploy("org.nuxeo.ecm.platform.restapi.test:pageprovider-test-contrib.xml") @RepositoryConfig(cleanup = Granularity.METHOD, init = RestServerInit.class) public class DocumentListTest extends BaseTest { @Inject protected CoreFeature coreFeature; @Test public void iCanGetTheChildrenOfADocument() throws Exception { // Given a folder DocumentModel folder = RestServerInit.getFolder(1, session); // When I query for it children ClientResponse response = getResponse(RequestType.GET, "id/" + folder.getId() + "/@" + ChildrenAdapter.NAME); // Then I get its children as JSON assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(session.getChildren(folder.getRef()).size(), getLogEntries(node).size()); } @Test public void iCanSearchInFullTextForDocuments() throws Exception { // Given a note with "nuxeo" in its description DocumentModel note = RestServerInit.getNote(0, session); note.setPropertyValue("dc:description", "nuxeo one platform to rule them all"); session.saveDocument(note); TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); // Waiting for all async events work for indexing content before // executing fulltext search Framework.getLocalService(EventService.class).waitForAsyncCompletion(); coreFeature.getStorageConfiguration().sleepForFulltext(); // When I search for "nuxeo" MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.putSingle("fullText", "nuxeo"); ClientResponse response = getResponse(RequestType.GET, "path/@" + SearchAdapter.NAME, queryParams); // Then I get the document in the result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); } @Test public void iCanPerformQueriesOnRepository() throws IOException { // Given a repository, when I perform a query in NXQL on it MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.putSingle("query", "SELECT * FROM Document"); ClientResponse response = getResponse(RequestType.GET, "query", queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(20, getLogEntries(node).size()); // Given a repository, when I perform a query in NXQL on it response = getResponse(RequestType.GET, QueryObject.PATH + "/" + QueryObject.NXQL, queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(20, getLogEntries(node).size()); // Given parameters as page size and ordered parameters queryParams.clear(); queryParams.add("pageSize", "2"); queryParams.add("queryParams", "$currentUser"); queryParams.add("query", "select * from Document where dc:creator = ?"); // Given a repository, when I perform a query in NXQL on it response = getResponse(RequestType.GET, QueryObject.PATH + "/" + QueryObject.NXQL, queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void iCanPerformQueriesWithNamedParametersOnRepository() throws IOException { // Given a repository and named parameters, when I perform a query in // NXQL on it DocumentModel folder = RestServerInit.getFolder(1, session); MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("query", "SELECT * FROM Document WHERE " + "ecm:parentId = :parentIdVar AND\n" + " ecm:mixinType != 'HiddenInNavigation' AND dc:title " + "IN (:note1,:note2)\n" + " AND ecm:isCheckedInVersion = 0 AND " + "ecm:currentLifeCycleState !=\n" + " 'deleted'"); queryParams.add("note1", "Note 1"); queryParams.add("note2", "Note 2"); queryParams.add("parentIdVar", folder.getId()); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH, queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void iCanPerformQueriesWithNamedParametersOnRepositoryAndSameVariables() throws IOException { // Given a repository and named parameters, when I perform a query in // NXQL on it DocumentModel folder = RestServerInit.getFolder(1, session); MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("query", "SELECT * FROM Document WHERE " + "ecm:parentId = :parentIdVar AND\n" + " ecm:mixinType != 'HiddenInNavigation' AND dc:title " + "IN (:title,:title2)\n" + " AND ecm:isCheckedInVersion = 0 AND " + "ecm:currentLifeCycleState !=\n" + " 'deleted'"); queryParams.add("title", "Note 1"); queryParams.add("title2", "Note 2"); queryParams.add("parentIdVar", folder.getId()); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH, queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void iCanPerformPageProviderOnRepository() throws IOException { // Given a repository, when I perform a pageprovider on it DocumentModel folder = RestServerInit.getFolder(1, session); MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("queryParams", folder.getId()); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/TEST_PP", queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void iCanPerformPageProviderWithNamedParametersOnRepository() throws IOException { // Given a repository, when I perform a pageprovider on it DocumentModel folder = RestServerInit.getFolder(1, session); MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("note1", "Note 1"); queryParams.add("note2", "Note 2"); queryParams.add("parentIdVar", folder.getId()); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/TEST_PP_PARAM", queryParams); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersInvalid() throws Exception { ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderInvalid"); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals( "Failed to execute query: SELECT * FROM Document where dc:title=:foo ORDER BY dc:title, Lexical Error: Illegal character <:> at offset 38", getErrorMessage(node)); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersAndDoc() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("np:title", "Folder 0"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithDoc", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersAndDocInvalid() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("np:title", "Folder 0"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithDocInvalid", queryParams); assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals( "Failed to execute query: SELECT * FROM Document where dc:title=:foo ORDER BY dc:title, Lexical Error: Illegal character <:> at offset 38", getErrorMessage(node)); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersInWhereClause() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("parameter1", "Folder 0"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithWhereClause", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); // retry without params response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithWhereClause"); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersInWhereClauseWithDoc() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("np:title", "Folder 0"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithWhereClauseWithDoc", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); // retry without params response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithWhereClauseWithDoc"); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } /** * @since 8.4 */ @Test public void iCanPerformPageProviderWithNamedParametersWithQuickFilter() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("quickFilters", "testQuickFilter"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderWithQuickFilter", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); } /** * @since 7.1 */ @Test public void iCanPerformPageProviderWithNamedParametersComplex() throws Exception { MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.add("parameter1", "Folder 0"); queryParams.add("np:isCheckedIn", Boolean.FALSE.toString()); queryParams.add("np:dateMin", "2007-01-30 01:02:03+04:00"); queryParams.add("np:dateMax", "2007-03-23 01:02:03+04:00"); ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderComplex", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); // remove filter on dates queryParams.remove("np:dateMin"); queryParams.remove("np:dateMax"); response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderComplex", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(1, getLogEntries(node).size()); queryParams.remove("parameter1"); response = getResponse(RequestType.GET, QueryObject.PATH + "/namedParamProviderComplex", queryParams); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void itCanGetAdapterForRootDocument() throws Exception { // Given the root document DocumentModel rootDocument = session.getRootDocument(); // When i ask for an adapter JsonNode node = getResponseAsJson(RequestType.GET, "path" + rootDocument.getPathAsString() + "@children"); // The it return a response ArrayNode jsonNode = (ArrayNode) node.get("entries"); assertEquals(session.getChildren(rootDocument.getRef()).size(), jsonNode.size()); } @Test public void iCanUseAPageProvider() throws Exception { // Given a note with "nuxeo" in its description DocumentModel folder = RestServerInit.getFolder(1, session); // When I search for "nuxeo" ClientResponse response = getResponse(RequestType.GET, "path" + folder.getPathAsString() + "/@" + PageProviderAdapter.NAME + "/TEST_PP"); // Then I get the two document in the result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); assertEquals(2, getLogEntries(node).size()); } @Test public void iCanDeleteAListOfDocuments() throws Exception { // Given two notes DocumentModel note1 = RestServerInit.getNote(1, session); DocumentModel folder0 = RestServerInit.getFolder(0, session); // When i call a bulk delete String data = Joiner.on(";").join( Arrays.asList(new String[] { "id=" + note1.getId(), "id=" + folder0.getId() })); ClientResponse response = getResponse(RequestType.DELETE, "/bulk;" + data); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); // Then the documents are removed from repository fetchInvalidations(); assertFalse(session.exists(note1.getRef())); assertFalse(session.exists(folder0.getRef())); } @Test public void iCanUpdateDocumentLists() throws Exception { // Given two notes DocumentModel note1 = RestServerInit.getNote(1, session); DocumentModel note2 = RestServerInit.getNote(2, session); String data = "{\"entity-type\":\"document\"," + "\"type\":\"Note\"," + "\"properties\":{" + " \"dc:description\":\"bulk description\"" + " }" + "}"; // When i call a bulk update String ids = Joiner.on(";").join(Arrays.asList(new String[] { "id=" + note1.getId(), "id=" + note2.getId() })); ClientResponse response = getResponse(RequestType.PUT, "/bulk;" + ids, data); // Then the documents are updated accordingly fetchInvalidations(); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); for (int i : new int[] { 1, 2 }) { note1 = RestServerInit.getNote(i, session); assertEquals("bulk description", note1.getPropertyValue("dc:description")); } } /** * @since 8.10 */ @Test public void iCanPerformPageProviderWithDefinitionDefaultSorting() throws IOException { // Given a repository, when I perform a pageprovider on it with // default sorting in its definition on dc:title desc ClientResponse response = getResponse(RequestType.GET, QueryObject.PATH + "/TEST_NOTE_PP_WITH_TITLE_ORDER"); // Then I get document listing as result assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); JsonNode node = mapper.readTree(response.getEntityInputStream()); List<JsonNode> noteNodes = getLogEntries(node); assertEquals(RestServerInit.MAX_NOTE, noteNodes.size()); for (int i = 0; i < noteNodes.size(); i++) { assertEquals("Note " + (RestServerInit.MAX_NOTE - (i + 1)), noteNodes.get(i).get("title").getTextValue()); } } }