org.r358.poolnetty.test.funcobs.AsyncLeaseTest.java Source code

Java tutorial

Introduction

Here is the source code for org.r358.poolnetty.test.funcobs.AsyncLeaseTest.java

Source

/*
 * Copyright (c) 2014 R358 https://github.com/R358
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.r358.poolnetty.test.funcobs;

import org.r358.poolnetty.common.*;
import org.r358.poolnetty.common.exceptions.PoolProviderException;
import org.r358.poolnetty.pool.NettyConnectionPool;
import org.r358.poolnetty.pool.NettyConnectionPoolBuilder;
import org.r358.poolnetty.test.simpleserver.SimpleInboundHandler;
import org.r358.poolnetty.test.simpleserver.SimpleOutboundHandler;
import org.r358.poolnetty.test.simpleserver.SimpleServer;
import org.r358.poolnetty.test.simpleserver.SimpleServerListener;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Test Asynchronous behavior on single connection.
 * Uses single connection.
 */
@RunWith(JUnit4.class)
public class AsyncLeaseTest {

    @Test
    public void testWithCallbackListener() throws Exception {
        final CountDownLatch startedLatch = new CountDownLatch(1);
        final CountDownLatch leaseRequestedLatch = new CountDownLatch(1);
        final CountDownLatch leaseGrantedLatch = new CountDownLatch(1);
        final CountDownLatch leaseYieldedLatch = new CountDownLatch(1);
        final CountDownLatch stopLatch = new CountDownLatch(1);
        final CountDownLatch connectionOpenedLatch = new CountDownLatch(1);
        final CountDownLatch connectionClosedLatch = new CountDownLatch(1);

        final AtomicReference<String> messageAtServer = new AtomicReference<>(); // I need to set the message into something!

        final List<Object> listOfUserObjectReports = new ArrayList<>();

        final String originalMessage = "The cat sat on the mat.";

        //
        // Pool listener.
        //
        PoolProviderListener ppl = new PoolProviderListener() {
            @Override
            public void started(PoolProvider provider) {
                startedLatch.countDown();
            }

            @Override
            public void stopped(PoolProvider provider) {
                stopLatch.countDown();
            }

            @Override
            public void leaseRequested(PoolProvider provider, int leaseTime, TimeUnit units, Object userObject) {
                leaseRequestedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".request");
            }

            @Override
            public void leaseGranted(PoolProvider provider, Channel channel, Object userObject) {
                leaseGrantedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".granted");
            }

            @Override
            public void leaseCanceled(PoolProvider provider, Object userObject) {

            }

            @Override
            public void leaseYield(PoolProvider provider, Channel channel, Object userObject) {
                leaseYieldedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".yield");
            }

            @Override
            public void leaseExpired(PoolProvider provider, Channel channel, Object userObject) {

            }

            @Override
            public void connectionClosed(PoolProvider provider, Channel ctx) {
                connectionClosedLatch.countDown();
            }

            @Override
            public void connectionCreated(PoolProvider provider, Channel ctx, boolean immortal) {
                connectionOpenedLatch.countDown();
            }

            @Override
            public void ephemeralReaped(PoolProvider poolProvider, Channel channel) {
                // Not tested here..
            }
        };

        //
        // The simple server side for testing.
        //

        SimpleServer simpleServer = new SimpleServer("127.0.0.1", 1887, 10, new SimpleServerListener() {

            @Override
            public void newConnection(ChannelHandlerContext ctx) {

            }

            @Override
            public void newValue(ChannelHandlerContext ctx, String val) {
                messageAtServer.set(val);
                ctx.writeAndFlush(val);
            }
        });

        simpleServer.start();

        //
        // Build the pool.
        //

        NettyConnectionPoolBuilder ncb = new NettyConnectionPoolBuilder(1, 1, 1);

        final EventLoopGroup elg = new NioEventLoopGroup();

        //
        // Create the boot strap.
        //
        ncb.withBootstrapProvider(new BootstrapProvider() {
            @Override
            public Bootstrap createBootstrap(PoolProvider poolProvider) {
                Bootstrap bs = new Bootstrap();
                bs.group(elg);
                bs.channel(NioSocketChannel.class);
                bs.option(ChannelOption.SO_KEEPALIVE, true);
                bs.option(ChannelOption.AUTO_READ, true);
                return bs;
            }
        });

        //
        // Sets up the connection info and the channel initializer.
        //
        ncb.withConnectionInfoProvider(new ConnectionInfoProvider() {
            @Override
            public ConnectionInfo connectionInfo(PoolProvider poolProvider) {

                return new ConnectionInfo(new InetSocketAddress("127.0.0.1", 1887), null, new ChannelInitializer() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast("decode", new SimpleInboundHandler(10));
                        ch.pipeline().addLast("encode", new SimpleOutboundHandler(10));
                    }
                });

            }
        });

        //
        // Make the pool add listener and start.
        //
        NettyConnectionPool ncp = ncb.build();
        ncp.addListener(ppl);

        ncp.start(0, TimeUnit.SECONDS);

        TestCase.assertTrue("Opening connection..", connectionOpenedLatch.await(5, TimeUnit.SECONDS));
        TestCase.assertTrue("Not started..", startedLatch.await(5, TimeUnit.SECONDS));

        String userObject = "Foo!";

        LeasedChannel ctx = null;

        final CountDownLatch respLatch = new CountDownLatch(1);
        final AtomicReference<String> respValue = new AtomicReference<>();

        //
        // Call with callback / listener.
        //

        ncp.leaseAsync(10, TimeUnit.DAYS, userObject, new LeaseListener() {
            @Override
            public void leaseRequest(boolean success, LeasedChannel channel, Throwable th) {

                //
                // Remember that any mods you make the pipeline when you have leased the channel
                // Will impact the next lease holder.
                //

                channel.pipeline().addLast("_foo_", new ChannelInboundHandlerAdapter() {
                    @Override
                    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                        respValue.set(msg.toString());
                        respLatch.countDown();
                    }
                });

                // Send the message.
                channel.writeAndFlush(originalMessage);

                //
                // Did we get a response back from the server.
                //
                try {
                    TestCase.assertTrue("Echo from server.", respLatch.await(5, TimeUnit.SECONDS));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //
                // Clean it up as a matter of habit.
                //
                channel.pipeline().remove("_foo_");

                //
                // Yield lease.
                //
                try {
                    channel.yield();
                } catch (PoolProviderException e) {
                    e.printStackTrace();
                }

            }
        });

        TestCase.assertTrue("Lease not requested", leaseRequestedLatch.await(5, TimeUnit.SECONDS));
        TestCase.assertTrue("Lease not granted", leaseGrantedLatch.await(5, TimeUnit.SECONDS));

        TestCase.assertTrue("Lease not yielded", leaseYieldedLatch.await(5, TimeUnit.SECONDS));

        ncp.stop(false);

        TestCase.assertTrue("Connection Not Closed.", connectionClosedLatch.await(5, TimeUnit.SECONDS));

        TestCase.assertTrue("Not stopped.", stopLatch.await(5, TimeUnit.SECONDS));

        //
        // Check we got back what we sent etc.
        //
        TestCase.assertEquals(originalMessage, messageAtServer.get());
        TestCase.assertEquals(originalMessage, respValue.get());

        //
        // - Request lease, Lease granted , Lease yielded check order.
        //
        TestCase.assertEquals(3, listOfUserObjectReports.size()); // Should only be 3 reports.

        TestCase.assertEquals(userObject + ".request", listOfUserObjectReports.get(0));
        TestCase.assertEquals(userObject + ".granted", listOfUserObjectReports.get(1));
        TestCase.assertEquals(userObject + ".yield", listOfUserObjectReports.get(2));

        simpleServer.stop();
    }

    @Test
    public void testWithFuture() throws Exception {
        final CountDownLatch startedLatch = new CountDownLatch(1);
        final CountDownLatch leaseRequestedLatch = new CountDownLatch(1);
        final CountDownLatch leaseGrantedLatch = new CountDownLatch(1);
        final CountDownLatch leaseYieldedLatch = new CountDownLatch(1);
        final CountDownLatch stopLatch = new CountDownLatch(1);
        final CountDownLatch connectionOpenedLatch = new CountDownLatch(1);
        final CountDownLatch connectionClosedLatch = new CountDownLatch(1);

        final AtomicReference<String> messageAtServer = new AtomicReference<>(); // I need to set the message into something!

        final List<Object> listOfUserObjectReports = new ArrayList<>();

        final String originalMessage = "The cat sat on the mat.";

        //
        // Pool listener.
        //
        PoolProviderListener ppl = new PoolProviderListener() {
            @Override
            public void started(PoolProvider provider) {
                startedLatch.countDown();
            }

            @Override
            public void stopped(PoolProvider provider) {
                stopLatch.countDown();
            }

            @Override
            public void leaseRequested(PoolProvider provider, int leaseTime, TimeUnit units, Object userObject) {
                leaseRequestedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".request");
            }

            @Override
            public void leaseGranted(PoolProvider provider, Channel channel, Object userObject) {
                leaseGrantedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".granted");
            }

            @Override
            public void leaseCanceled(PoolProvider provider, Object userObject) {

            }

            @Override
            public void leaseYield(PoolProvider provider, Channel channel, Object userObject) {
                leaseYieldedLatch.countDown();
                listOfUserObjectReports.add(userObject.toString() + ".yield");
            }

            @Override
            public void leaseExpired(PoolProvider provider, Channel channel, Object userObject) {

            }

            @Override
            public void connectionClosed(PoolProvider provider, Channel ctx) {
                connectionClosedLatch.countDown();
            }

            @Override
            public void connectionCreated(PoolProvider provider, Channel ctx, boolean immortal) {
                connectionOpenedLatch.countDown();
            }

            @Override
            public void ephemeralReaped(PoolProvider poolProvider, Channel channel) {
                // Not tested here..
            }
        };

        //
        // The simple server side for testing.
        //

        SimpleServer simpleServer = new SimpleServer("127.0.0.1", 1887, 10, new SimpleServerListener() {

            @Override
            public void newConnection(ChannelHandlerContext ctx) {

            }

            @Override
            public void newValue(ChannelHandlerContext ctx, String val) {
                messageAtServer.set(val);
                ctx.writeAndFlush(val);
            }
        });

        simpleServer.start();

        //
        // Build the pool.
        //

        NettyConnectionPoolBuilder ncb = new NettyConnectionPoolBuilder(1, 1, 1);

        final EventLoopGroup elg = new NioEventLoopGroup();

        //
        // Create the boot strap.
        //
        ncb.withBootstrapProvider(new BootstrapProvider() {
            @Override
            public Bootstrap createBootstrap(PoolProvider poolProvider) {
                Bootstrap bs = new Bootstrap();
                bs.group(elg);
                bs.channel(NioSocketChannel.class);
                bs.option(ChannelOption.SO_KEEPALIVE, true);
                bs.option(ChannelOption.AUTO_READ, true);
                return bs;
            }
        });

        //
        // Sets up the connection info and the channel initializer.
        //
        ncb.withConnectionInfoProvider(new ConnectionInfoProvider() {
            @Override
            public ConnectionInfo connectionInfo(PoolProvider poolProvider) {

                return new ConnectionInfo(new InetSocketAddress("127.0.0.1", 1887), null, new ChannelInitializer() {
                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast("decode", new SimpleInboundHandler(10));
                        ch.pipeline().addLast("encode", new SimpleOutboundHandler(10));
                    }
                });

            }
        });

        //
        // Make the pool add listener and start.
        //
        NettyConnectionPool ncp = ncb.build();
        ncp.addListener(ppl);

        ncp.start(0, TimeUnit.SECONDS);
        TestCase.assertTrue("Opening connection..", connectionOpenedLatch.await(5, TimeUnit.SECONDS));
        TestCase.assertTrue("Not started..", startedLatch.await(5, TimeUnit.SECONDS));

        String userObject = "Foo!";

        Future<LeasedChannel> ctxFuture = ncp.leaseAsync(10, TimeUnit.DAYS, userObject);

        LeasedChannel ctx = null;

        ctx = ctxFuture.get(5, TimeUnit.SECONDS);

        //
        // Lease a channel.
        //
        //   Channel ctx = ncp.lease(10, TimeUnit.DAYS, userObject);

        TestCase.assertTrue("Lease not requested", leaseRequestedLatch.await(5, TimeUnit.SECONDS));
        TestCase.assertTrue("Lease not granted", leaseGrantedLatch.await(5, TimeUnit.SECONDS));

        final CountDownLatch respLatch = new CountDownLatch(1);
        final AtomicReference<String> respValue = new AtomicReference<>();

        //
        // Remember that any mods you make the pipeline when you have leased the channel
        // Will impact the next lease holder.
        //

        ctx.pipeline().addLast("_foo_", new ChannelInboundHandlerAdapter() {
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

                respValue.set(msg.toString());
                respLatch.countDown();
            }
        });

        // Send the message.
        ctx.writeAndFlush(originalMessage);

        //
        // Did we get a response back from the server.
        //
        TestCase.assertTrue("Echo from server.", respLatch.await(5, TimeUnit.SECONDS));

        //
        // Clean it up as a matter of habit.
        //
        ctx.pipeline().remove("_foo_");

        //
        // Yield lease.
        //
        ncp.yield(ctx);

        TestCase.assertTrue("Lease not yielded", leaseYieldedLatch.await(5, TimeUnit.SECONDS));

        ncp.stop(false);

        TestCase.assertTrue("Connection Not Closed.", connectionClosedLatch.await(5, TimeUnit.SECONDS));

        TestCase.assertTrue("Not stopped.", stopLatch.await(5, TimeUnit.SECONDS));

        //
        // Check we got back what we sent etc.
        //
        TestCase.assertEquals(originalMessage, messageAtServer.get());
        TestCase.assertEquals(originalMessage, respValue.get());

        //
        // - Request lease, Lease granted , Lease yielded check order.
        //
        TestCase.assertEquals(3, listOfUserObjectReports.size()); // Should only be 3 reports.

        TestCase.assertEquals(userObject + ".request", listOfUserObjectReports.get(0));
        TestCase.assertEquals(userObject + ".granted", listOfUserObjectReports.get(1));
        TestCase.assertEquals(userObject + ".yield", listOfUserObjectReports.get(2));

        simpleServer.stop();
    }
}