org.wisdom.framework.vertx.ServerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.wisdom.framework.vertx.ServerTest.java

Source

/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2015 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.framework.vertx;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.wisdom.api.Controller;
import org.wisdom.api.DefaultController;
import org.wisdom.api.configuration.ApplicationConfiguration;
import org.wisdom.api.content.ContentEngine;
import org.wisdom.api.exceptions.ExceptionMapper;
import org.wisdom.api.http.HttpMethod;
import org.wisdom.api.http.Request;
import org.wisdom.api.http.Result;
import org.wisdom.api.http.Status;
import org.wisdom.api.router.Route;
import org.wisdom.api.router.RouteBuilder;
import org.wisdom.api.router.Router;
import org.wisdom.test.parents.FakeConfiguration;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Collections;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;

/**
 * Check the behavior of the {@link Server}.
 */
public class ServerTest extends VertxBaseTest {

    private WisdomVertxServer wisdom;
    private ApplicationConfiguration application;
    private Router router;

    @Before
    public void setUp() {
        wisdom = new WisdomVertxServer();

        application = mock(ApplicationConfiguration.class);
        when(application.getIntegerWithDefault(eq("vertx.http.port"), anyInt())).thenReturn(0);
        when(application.getIntegerWithDefault(eq("vertx.https.port"), anyInt())).thenReturn(0);
        when(application.getIntegerWithDefault("vertx.acceptBacklog", -1)).thenReturn(-1);
        when(application.getIntegerWithDefault("vertx.receiveBufferSize", -1)).thenReturn(-1);
        when(application.getIntegerWithDefault("vertx.sendBufferSize", -1)).thenReturn(-1);
        when(application.getStringArray("wisdom.websocket.subprotocols")).thenReturn(new String[0]);
        when(application.getStringArray("vertx.websocket-subprotocols")).thenReturn(new String[0]);
        when(application.getBaseDir()).thenReturn(new File("target/junk/server/conf"));
        wisdom.configuration = application;
        wisdom.vertx = vertx;

        router = mock(Router.class);

        ContentEngine contentEngine = mock(ContentEngine.class);

        wisdom.accessor = new ServiceAccessor(null, application, router, contentEngine, null, null,
                Collections.<ExceptionMapper>emptyList());
    }

    @After
    public void tearDown() {
        if (wisdom != null) {
            wisdom.stop();
        }
    }

    @Test
    public void testCreationFromConfiguration() throws InterruptedException {
        FakeConfiguration configuration = new FakeConfiguration(ImmutableMap.<String, Object>builder()
                .put("port", 0).put("ssl", true).put("authentication", true).build());

        when(application.getConfiguration("vertx.servers"))
                .thenReturn(new FakeConfiguration(Collections.<String, Object>emptyMap()));

        Server server = Server.from(wisdom.accessor, vertx, "test", configuration);
        wisdom.servers.add(server);
        wisdom.start();
        waitForHttpsStart(wisdom);

        assertThat(server.port()).isNotEqualTo(-1).isNotEqualTo(0);
        assertThat(server.ssl()).isTrue();

        assertThat(server.accept("/foo")).isTrue();
    }

    /**
     * This methods checks HTTP, HTTPS and HTTPS with Mutual Authentication.
     */
    @Test
    public void testCreationOfThreeServersFromConfiguration()
            throws InterruptedException, IOException, KeyStoreException, CertificateException,
            NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException {
        FakeConfiguration s1 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", false).put("authentication", false).build());

        FakeConfiguration s2 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", true).put("authentication", false).build());

        FakeConfiguration s3 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", true).put("authentication", true).build());

        // Server HTTPS
        File root = new File("");
        final File serverKeyStore = new File(
                root.getAbsolutePath() + "/src/test/resources/keystore/server/server.jks");
        assertThat(serverKeyStore).isFile();
        when(application.get("https.keyStore")).thenReturn(serverKeyStore.getAbsolutePath());
        when(application.get("https.trustStore"))
                .thenReturn(new File(root.getAbsolutePath() + "/src/test/resources/keystore/server/server.jks")
                        .getAbsolutePath());
        when(application.getWithDefault("https.keyStoreType", "JKS")).thenReturn("JKS");
        when(application.getWithDefault("https.trustStoreType", "JKS")).thenReturn("JKS");
        when(application.getWithDefault("https.keyStorePassword", "")).thenReturn("wisdom");
        when(application.getWithDefault("https.trustStorePassword", "")).thenReturn("wisdom");

        when(application.getWithDefault("https.keyStoreAlgorithm", KeyManagerFactory.getDefaultAlgorithm()))
                .thenReturn(KeyManagerFactory.getDefaultAlgorithm());
        when(application.getWithDefault("https.trustStoreAlgorithm", KeyManagerFactory.getDefaultAlgorithm()))
                .thenReturn(KeyManagerFactory.getDefaultAlgorithm());
        when(application.getConfiguration("vertx.servers"))
                .thenReturn(new FakeConfiguration(ImmutableMap.<String, Object>of("s1", s1, "s2", s2, "s3", s3)));

        Controller controller = new DefaultController() {
            @SuppressWarnings("unused")
            public Result index() {
                return ok("Alright");
            }
        };
        Route route = new RouteBuilder().route(HttpMethod.GET).on("/").to(controller, "index");
        when(router.getRouteFor(anyString(), anyString(), any(Request.class))).thenReturn(route);

        wisdom.start();
        waitForStart(wisdom);
        waitForHttpsStart(wisdom);

        assertThat(wisdom.servers).hasSize(3);

        // Check rendering
        for (Server server : wisdom.servers) {
            String r;
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            FileInputStream instream = new FileInputStream("src/test/resources/keystore/client/client1.jks");
            trustStore.load(instream, "wisdom".toCharArray());

            // Trust own CA and all self-signed certs
            SSLContext sslcontext = SSLContexts.custom()
                    .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                    .loadKeyMaterial(trustStore, "wisdom".toCharArray()).build();

            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
                    new String[] { "TLSv1", "SSLv3" }, null,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

            if (server.ssl()) {
                HttpGet httpget = new HttpGet("https://localhost:" + server.port());
                final CloseableHttpResponse response = httpclient.execute(httpget);
                r = EntityUtils.toString(response.getEntity());
            } else {
                r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port()).execute()
                        .returnContent().asString();
            }

            assertThat(r).isEqualToIgnoringCase("Alright");
        }
    }

    @Test
    public void testAllow() throws InterruptedException, IOException, KeyStoreException, CertificateException,
            NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException {
        FakeConfiguration s1 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", false).put("authentication", false).put("allow", ImmutableList.of("/foo*")).build());

        FakeConfiguration s2 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", false).put("authentication", false).put("allow", ImmutableList.of("/bar*")).build());

        when(application.getConfiguration("vertx.servers"))
                .thenReturn(new FakeConfiguration(ImmutableMap.<String, Object>of("s1", s1, "s2", s2)));
        Controller controller = new DefaultController() {
            @SuppressWarnings("unused")
            public Result index() {
                return ok("Alright");
            }
        };
        final Route route1 = new RouteBuilder().route(HttpMethod.GET).on("/foo").to(controller, "index");
        final Route route2 = new RouteBuilder().route(HttpMethod.GET).on("/bar").to(controller, "index");
        doAnswer(new Answer<Route>() {
            @Override
            public Route answer(InvocationOnMock mock) throws Throwable {
                String url = (String) mock.getArguments()[1];
                if (url.equals("/foo")) {
                    return route1;
                }
                if (url.equals("/bar")) {
                    return route2;
                }
                return null;
            }
        }).when(router).getRouteFor(anyString(), anyString(), any(Request.class));

        wisdom.start();
        waitForStart(wisdom);

        assertThat(wisdom.servers).hasSize(2);
        for (Server server : wisdom.servers) {
            if (server.name().equalsIgnoreCase("s1")) {
                // Accept /foo, Deny /bar
                HttpResponse r = org.apache.http.client.fluent.Request
                        .Get("http://localhost:" + server.port() + "/foo").execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);
                EntityUtils.consumeQuietly(r.getEntity());
                r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/bar")
                        .execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.FORBIDDEN);
                EntityUtils.consumeQuietly(r.getEntity());
            } else {
                // Accept /foo, Deny /bar
                HttpResponse r = org.apache.http.client.fluent.Request
                        .Get("http://localhost:" + server.port() + "/bar").execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);
                EntityUtils.consumeQuietly(r.getEntity());
                r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/foo")
                        .execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.FORBIDDEN);
                EntityUtils.consumeQuietly(r.getEntity());
            }
        }
    }

    @Test
    public void testDeny() throws InterruptedException, IOException, KeyStoreException, CertificateException,
            NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException {
        FakeConfiguration s1 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", false).put("authentication", false).put("deny", ImmutableList.of("/bar*")).build());

        FakeConfiguration s2 = new FakeConfiguration(ImmutableMap.<String, Object>builder().put("port", 0)
                .put("ssl", false).put("authentication", false).put("deny", ImmutableList.of("/foo*")).build());

        when(application.getConfiguration("vertx.servers"))
                .thenReturn(new FakeConfiguration(ImmutableMap.<String, Object>of("s1", s1, "s2", s2)));

        Controller controller = new DefaultController() {
            @SuppressWarnings("unused")
            public Result index() {
                return ok("Alright");
            }
        };
        final Route route1 = new RouteBuilder().route(HttpMethod.GET).on("/foo").to(controller, "index");
        final Route route2 = new RouteBuilder().route(HttpMethod.GET).on("/bar").to(controller, "index");
        doAnswer(new Answer<Route>() {
            @Override
            public Route answer(InvocationOnMock mock) throws Throwable {
                String url = (String) mock.getArguments()[1];
                if (url.equals("/foo")) {
                    return route1;
                }
                if (url.equals("/bar")) {
                    return route2;
                }
                return null;
            }
        }).when(router).getRouteFor(anyString(), anyString(), any(Request.class));

        wisdom.start();
        waitForStart(wisdom);

        assertThat(wisdom.servers).hasSize(2);
        for (Server server : wisdom.servers) {
            if (server.name().equalsIgnoreCase("s1")) {
                // Accept /foo, Deny /bar
                HttpResponse r = org.apache.http.client.fluent.Request
                        .Get("http://localhost:" + server.port() + "/foo").execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);
                EntityUtils.consumeQuietly(r.getEntity());
                r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/bar")
                        .execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.FORBIDDEN);
                EntityUtils.consumeQuietly(r.getEntity());
            } else {
                // Accept /foo, Deny /bar
                HttpResponse r = org.apache.http.client.fluent.Request
                        .Get("http://localhost:" + server.port() + "/bar").execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);
                EntityUtils.consumeQuietly(r.getEntity());
                r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/foo")
                        .execute().returnResponse();
                assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.FORBIDDEN);
                EntityUtils.consumeQuietly(r.getEntity());
            }
        }
    }

    @Test
    public void testDenyWithRedirect() throws InterruptedException, IOException, KeyStoreException,
            CertificateException, NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException {
        FakeConfiguration s1 = new FakeConfiguration(
                ImmutableMap.<String, Object>builder().put("port", 0).put("ssl", false).put("authentication", false)
                        .put("deny", ImmutableList.of("/bar*")).put("onDenied", "/foo").build());

        when(application.getConfiguration("vertx.servers"))
                .thenReturn(new FakeConfiguration(ImmutableMap.<String, Object>of("s1", s1)));

        Controller controller = new DefaultController() {
            @SuppressWarnings("unused")
            public Result index() {
                return ok("Alright");
            }

            @SuppressWarnings("unused")
            public Result bar() {
                return ok("bar");
            }
        };
        final Route route1 = new RouteBuilder().route(HttpMethod.GET).on("/foo").to(controller, "index");
        final Route route2 = new RouteBuilder().route(HttpMethod.GET).on("/bar").to(controller, "bar");
        doAnswer(new Answer<Route>() {
            @Override
            public Route answer(InvocationOnMock mock) throws Throwable {
                String url = (String) mock.getArguments()[1];
                if (url.equals("/foo")) {
                    return route1;
                }
                if (url.equals("/bar")) {
                    return route2;
                }
                return null;
            }
        }).when(router).getRouteFor(anyString(), anyString(), any(Request.class));

        wisdom.start();
        waitForStart(wisdom);

        assertThat(wisdom.servers).hasSize(1);
        for (Server server : wisdom.servers) {
            // foo allowed
            HttpResponse r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/foo")
                    .execute().returnResponse();
            assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);

            // bar denied => redirected
            r = org.apache.http.client.fluent.Request.Get("http://localhost:" + server.port() + "/bar").execute()
                    .returnResponse();
            assertThat(r.getStatusLine().getStatusCode()).isEqualTo(Status.OK);
            assertThat(EntityUtils.toString(r.getEntity())).contains("Alright");
        }
    }

}