org.modeshape.web.jcr.rest.AbstractRestTest.java Source code

Java tutorial

Introduction

Here is the source code for org.modeshape.web.jcr.rest.AbstractRestTest.java

Source

/*
 * ModeShape (http://www.modeshape.org)
 *
 * 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.
 */
package org.modeshape.web.jcr.rest;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.core.MediaType;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.modeshape.common.text.UrlEncoder;
import org.modeshape.common.util.IoUtil;
import org.modeshape.common.util.StringUtil;
import org.modeshape.jcr.api.JcrConstants;
import org.modeshape.web.jcr.rest.handler.AbstractHandler;
import junit.framework.AssertionFailedError;

/**
 * Base class used for testing the interaction with {@link org.modeshape.web.jcr.rest.ModeShapeRestService}
 *
 * @author Horia Chiorean (hchiorea@redhat.com)
 */
@SuppressWarnings("deprecation")
public abstract class AbstractRestTest {

    private static final List<String> JSON_PROPERTIES_IGNORE_EQUALS = Arrays.asList("jcr:uuid", "jcr:score",
            AbstractHandler.NODE_ID_CUSTOM_PROPERTY);
    private static final UrlEncoder URL_ENCODER = new UrlEncoder().setSlashEncoded(false);

    protected CloseableHttpClient httpClient;
    protected HttpClientContext httpContext;

    protected abstract String getServerContext();

    protected abstract HttpHost getHost();

    @Before
    public void beforeEach() throws Exception {
        httpClient = HttpClientBuilder.create().build();
        httpContext = HttpClientContext.create();
    }

    @After
    public void afterEach() throws Exception {
        httpClient.getConnectionManager().shutdown();
    }

    protected void setAuthCredentials(String authUsername, String authPassword) {
        BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(new AuthScope(getHost()),
                new UsernamePasswordCredentials(authUsername, authPassword));
        httpContext.setCredentialsProvider(credentialsProvider);
    }

    protected Response doGet() throws Exception {
        return new Response(newDefaultRequest(HttpGet.class, null, null));
    }

    protected Response doGet(String url) throws Exception {
        return new Response(newDefaultRequest(HttpGet.class, null, null, url));
    }

    protected Response doPost(String payloadFile, String url) throws Exception {
        InputStream is = null;
        if (payloadFile != null) {
            is = fileStream(payloadFile);
            assertNotNull(is);
        }
        return postStream(is, url, MediaType.APPLICATION_JSON);
    }

    protected Response doPost(InputStream is, String url) throws Exception {
        return postStream(is, url, null);
    }

    protected Response doPost(JSONObject object, String url) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(byteArrayOutputStream);
        object.write(writer);
        writer.flush();
        writer.close();

        HttpPost post = newDefaultRequest(HttpPost.class,
                new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), MediaType.APPLICATION_JSON, url);
        return new Response(post);
    }

    protected InputStream fileStream(String file) {
        return getClass().getClassLoader().getResourceAsStream(file);
    }

    protected JSONObject readJson(String file) throws Exception {
        String fileContent = IoUtil.read(fileStream(file));
        return new JSONObject(fileContent);
    }

    protected Response xpathQuery(String query, String url) throws Exception {
        return postStream(new ByteArrayInputStream(query.getBytes()), url, "application/jcr+xpath");
    }

    protected Response jcrSQL2Query(String query, String url) throws Exception {
        return postStream(new ByteArrayInputStream(query.getBytes()), url, "application/jcr+sql2");
    }

    protected Response jcrSQL2QueryPlan(String query, String url) throws Exception {
        return postStream(new ByteArrayInputStream(query.getBytes()), url, "application/jcr+sql2");
    }

    protected Response jcrSQL2QueryPlanAsText(String query, String url) throws Exception {
        return postStreamForTextResponse(new ByteArrayInputStream(query.getBytes()), url, "application/jcr+sql2");
    }

    protected Response postStream(InputStream is, String url, String contentType) throws Exception {
        HttpPost post = newDefaultRequest(HttpPost.class, is, contentType, url);
        return new Response(post);
    }

    protected Response postStreamForTextResponse(InputStream is, String url, String contentType) throws Exception {
        HttpPost post = newRequest(HttpPost.class, is, contentType, MediaType.TEXT_PLAIN, url);
        return new Response(post);
    }

    protected Response doPostMultiPart(String filePath, String elementName, String url, String contentType) {
        try {

            if (StringUtil.isBlank(contentType)) {
                contentType = MediaType.APPLICATION_OCTET_STREAM;
            }

            url = URL_ENCODER.encode(RestHelper.urlFrom(getServerContext(), url));

            HttpPost post = new HttpPost(url);
            post.setHeader("Accept", MediaType.APPLICATION_JSON);
            MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IoUtil.write(fileStream(filePath), baos);
            entityBuilder.addPart(elementName, new ByteArrayBody(baos.toByteArray(), "test_file"));
            post.setEntity(entityBuilder.build());

            return new Response(post);
        } catch (Exception e) {
            e.printStackTrace();
            fail(e.getMessage());
            return null;
        }
    }

    protected Response doPut(String payloadFile, String url) throws Exception {
        HttpPut put = newDefaultRequest(HttpPut.class, fileStream(payloadFile), MediaType.APPLICATION_JSON, url);
        return new Response(put);
    }

    protected Response doPut(InputStream is, String url) throws Exception {
        HttpPut put = newDefaultRequest(HttpPut.class, is, MediaType.APPLICATION_JSON, url);
        return new Response(put);
    }

    protected Response doPut(JSONObject request, String url) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(byteArrayOutputStream);
        request.write(writer);
        writer.flush();
        writer.close();
        HttpPut put = newDefaultRequest(HttpPut.class,
                new ByteArrayInputStream(byteArrayOutputStream.toByteArray()), MediaType.APPLICATION_JSON, url);
        return new Response(put);
    }

    protected Response doDelete(String url) throws Exception {
        HttpDeleteWithBody delete = newDefaultRequest(HttpDeleteWithBody.class, null, null, url);
        return new Response(delete);
    }

    protected Response doDelete(String payloadFile, String url) throws Exception {
        InputStream is = null;
        if (payloadFile != null) {
            is = fileStream(payloadFile);
        }
        HttpDeleteWithBody delete = newDefaultRequest(HttpDeleteWithBody.class, is, MediaType.APPLICATION_JSON,
                url);
        return new Response(delete);
    }

    private <T extends HttpRequestBase> T newDefaultRequest(Class<T> clazz, InputStream inputStream,
            String contentType, String... pathSegments) {
        return newRequest(clazz, inputStream, contentType, MediaType.APPLICATION_JSON, pathSegments);
    }

    private <T extends HttpRequestBase> T newRequest(Class<T> clazz, InputStream inputStream, String contentType,
            String accepts, String... pathSegments) {
        String url = RestHelper.urlFrom(getServerContext(), pathSegments);

        try {
            URIBuilder uriBuilder;
            try {
                uriBuilder = new URIBuilder(url);
            } catch (URISyntaxException e) {
                uriBuilder = new URIBuilder(URL_ENCODER.encode(url));
            }

            T result = clazz.getConstructor(URI.class).newInstance(uriBuilder.build());
            result.setHeader("Accept", accepts);
            result.setHeader("Content-Type", contentType);

            if (inputStream != null) {
                assertTrue("Invalid request clazz (requires an entity)",
                        result instanceof HttpEntityEnclosingRequestBase);
                InputStreamEntity inputStreamEntity = new InputStreamEntity(inputStream, inputStream.available());
                ((HttpEntityEnclosingRequestBase) result).setEntity(new BufferedHttpEntity(inputStreamEntity));
            }

            return result;
        } catch (Exception e) {
            e.printStackTrace();
            fail(e.getMessage());
            return null;
        }
    }

    protected void assertJSON(Object expected, Object actual) throws JSONException {
        if (expected instanceof JSONObject) {
            assert (actual instanceof JSONObject);
            JSONObject expectedJSON = (JSONObject) expected;
            JSONObject actualJSON = (JSONObject) actual;

            for (Iterator<?> keyIterator = expectedJSON.keys(); keyIterator.hasNext();) {
                String key = keyIterator.next().toString();
                assertTrue("Actual JSON object does not contain key '" + key + "': " + actualJSON,
                        actualJSON.has(key));

                Object expectedValueAtKey = expectedJSON.get(key);
                Object actualValueAtKey = actualJSON.get(key);

                if (shouldNotAssertEquality(key)) {
                    assertNotNull(actualValueAtKey);
                } else {
                    assertJSON(expectedValueAtKey, actualValueAtKey);
                }
            }
        } else if (expected instanceof JSONArray) {
            assert (actual instanceof JSONArray);
            JSONArray expectedArray = (JSONArray) expected;
            JSONArray actualArray = (JSONArray) actual;
            Assert.assertEquals(
                    "Arrays don't match. \nExpected:" + expectedArray.toString() + "\nActual  :" + actualArray,
                    expectedArray.length(), actualArray.length());
            for (int i = 0; i < expectedArray.length(); i++) {
                assertJSON(expectedArray.get(i), actualArray.get(i));
            }
        } else {
            assertEquals("Values don't match", expected.toString(), actual.toString());
        }
    }

    private boolean shouldNotAssertEquality(String propertyName) {
        for (String propertyToIgnore : JSON_PROPERTIES_IGNORE_EQUALS) {
            if (propertyName.toLowerCase().contains(propertyToIgnore.toLowerCase())) {
                return true;
            }
        }
        return false;
    }

    protected static class HttpDeleteWithBody extends HttpPost {
        public HttpDeleteWithBody(URI uri) {
            super(uri);
        }

        @Override
        public String getMethod() {
            return "DELETE";
        }
    }

    protected class Response {

        private final HttpResponse response;
        private byte[] content;
        private String contentString;
        private JSONObject contentJSON;

        protected Response(HttpRequestBase request) {
            try {
                response = httpClient.execute(getHost(), request, httpContext);
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    ByteArrayOutputStream baous = new ByteArrayOutputStream();
                    entity.writeTo(baous);
                    EntityUtils.consumeQuietly(entity);
                    content = baous.toByteArray();
                } else {
                    content = new byte[0];
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                request.releaseConnection();
            }
        }

        private Response hasCode(int responseCode) throws Exception {
            assertEquals(responseCode, response.getStatusLine().getStatusCode());
            return this;
        }

        private Response hasHeader(String name, String value) {
            assertEquals(value, response.getFirstHeader(name).getValue());
            return this;
        }

        protected String getContentTypeHeader() {
            return response.getFirstHeader("Content-Type").getValue();
        }

        protected Response hasMimeType(String mimeType) {
            hasHeader("Content-Type", mimeType);
            return this;
        }

        protected Response hasContentDisposition(String contentDisposition) {
            hasHeader("Content-Disposition", contentDisposition);
            return this;
        }

        protected Response isOk() throws Exception {
            return hasCode(HttpURLConnection.HTTP_OK);
        }

        protected Response isCreated() throws Exception {
            return hasCode(HttpURLConnection.HTTP_CREATED);
        }

        protected Response isDeleted() throws Exception {
            return hasCode(HttpURLConnection.HTTP_NO_CONTENT);
        }

        protected Response isNotFound() throws Exception {
            return hasCode(HttpURLConnection.HTTP_NOT_FOUND);
        }

        protected Response isUnauthorized() throws Exception {
            return hasCode(HttpURLConnection.HTTP_UNAUTHORIZED);
        }

        protected Response isBadRequest() throws Exception {
            return hasCode(HttpURLConnection.HTTP_BAD_REQUEST);
        }

        protected Response isJSON() throws Exception {
            assertTrue(getContentTypeHeader().toLowerCase().contains(MediaType.APPLICATION_JSON.toLowerCase()));
            return this;
        }

        protected Response isJSONObjectLikeFile(String pathToExpectedJSON) throws Exception {
            isJSON();
            String expectedJSONString = IoUtil.read(fileStream(pathToExpectedJSON));
            JSONObject expectedObject = new JSONObject(expectedJSONString);

            JSONObject responseObject = new JSONObject(contentAsString());

            try {
                assertJSON(expectedObject, responseObject);
            } catch (AssertionFailedError e) {
                System.out.println("expected: " + expectedObject);
                System.out.println("response: " + responseObject);
                throw e;
            }

            return this;
        }

        protected Response isJSONObjectLike(Response otherResponse) throws Exception {
            isJSON();
            JSONObject expectedObject = otherResponse.json();

            JSONObject responseObject = new JSONObject(contentAsString());
            assertJSON(expectedObject, responseObject);

            return this;
        }

        protected Response isJSONArrayLikeFile(String pathToExpectedJSON) throws Exception {
            isJSON();
            String expectedJSONString = IoUtil.read(fileStream(pathToExpectedJSON));
            JSONArray expectedArray = new JSONArray(expectedJSONString);

            JSONArray responseObject = new JSONArray(contentAsString());
            assertJSON(expectedArray, responseObject);

            return this;
        }

        protected String hasNodeIdentifier() throws Exception {
            JSONObject responseObject = new JSONObject(contentAsString());
            String id = responseObject.getString("id");
            assertNotNull(id);
            assertTrue(id.trim().length() != 0);
            return id;
        }

        protected JSONObject json() throws Exception {
            if (contentJSON == null) {
                contentJSON = new JSONObject(contentAsString());
            }
            return contentJSON;
        }

        protected String contentAsString() {
            if (contentString == null) {
                contentString = new String(content);
            }
            return contentString;
        }

        protected Response hasPrimaryType(String primaryType) throws Exception {
            JSONObject json = json();
            assertTrue("jcr:primary type property not found", json.has(JcrConstants.JCR_PRIMARY_TYPE));
            assertEquals(primaryType, json().getString(JcrConstants.JCR_PRIMARY_TYPE));
            return this;
        }

        protected byte[] contentAsBytes() {
            return content;
        }

        @Override
        public String toString() {
            return contentAsString();
        }
    }
}