Package org.neo4j.smack.test.util

Source Code of org.neo4j.smack.test.util.RESTDocsGenerator$ResponseEntity

package org.neo4j.smack.test.util;

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.File;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import org.neo4j.test.AsciiDocGenerator;
import org.neo4j.test.GraphDefinition;
import org.neo4j.test.TestData.Producer;
import org.neo4j.visualization.asciidoc.AsciidocHelper;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientRequest.Builder;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;

/**
* Generate asciidoc-formatted documentation from HTTP requests and responses.
* The status and media type of all responses is checked as well as the
* existence of any expected headers.
*
* The filename of the resulting ASCIIDOC test file is derived from the title.
*
* The title is determined by either a JavaDoc perioed terminated first title line,
* the @Title annotation or the method name, where "_" is replaced by " ".
*/
public class RESTDocsGenerator extends AsciiDocGenerator
{

    private static final Builder REQUEST_BUILDER = ClientRequest.create();

    private static final List<String> RESPONSE_HEADERS = Arrays.asList( new String[] { "Content-Type", "Location" } );

    private static final List<String> REQUEST_HEADERS = Arrays.asList( new String[] { "Content-Type", "Accept" } );

    public static final Producer<RESTDocsGenerator> PRODUCER = new Producer<RESTDocsGenerator>()
    {
        @Override
        public RESTDocsGenerator create( GraphDefinition graph, String title, String documentation )
        {
            RESTDocsGenerator gen = RESTDocsGenerator.create( title );
            gen.description(documentation);
            return gen;
        }

        @Override
        public void destroy( RESTDocsGenerator product, boolean successful )
        {
            // TODO: invoke some complete method here?
        }
    };

    private int expectedResponseStatus = -1;
    private MediaType expectedMediaType = MediaType.APPLICATION_JSON_TYPE;
    private MediaType payloadMediaType = MediaType.APPLICATION_JSON_TYPE;
    private final List<String> expectedHeaderFields = new ArrayList<String>();
    private String payload;

    /**
     * Creates a documented test case. Finish building it by using one of these:
     * {@link #get(String)}, {@link #post(String)}, {@link #put(String)},
     * {@link #delete(String)}, {@link #request(ClientRequest)}. To access the
     * response, use {@link ResponseEntity#entity} to get the entity or
     * {@link ResponseEntity#response} to get the rest of the response
     * (excluding the entity).
     *
     * @param title title of the test
     */
    public static RESTDocsGenerator create( final String title )
    {
        if ( title == null )
        {
            throw new IllegalArgumentException( "The title can not be null" );
        }
        return new RESTDocsGenerator( title );
    }

    private RESTDocsGenerator( String ti )
    {
        super(ti, "rest-api");
    }
   


    /**
     * Set the expected status of the response. The test will fail if the
     * response has a different status. Defaults to HTTP 200 OK.
     *
     * @param expectedResponseStatus the expected response status
     */
    public RESTDocsGenerator expectedStatus( final int expectedResponseStatus )
    {
        this.expectedResponseStatus = expectedResponseStatus;
        return this;
    }
   
    /**
     * Set the expected status of the response. The test will fail if the
     * response has a different status. Defaults to HTTP 200 OK.
     *
     * @param expectedResponseStatus the expected response status
     */
    public RESTDocsGenerator expectedStatus( final ClientResponse.Status expectedStatus)
    {
        this.expectedResponseStatus = expectedStatus.getStatusCode();
        return this;
    }

    /**
     * Set the expected media type of the response. The test will fail if the
     * response has a different media type. Defaults to application/json.
     *
     * @param expectedMediaType the expected media tyupe
     */
    public RESTDocsGenerator expectedType( final MediaType expectedMediaType )
    {
        this.expectedMediaType = expectedMediaType;
        return this;
    }

    /**
     * The media type of the request payload. Defaults to application/json.
     *
     * @param payloadMediaType the media type to use
     */
    public RESTDocsGenerator payloadType( final MediaType payloadMediaType )
    {
        this.payloadMediaType = payloadMediaType;
        return this;
    }

    /**
     * Set the payload of the request.
     *
     * @param payload the payload
     */
    public RESTDocsGenerator payload( final String payload )
    {
        this.payload = payload;
        return this;
    }
   
   

    /**
     * Add an expected response header. If the heading is missing in the
     * response the test will fail. The header and its value are also included
     * in the documentation.
     *
     * @param expectedHeaderField the expected header
     */
    public RESTDocsGenerator expectedHeader( final String expectedHeaderField )
    {
        this.expectedHeaderFields.add( expectedHeaderField );
        return this;
    }

    /**
     * Send a request using your own request object.
     *
     * @param request the request to perform
     */
    public ResponseEntity request( final ClientRequest request )
    {
        return retrieveResponse( title, description, request.getURI()
                .toString(), expectedResponseStatus, expectedMediaType, expectedHeaderFields, request );
    }
   
    @Override
    public RESTDocsGenerator description( String description )
    {
        return (RESTDocsGenerator) super.description( description );
    }

    /**
     * Send a GET request.
     *
     * @param uri the URI to use.
     */
    public ResponseEntity get( final String uri )
    {
        return retrieveResponseFromRequest( title, description, "GET", uri, expectedResponseStatus, expectedMediaType,
                expectedHeaderFields );
    }

    /**
     * Send a POST request.
     *
     * @param uri the URI to use.
     */
    public ResponseEntity post( final String uri )
    {
        return retrieveResponseFromRequest( title, description, "POST", uri, payload, payloadMediaType,
                expectedResponseStatus, expectedMediaType, expectedHeaderFields );
    }

    /**
     * Send a PUT request.
     *
     * @param uri the URI to use.
     */
    public ResponseEntity put( final String uri )
    {
        return retrieveResponseFromRequest( title, description, "PUT", uri, payload, payloadMediaType,
                expectedResponseStatus, expectedMediaType, expectedHeaderFields );
    }

    /**
     * Send a DELETE request.
     *
     * @param uri the URI to use.
     */
    public ResponseEntity delete( final String uri )
    {
        return retrieveResponseFromRequest( title, description, "DELETE", uri, payload, payloadMediaType,
                expectedResponseStatus, expectedMediaType, expectedHeaderFields );
    }

    /**
     * Send a request with no payload.
     */
    private ResponseEntity retrieveResponseFromRequest( final String title, final String description,
            final String method, final String uri, final int responseCode, final MediaType accept,
            final List<String> headerFields )
    {
        ClientRequest request;
        try
        {
            request = REQUEST_BUILDER.accept( accept )
                    .build( new URI( uri ), method );
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeException( e );
        }
        return retrieveResponse( title, description, uri, responseCode, accept, headerFields, request );
    }

    /**
     * Send a request with payload.
     */
    private ResponseEntity retrieveResponseFromRequest( final String title, final String description,
            final String method, final String uri, final String payload, final MediaType payloadType,
            final int responseCode, final MediaType accept, final List<String> headerFields )
    {
        ClientRequest request;
        try
        {
            if ( payload != null )
            {
                request = REQUEST_BUILDER.type( payloadType )
                        .accept( accept )
                        .entity( payload )
                        .build( new URI( uri ), method );
            }
            else
            {
                request = REQUEST_BUILDER.accept( accept )
                        .build( new URI( uri ), method );
            }
        }
        catch ( URISyntaxException e )
        {
            throw new RuntimeException( e );
        }
        return retrieveResponse( title, description, uri, responseCode, accept, headerFields, request );
    }

    /**
     * Send the request and create the documentation.
     */
    private ResponseEntity retrieveResponse( final String title, final String description, final String uri,
            final int responseCode, final MediaType type, final List<String> headerFields, final ClientRequest request )
    {
        DocumentationData data = new DocumentationData();
        getRequestHeaders( data, request.getHeaders() );
        if ( request.getEntity() != null )
        {
            data.setPayload( String.valueOf( request.getEntity() ) );
        }
        Client client = new Client();
        ClientResponse response = client.handle( request );
        if ( response.hasEntity() && response.getStatus() != 204 )
        {
            data.setEntity( response.getEntity( String.class ) );
        }
        try {
        } catch (UniformInterfaceException uie) {
            //ok
        }
        if ( response.getType() != null )
        {
            assertTrue( "wrong response type: "+ data.entity, response.getType().isCompatible( type ) );
        }
        for ( String headerField : headerFields )
        {
            assertNotNull( "wrong headers: "+ data.entity, response.getHeaders()
                    .get( headerField ) );
        }
        data.setTitle( title );
        data.setDescription( description );
        data.setMethod( request.getMethod() );
        data.setUri( uri );
        data.setStatus( responseCode );
        assertEquals( "Wrong response status. response: " + data.entity, responseCode, response.getStatus() );
        getResponseHeaders( data, response.getHeaders(), headerFields );
        document( data );
        return new ResponseEntity( response, data.entity );
    }

    private void getResponseHeaders( final DocumentationData data, final MultivaluedMap<String, String> headers,
            final List<String> additionalFilter )
    {
        data.setResponseHeaders( getHeaders( headers, RESPONSE_HEADERS, additionalFilter ) );
    }

    private void getRequestHeaders( final DocumentationData data, final MultivaluedMap<String, Object> headers )
    {
        data.setRequestHeaders( getHeaders( headers, REQUEST_HEADERS, Collections.<String>emptyList() ) );
    }

    private <T> Map<String, String> getHeaders( final MultivaluedMap<String, T> headers, final List<String> filter,
            final List<String> additionalFilter )
    {
        Map<String, String> filteredHeaders = new TreeMap<String, String>();
        for ( Entry<String, List<T>> header : headers.entrySet() )
        {
            if ( filter.contains( header.getKey() ) || additionalFilter.contains( header.getKey() ) )
            {
                String values = "";
                for ( T value : header.getValue() )
                {
                    if ( !values.isEmpty() )
                    {
                        values += ", ";
                    }
                    values += String.valueOf( value );
                }
                filteredHeaders.put( header.getKey(), values );
            }
        }
        return filteredHeaders;
    }

    /**
     * Wraps a response, to give access to the response entity as well.
     */
    public static class ResponseEntity
    {
        private final String entity;
        private final JaxRsResponse response;

        public ResponseEntity( ClientResponse response, String entity )
        {
            this.response = new JaxRsResponse(response,entity);
            this.entity = entity;
        }

        /**
         * The response entity as a String.
         */
        public String entity()
        {
            return entity;
        }

        /**
         * Note that the response object returned does not give access to the
         * response entity.
         */
        public JaxRsResponse response()
        {
            return response;
        }
    }

    private class DocumentationData
    {
        public String payload;
        public String title;
        public String description;
        public String uri;
        public String method;
        public int status;
        public String entity;
        public Map<String, String> requestHeaders;
        public Map<String, String> responseHeaders;

        public void setPayload( final String payload )
        {
            this.payload = payload;
        }

        public void setDescription( final String description )
        {
            this.description = description;
        }

        public void setTitle( final String title )
        {
            this.title = title;
        }
       

        public void setUri( final String uri )
        {
            this.uri = uri;
        }

        public void setMethod( final String method )
        {
            this.method = method;
        }

        public void setStatus( final int responseCode )
        {
            this.status = responseCode;

        }

        public void setEntity( final String entity )
        {
            this.entity = entity;
        }

        public void setResponseHeaders( final Map<String, String> response )
        {
            responseHeaders = response;
        }

        public void setRequestHeaders( final Map<String, String> request )
        {
            requestHeaders = request;
        }

        @Override
        public String toString()
        {
            return "DocumentationData [payload=" + payload + ", title=" + title + ", description=" + description
                   + ", uri=" + uri + ", method=" + method + ", status=" + status + ", entity=" + entity
                   + ", requestHeaders=" + requestHeaders + ", responseHeaders=" + responseHeaders + "]";
        }
    }

    protected void document( final DocumentationData data )
    {
        data.description = replaceSnippets( data.description );
        Writer fw = null;
        try
        {
            fw = getFW("target" + File.separator + "docs"+ File.separator + section , data.title);
            String name = title.replace( " ", "-" )
                    .toLowerCase();
            line( fw, "[["+section.replaceAll( "\\(|\\)", "" )+"-" + name.replaceAll( "\\(|\\)", "" ) + "]]" );
            //make first Character uppercase
            String firstChar = data.title.substring0, 1 ).toUpperCase();
            line( fw, "=== " + firstChar + data.title.substring( 1 ) + " ===" );
            line( fw, "" );
            if ( data.description != null && !data.description.isEmpty() )
            {
                line( fw, data.description );
                line( fw, "" );
            }
            if( graph != null) {
                fw.append( AsciidocHelper.createGraphViz( "Final Graph", graph, title));
                line(fw, "" );
            }
            line( fw, "_Example request_" );
            line( fw, "" );
            line( fw, "* *+" + data.method + "+*  +" + data.uri + "+" );
            if ( data.requestHeaders != null )
            {
                for ( Entry<String, String> header : data.requestHeaders.entrySet() )
                {
                    line( fw, "* *+" + header.getKey() + ":+* +" + header.getValue() + "+" );
                }
            }
            writeEntity( fw, data.payload );
            line( fw, "" );
            line( fw, "_Example response_" );
            line( fw, "" );
            line( fw, "* *+" + data.status + ":+* +" + Response.Status.fromStatusCode( data.status )
                    + "+" );
            if ( data.responseHeaders != null )
            {
                for ( Entry<String, String> header : data.responseHeaders.entrySet() )
                {
                    line( fw, "* *+" + header.getKey() + ":+* +" + header.getValue() + "+" );
                }
            }
            writeEntity( fw, data.entity );
            line( fw, "" );
        }
        catch ( IOException e )
        {
            e.printStackTrace();
            fail();
        }
        finally
        {
            if ( fw != null )
            {
                try
                {
                    fw.close();
                }
                catch ( IOException e )
                {
                    e.printStackTrace();
                    fail();
                }
            }
        }
    }

    public void writeEntity( final Writer fw, final String entity ) throws IOException
    {
        if ( entity != null )
        {
            line( fw, "[source,javascript]" );
            line( fw, "----" );
            line( fw, entity );
            line( fw, "----" );
            line( fw, "" );
        }
    }

   
  

}
TOP

Related Classes of org.neo4j.smack.test.util.RESTDocsGenerator$ResponseEntity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
script>