eu.fusepool.p3.proxy.ProxyTest.java Source code

Java tutorial

Introduction

Here is the source code for eu.fusepool.p3.proxy.ProxyTest.java

Source

/*
 * Copyright 2014 reto.
 *
 * 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 eu.fusepool.p3.proxy;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.jayway.restassured.RestAssured;
import eu.fusepool.p3.transformer.AsyncTransformer;
import eu.fusepool.p3.transformer.HttpRequestEntity;
import eu.fusepool.p3.transformer.SyncTransformer;
import eu.fusepool.p3.transformer.Transformer;
import eu.fusepool.p3.transformer.commons.Entity;
import eu.fusepool.p3.transformer.commons.util.InputStreamEntity;
import eu.fusepool.p3.transformer.sample.LongRunningTransformer;
import eu.fusepool.p3.transformer.server.TransformerServer;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import org.apache.http.HttpStatus;
import org.eclipse.jetty.server.Server;
import org.hamcrest.core.IsEqual;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;

/**
 *
 * @author reto
 */
public class ProxyTest {

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(backendPort);
    //TODO choose free port instead
    private static final int backendPort = findFreePort();
    private int transformerPort = backendPort + 1;
    private static int proxyPort = 8080;
    static Server server;
    public int longRunningSeconds = 50;

    @BeforeClass
    public static void startProxy() throws Exception {
        proxyPort = findFreePort();
        Assert.assertNotEquals("the assignment of different ports went wrong", backendPort, proxyPort);
        server = new Server(proxyPort);
        server.setHandler(new ProxyHandler("http://localhost:" + backendPort));
        server.start();
        RestAssured.baseURI = "http://localhost:" + proxyPort + "/";
    }

    @AfterClass
    public static void stopProxy() throws Exception {
        server.stop();
    }

    @Test
    public void nonTransformingContainer() throws Exception {

        final String turtleLdpc = "@prefix dcterms: <http://purl.org/dc/terms/>.\n"
                + "@prefix ldp: <http://www.w3.org/ns/ldp#>.\n"
                + "@prefix eldp: <http://vocab.fusepool.info/eldp#>.\n" + "\n"
                + "<http://example.org/container1/>\n" + "   a ldp:DirectContainer;\n"
                + "   dcterms:title \"An extracting LDP Container using simple-transformer\";\n"
                + "   ldp:membershipResource <http://example.org/container1/>;\n"
                + "   ldp:hasMemberRelation ldp:member;\n" + "   ldp:insertedContentRelation ldp:MemberSubject.";

        stubFor(get(urlEqualTo("/my/resource")).withHeader("Accept", equalTo("text/turtle")).willReturn(
                aResponse().withStatus(200).withHeader("Content-Type", "text/turtle").withBody(turtleLdpc)));

        RestAssured.given().header("Accept", "text/turtle").expect().statusCode(HttpStatus.SC_OK)
                .header("Content-Type", "text/turtle").body(new IsEqual(turtleLdpc)).when().get("/my/resource");

    }

    @Test
    public void transformingContainer() throws Exception {

        final String turtleLdpc = "@prefix dcterms: <http://purl.org/dc/terms/>.\n"
                + "@prefix ldp: <http://www.w3.org/ns/ldp#>.\n"
                + "@prefix eldp: <http://vocab.fusepool.info/eldp#>.\n" + "\n" + "<http://localhost:" + proxyPort
                + "/container1/>\n" + "   a ldp:DirectContainer;\n"
                + "   dcterms:title \"An extracting LDP Container using simple-transformer\";\n"
                + "   ldp:membershipResource <http://localhost:" + proxyPort + "/container1/>;\n"
                + "   ldp:hasMemberRelation ldp:member;\n" + "   ldp:insertedContentRelation ldp:MemberSubject;\n"
                + "   eldp:transformer <http://localhost:" + backendPort + "/simple-transformer>.";

        final String turtleTransformer = "@prefix dct: <http://purl.org/dc/terms/>.\n"
                + "@prefix trans: <http://vocab.fusepool.info/transformer#>.\n"
                + "<http://example.org/simple-transformer> a trans:Transformer;\n"
                + "    dct:title \"A simple RDF Transformation\"@en;\n"
                + "    dct:description \"transforms vcards to RDF\";\n"
                + "    trans:supportedInputFormat \"text/vcard\";\n"
                + "    trans:supportedOutputFormat \"text/turtle\";\n"
                + "    trans:supportedOutputFormat \"text/ld+json\".";

        stubFor(get(urlEqualTo("/container1/"))
                //.withHeader("Accept", equalTo("text/turtle"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_OK).withHeader("Content-Type", "text/turtle")
                        .withBody(turtleLdpc)));

        stubFor(post(urlEqualTo("/container1/"))
                //.withHeader("Conetnt-Type", matching("text/plain*"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_CREATED).withHeader("Location",
                        "http://localhost:" + proxyPort + "/container1/new-resource")));

        stubFor(get(urlEqualTo("/simple-transformer"))
                //.withHeader("Accept", equalTo("text/turtle"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_OK).withHeader("Content-Type", "text/turtle")
                        .withBody(turtleTransformer)));

        stubFor(post(urlEqualTo("/simple-transformer"))
                //.withHeader("Accept", equalTo("text/turtle"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_OK).withHeader("Content-Type", "text/plain")
                        .withBody("I am transformed")));

        //A GET request returns the unmodified answer
        RestAssured.given().header("Accept", "text/turtle").expect().statusCode(HttpStatus.SC_OK)
                .header("Content-Type", "text/turtle").when().get("/container1/");
        //Certainly the backend got the request
        verify(getRequestedFor(urlMatching("/container1/")));

        //Let's post some content
        RestAssured.given().contentType("text/plain;charset=UTF-8").header("Authorization", "foobar")
                .content("hello").expect().statusCode(HttpStatus.SC_CREATED).when().post("/container1/");
        //the backend got the post request aiaginst the LDPC
        verify(postRequestedFor(urlMatching("/container1/")).withHeader("Authorization", equalTo("foobar")));
        //and after a while also against the Transformer
        //first the transformer whould be checcked if the format matches
        //wait and try: verify(getRequestedFor(urlMatching("/simple-transformer")));
        //then we will get a POST (since media type is supported)
        int i = 0;
        while (true) {
            Thread.sleep(100);
            try {
                verify(postRequestedFor(urlMatching("/simple-transformer")));
                break;
            } catch (Error e) {

            }
            if (i++ > 600) {
                //after one minute for real:
                verify(postRequestedFor(urlMatching("/simple-transformer")));
            }
        }
        i = 0;
        while (true) {
            try {
                verify(2, postRequestedFor(urlMatching("/container1/")).withHeader("Authorization",
                        equalTo("foobar")));
                break;
            } catch (Error e) {

            }
            Thread.sleep(100);
            if (i++ > 600) {
                //after one minute for real:
                verify(2, postRequestedFor(urlMatching("/container1/")).withHeader("Authorization",
                        equalTo("foobar")));
            }
        }

    }

    @Test
    public void longRunningTransformer() throws Exception {

        TransformerServer transformerServer = new TransformerServer(transformerPort, false);
        final boolean[] transformerInvoked = new boolean[1];
        transformerServer.start(new SyncTransformer() {

            @Override
            public Entity transform(HttpRequestEntity hre) throws IOException {
                transformerInvoked[0] = true;
                try {
                    Thread.sleep(longRunningSeconds * 1000);
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
                return new InputStreamEntity() {

                    @Override
                    public MimeType getType() {
                        try {
                            return new MimeType("text/plain");
                        } catch (MimeTypeParseException ex) {
                            throw new RuntimeException(ex);
                        }
                    }

                    @Override
                    public InputStream getData() throws IOException {
                        return new ByteArrayInputStream("Tranformed".getBytes());
                    }
                };
            }

            @Override
            public boolean isLongRunning() {
                return true;
            }

            @Override
            public Set<MimeType> getSupportedInputFormats() {
                try {
                    return Collections.singleton(new MimeType("text/plain"));
                } catch (MimeTypeParseException ex) {
                    throw new RuntimeException(ex);
                }
            }

            @Override
            public Set<MimeType> getSupportedOutputFormats() {
                try {
                    return Collections.singleton(new MimeType("text/plain"));
                } catch (MimeTypeParseException ex) {
                    throw new RuntimeException(ex);
                }
            }

        });

        final String turtleLdpc = "@prefix dcterms: <http://purl.org/dc/terms/>.\n"
                + "@prefix ldp: <http://www.w3.org/ns/ldp#>.\n"
                + "@prefix eldp: <http://vocab.fusepool.info/eldp#>.\n" + "\n" + "<http://localhost:" + proxyPort
                + "/container2/>\n" + "   a ldp:DirectContainer;\n"
                + "   dcterms:title \"An extracting LDP Container using simple-transformer\";\n"
                + "   ldp:membershipResource <http://localhost:" + proxyPort + "/container1/>;\n"
                + "   ldp:hasMemberRelation ldp:member;\n" + "   ldp:insertedContentRelation ldp:MemberSubject;\n"
                + "   eldp:transformer <http://localhost:" + transformerPort + "/long-transformer>.";

        stubFor(get(urlEqualTo("/container2/"))
                //.withHeader("Accept", equalTo("text/turtle"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_OK).withHeader("Content-Type", "text/turtle")
                        .withBody(turtleLdpc)));

        stubFor(post(urlEqualTo("/container2/"))
                //.withHeader("Conetnt-Type", matching("text/plain*"))
                .willReturn(aResponse().withStatus(HttpStatus.SC_CREATED).withHeader("Location",
                        "http://localhost:" + proxyPort + "/container2/new-resource")));

        //A GET request returns the unmodified answer
        RestAssured.given().header("Accept", "text/turtle").expect().statusCode(HttpStatus.SC_OK)
                .header("Content-Type", "text/turtle").when().get("/container2/");
        //Certainly the backend got the request
        verify(getRequestedFor(urlMatching("/container2/")));

        //Let's post some content
        RestAssured.given().contentType("text/plain;charset=UTF-8").header("Authorization", "foobar")
                .content("hello").expect().statusCode(HttpStatus.SC_CREATED).when().post("/container2/");
        //the backend got the post request aiaginst the LDPC
        verify(postRequestedFor(urlMatching("/container2/")).withHeader("Authorization", equalTo("foobar")));
        //and after a while also against the Transformer
        //first the transformer whould be checcked if the format matches
        //wait and try: verify(getRequestedFor(urlMatching("/simple-transformer")));
        //then we will get a POST (since media type is supported)
        int i = 0;
        while (true) {
            Thread.sleep(100);
            try {
                Assert.assertTrue(transformerInvoked[0]);
                break;
            } catch (Error e) {

            }
            if (i++ > 600) {
                //after one minute for real:
                Assert.assertTrue(transformerInvoked[0]);
            }
        }
        Thread.sleep(longRunningSeconds * 1000);
        i = 0;
        while (true) {
            try {
                verify(2, postRequestedFor(urlMatching("/container2/")).withHeader("Authorization",
                        equalTo("foobar")));
                break;
            } catch (Error e) {

            }
            Thread.sleep(100);
            if (i++ > 1200) {
                //after two minute for real (two minutes is the maximum polling interval of the transformer client)
                verify(2, postRequestedFor(urlMatching("/container2/")).withHeader("Authorization",
                        equalTo("foobar")));
            }
        }

    }

    public static int findFreePort() {
        int port = 0;
        try (ServerSocket server = new ServerSocket(0);) {
            port = server.getLocalPort();
        } catch (Exception e) {
            throw new RuntimeException("unable to find a free port");
        }
        return port;
    }

}