001/*
002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     dmetzler
016 */
017package org.nuxeo.ecm.restapi.test;
018
019import static org.junit.Assert.assertEquals;
020import static org.junit.Assert.assertTrue;
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.util.ArrayList;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Map;
028
029import javax.inject.Inject;
030import javax.ws.rs.core.MediaType;
031import javax.ws.rs.core.MultivaluedMap;
032import javax.ws.rs.core.Response;
033
034import org.codehaus.jackson.JsonNode;
035import org.codehaus.jackson.JsonProcessingException;
036import org.codehaus.jackson.map.ObjectMapper;
037import org.junit.Before;
038import org.nuxeo.ecm.core.api.CoreSession;
039import org.nuxeo.ecm.core.api.DocumentModel;
040import org.nuxeo.runtime.transaction.TransactionHelper;
041
042import com.sun.jersey.api.client.Client;
043import com.sun.jersey.api.client.ClientResponse;
044import com.sun.jersey.api.client.WebResource;
045import com.sun.jersey.api.client.WebResource.Builder;
046import com.sun.jersey.api.client.config.ClientConfig;
047import com.sun.jersey.api.client.config.DefaultClientConfig;
048import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
049import com.sun.jersey.multipart.MultiPart;
050import com.sun.jersey.multipart.impl.MultiPartWriter;
051
052/**
053 * @since 5.7.2
054 */
055public class BaseTest {
056
057    private static final Integer TIMEOUT = Integer.valueOf(1000 * 60 * 5); // 5min
058
059    protected static enum RequestType {
060        GET, POST, DELETE, PUT, POSTREQUEST, GETES
061    }
062
063    protected ObjectMapper mapper;
064
065    protected Client client;
066
067    protected WebResource service;
068
069    @Before
070    public void doBefore() throws Exception {
071        service = getServiceFor("Administrator", "Administrator");
072
073        mapper = new ObjectMapper();
074
075    }
076
077    /**
078     * @param user
079     * @param password
080     * @return
081     * @since 5.7.3
082     */
083    protected WebResource getServiceFor(String user, String password) {
084        ClientConfig config = new DefaultClientConfig();
085        config.getClasses().add(MultiPartWriter.class);
086        client = Client.create(config);
087        client.setConnectTimeout(TIMEOUT);
088        client.setReadTimeout(TIMEOUT);
089        client.addFilter(new HTTPBasicAuthFilter(user, password));
090
091        return client.resource("http://localhost:18090/api/v1/");
092    }
093
094    @Inject
095    public CoreSession session;
096
097    protected ClientResponse getResponse(RequestType requestType, String path) {
098        return getResponse(requestType, path, null, null, null, null);
099    }
100
101    protected ClientResponse getResponse(RequestType requestType, String path, Map<String, String> headers) {
102        return getResponse(requestType, path, null, null, null, headers);
103    }
104
105    protected ClientResponse getResponse(RequestType requestType, String path, MultiPart mp) {
106        return getResponse(requestType, path, null, null, mp, null);
107    }
108
109    protected ClientResponse getResponse(RequestType requestType, String path, MultiPart mp, Map<String, String> headers) {
110        return getResponse(requestType, path, null, null, mp, headers);
111    }
112
113    protected ClientResponse getResponse(RequestType requestType, String path,
114            MultivaluedMap<String, String> queryParams) {
115        return getResponse(requestType, path, null, queryParams, null, null);
116    }
117
118    protected ClientResponse getResponse(RequestType requestType, String path, String data) {
119        return getResponse(requestType, path, data, null, null, null);
120    }
121
122    protected ClientResponse getResponse(RequestType requestType, String path, String data, Map<String, String> headers) {
123        return getResponse(requestType, path, data, null, null, headers);
124    }
125
126    protected ClientResponse getResponse(RequestType requestType, String path, String data,
127            MultivaluedMap<String, String> queryParams, MultiPart mp, Map<String, String> headers) {
128        WebResource wr = service.path(path);
129
130        if (queryParams != null && !queryParams.isEmpty()) {
131            wr = wr.queryParams(queryParams);
132        }
133        Builder builder;
134        if (requestType == RequestType.GETES) {
135            builder = wr.accept("application/json+esentity");
136        } else {
137            builder = wr.accept(MediaType.APPLICATION_JSON).header("X-NXDocumentProperties", "dublincore");
138        }
139        if (mp != null) {
140            builder = wr.type(MediaType.MULTIPART_FORM_DATA_TYPE);
141        }
142
143        if (headers == null || !(headers.containsKey("Content-Type"))) {
144            if (requestType == RequestType.POSTREQUEST) {
145                builder.header("Content-Type", "application/json+nxrequest");
146            } else {
147                builder.header("Content-Type", "application/json+nxentity");
148            }
149        }
150
151        // Adding some headers if needed
152        if (headers != null && !headers.isEmpty()) {
153            for (String headerKey : headers.keySet()) {
154                builder.header(headerKey, headers.get(headerKey));
155            }
156        }
157        switch (requestType) {
158        case GET:
159        case GETES:
160            return builder.get(ClientResponse.class);
161        case POST:
162        case POSTREQUEST:
163            if (mp != null) {
164                return builder.post(ClientResponse.class, mp);
165            } else {
166                return builder.post(ClientResponse.class, data);
167            }
168        case PUT:
169            if (mp != null) {
170                return builder.put(ClientResponse.class, mp);
171            } else {
172                return builder.put(ClientResponse.class, data);
173            }
174        case DELETE:
175            return builder.delete(ClientResponse.class, data);
176        default:
177            throw new RuntimeException();
178        }
179    }
180
181    protected JsonNode getResponseAsJson(RequestType responseType, String url) throws IOException,
182            JsonProcessingException {
183        return getResponseAsJson(responseType, url, null);
184    }
185
186    /**
187     * @param get
188     * @param string
189     * @param queryParamsForPage
190     * @return
191     * @throws IOException
192     * @throws JsonProcessingException
193     * @since 5.8
194     */
195    protected JsonNode getResponseAsJson(RequestType responseType, String url,
196            MultivaluedMap<String, String> queryParams) throws JsonProcessingException, IOException {
197        ClientResponse response = getResponse(responseType, url, queryParams);
198        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
199        return mapper.readTree(response.getEntityInputStream());
200    }
201
202    /**
203     * Fetch session invalidations.
204     *
205     * @since 5.9.3
206     */
207    protected void fetchInvalidations() {
208        session.save();
209        if (TransactionHelper.isTransactionActiveOrMarkedRollback()) {
210            TransactionHelper.commitOrRollbackTransaction();
211            TransactionHelper.startTransaction();
212        }
213    }
214
215    protected void assertNodeEqualsDoc(JsonNode node, DocumentModel note) throws Exception {
216        assertEquals("document", node.get("entity-type").getValueAsText());
217        assertEquals(note.getPathAsString(), node.get("path").getValueAsText());
218        assertEquals(note.getId(), node.get("uid").getValueAsText());
219        assertEquals(note.getTitle(), node.get("title").getValueAsText());
220    }
221
222    protected List<JsonNode> getLogEntries(JsonNode node) {
223        assertEquals("documents", node.get("entity-type").getValueAsText());
224        assertTrue(node.get("entries").isArray());
225        List<JsonNode> result = new ArrayList<>();
226        Iterator<JsonNode> elements = node.get("entries").getElements();
227        while (elements.hasNext()) {
228            result.add(elements.next());
229        }
230        return result;
231    }
232
233    /**
234     * @since 7.1
235     */
236    protected String getErrorMessage(JsonNode node) {
237        assertEquals("exception", node.get("entity-type").getValueAsText());
238        assertTrue(node.get("message").isTextual());
239        return node.get("message").getValueAsText();
240    }
241
242    protected void assertEntityEqualsDoc(InputStream in, DocumentModel doc) throws Exception {
243
244        JsonNode node = mapper.readTree(in);
245        assertNodeEqualsDoc(node, doc);
246
247    }
248}