io.ventu.rpc.integration.rest.TestRestInvocationRoundtrip.java Source code

Java tutorial

Introduction

Here is the source code for io.ventu.rpc.integration.rest.TestRestInvocationRoundtrip.java

Source

/*
 * Copyright (c) 2015-2016. Ventu.io, Oleg Sklyar and contributors, distributed under the MIT license.
 */

package io.ventu.rpc.integration.rest;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.ventu.rpc.RemoteInvoker;
import io.ventu.rpc.exception.ApiException;
import io.ventu.rpc.exception.EncodingException;
import io.ventu.rpc.rest.HttpRestInvoker;
import io.ventu.rpc.rest.exception.HttpException;
import io.ventu.rpc.util.Validator;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

/**
 * The tests is explicitly put into a different package from the implementation to test the client
 * under "real-life" conditions.
 */
public class TestRestInvocationRoundtrip {

    @Rule
    public ExpectedException exception = ExpectedException.none();

    private static Vertx vertx = Vertx.vertx();
    private static HttpServer server;

    public static class Req {
        public int value;

        protected Req() {
        }

        public Req(int value) {
            this.value = value;
        }
    }

    public static class Res {
        public int value;

        protected Res() {
        }

        public Res(int value) {
            this.value = value;
        }
    }

    public static class Unsupported {
        public int value;

        protected Unsupported() {
        }

        public Unsupported(int value) {
            this.value = value;
        }
    }

    public static class Invalid {
        protected int value;

        public Invalid(int value) {
            this.value = value;
        }
    }

    @BeforeClass
    public static void init() throws InterruptedException {
        server = vertx.createHttpServer();
        server.requestHandler(request -> {
            HttpServerResponse response = request.response();
            try {
                if (!"123".equals(request.headers().get("APIKEY"))) {
                    response.setStatusCode(401).end();
                    return;
                }
                Object res;
                if (request.uri().endsWith("Unsupported")) {
                    res = new Invalid(123);
                } else {
                    res = new Res(29);
                }
                response.putHeader("Content-type", "application/json")
                        .end(new ObjectMapper().writeValueAsString(res));
            } catch (JsonProcessingException ex) {
                response.setStatusCode(500).end();
            }
        });
        server.listen(23332);
        Thread.sleep(500);
    }

    @AfterClass
    public static void teardown() {
        server.close();
    }

    @Test
    public void invoke_basicRoundtrip_success() throws InterruptedException, TimeoutException, ExecutionException {
        RemoteInvoker invoker = HttpRestInvoker.host("localhost").port(23332).ssl(false).header("APIKEY", "123")
                .build();

        try {
            CompletableFuture<Res> future = invoker.invoke(new Req(25), Res.class);
            Res res = future.get(500, TimeUnit.MILLISECONDS);
            assertEquals(29, res.value);
        } finally {
            invoker.close().get(500, TimeUnit.MILLISECONDS);
        }
    }

    @Test
    public void invoke_basicRoundtrip_server401_error()
            throws InterruptedException, TimeoutException, ExecutionException {
        RemoteInvoker invoker = HttpRestInvoker.host("localhost").port(23332).ssl(false).build();

        try {
            CompletableFuture<Res> future = invoker.invoke(new Req(25), Res.class);
            exception.expect(ExecutionException.class);
            future.get(500, TimeUnit.MILLISECONDS);
        } catch (ExecutionException ex) {
            HttpException cause = (HttpException) ex.getCause();
            assertEquals(401, cause.getStatusCode());
            throw ex;
        } finally {
            invoker.close().get(500, TimeUnit.MILLISECONDS);
        }
    }

    @Test
    public void invoke_basicRoundtrip_server500_error()
            throws InterruptedException, TimeoutException, ExecutionException {
        RemoteInvoker invoker = HttpRestInvoker.host("localhost").port(23332).header("APIKEY", "123").ssl(false)
                .build();

        try {
            CompletableFuture<Res> future = invoker.invoke(new Unsupported(25), Res.class);
            exception.expect(ExecutionException.class);
            future.get(500, TimeUnit.MILLISECONDS);
        } catch (ExecutionException ex) {
            HttpException cause = (HttpException) ex.getCause();
            assertEquals(500, cause.getStatusCode());
            throw ex;
        } finally {
            invoker.close().get(500, TimeUnit.MILLISECONDS);
        }
    }

    @Test
    public void invoke_basicRoundtrip_responseValidator_error()
            throws InterruptedException, TimeoutException, ExecutionException {
        RemoteInvoker invoker = HttpRestInvoker.host("localhost").port(23332).header("APIKEY", "123").ssl(false)
                .responseValidator(new Validator() {
                    @Override
                    public <RS> void validate(RS value) throws ApiException, IllegalArgumentException {
                        throw new ApiException("boom");
                    }
                }).build();

        try {
            CompletableFuture<Res> future = invoker.invoke(new Req(25), Res.class);
            exception.expect(ExecutionException.class);
            future.get(500, TimeUnit.MILLISECONDS);
        } catch (ExecutionException ex) {
            ApiException cause = (ApiException) ex.getCause();
            assertEquals("boom", cause.getMessage());
            throw ex;
        } finally {
            invoker.close().get(500, TimeUnit.MILLISECONDS);
        }
    }

    @Test
    public void invoke_invalidRequest_error() throws InterruptedException, TimeoutException, ExecutionException {
        RemoteInvoker invoker = HttpRestInvoker.host("localhost").port(23332).ssl(false).build();

        try {
            CompletableFuture<Res> future = invoker.invoke(new Invalid(25), Res.class);
            exception.expect(ExecutionException.class);
            future.get(500, TimeUnit.MILLISECONDS);
        } catch (ExecutionException ex) {
            EncodingException cause = (EncodingException) ex.getCause();
            assertEquals(
                    "Failed to encode JSON: No serializer found for class io.ventu.rpc.integration.rest.TestRestInvocationRoundtrip$Invalid and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )",
                    cause.getMessage());
            throw ex;
        } finally {
            invoker.close().get(500, TimeUnit.MILLISECONDS);
        }
    }
}