com.mastfrog.scamper.SctpServerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.mastfrog.scamper.SctpServerTest.java

Source

/*
 * Copyright (c) 2014 Tim Boudreau
 *
 * This file is part of Scamper.
 *
 * Scamper is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.mastfrog.scamper;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Names;
import com.mastfrog.giulius.tests.GuiceRunner;
import com.mastfrog.giulius.tests.TestWith;
import static com.mastfrog.scamper.ProtocolModule.SETTINGS_KEY_SCTP_PORT;
import com.mastfrog.scamper.SctpServerTest.BsonModule;
import com.mastfrog.scamper.SctpServerTest.JsonModule;
import com.mastfrog.scamper.SctpServerTest.M;
import com.mastfrog.scamper.SctpServerTest.SerializationModule;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(GuiceRunner.class)
@TestWith(iterate = { BsonModule.class, JsonModule.class, SerializationModule.class })
public class SctpServerTest {

    static final MessageType INBOUND = new MessageType("in", 3, 3);
    static final MessageType OUTBOUND = new MessageType("out", 3, 4);

    String longString;

    @Before
    public void before() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 200; i++) {
            sb.append("abcdefghijklmnopqrstuvwxyz1234567890");
        }
        longString = sb.toString();
    }

    @Test
    public void test(Sender sender, CountDownLatch latch, MessageHandlerMapping mapping) throws Throwable {
        assertNotNull(mapping.get(INBOUND));
        assertNotNull(mapping.get(OUTBOUND));

        sender.send(new Address("127.0.0.1", port), INBOUND.newMessage(newThing(1, longString)));
        latch.await(1, TimeUnit.SECONDS);
        errors.maybeThrow();
        assertNotNull(inInstance);
        inInstance.await();
        errors.maybeThrow();
        assertFalse(inInstance.things.isEmpty());
        assertEquals(longString, inInstance.things.iterator().next().what);
        assertEquals(1, inInstance.things.iterator().next().index);
        for (int i = 0; outInstance == null && i < 100; i++) {
            Thread.sleep(20);
        }
        assertNotNull(outInstance);
        System.out.println("Wiat on ");
        outInstance.await();
        System.out.println("done");
        errors.maybeThrow();
        assertFalse(outInstance.strings.isEmpty());
        assertEquals("Received " + longString, outInstance.strings.iterator().next());
    }

    static InHandler inInstance;
    static OutHandler outInstance;

    @Singleton
    static class InHandler extends MessageHandler<OtherThing, Thing> {

        List<Thing> things = Collections.synchronizedList(new LinkedList<>());

        @Inject
        InHandler(CountDownLatch latch) {
            super(Thing.class);
            inInstance = this;
            latch.countDown();
        }

        @Override
        public Message<OtherThing> onMessage(Message<Thing> data, ChannelHandlerContext ctx) {
            System.out.println("in onMessage " + data.body.what + " " + data.body.index);
            assertNotNull(data);
            assertNotNull(data.body);
            Message<OtherThing> result = OUTBOUND.newMessage(new OtherThing("Received " + data.body.what));
            synchronized (this) {
                things.add(data.body);
                notifyAll();
            }
            return result;
        }

        synchronized void await() throws InterruptedException {
            if (!things.isEmpty()) {
                return;
            }
            this.wait(1000);
        }
    }

    @Singleton
    static class OutHandler extends MessageHandler<Void, OtherThing> {

        List<String> strings = Collections.synchronizedList(new LinkedList<>());

        OutHandler() {
            super(OtherThing.class);
            outInstance = this;
        }

        @Override
        public Message<Void> onMessage(Message<OtherThing> data, ChannelHandlerContext ctx) {
            System.out.println("out onMessage " + data.body);
            assertNotNull(data);
            assertNotNull(data.body);
            synchronized (this) {
                strings.add(data.body.data);
                notifyAll();
            }
            return null;
        }

        synchronized void await() throws InterruptedException {
            if (!strings.isEmpty()) {
                return;
            }
            this.wait(1000);
        }
    }

    static int port;

    static class BsonModule extends AbstractModule {

        @Override
        protected void configure() {
            install(new M(DataEncoding.BSON));
        }
    }

    static class JsonModule extends AbstractModule {

        @Override
        protected void configure() {
            install(new M(DataEncoding.JSON));
        }
    }

    static class SerializationModule extends AbstractModule {

        @Override
        protected void configure() {
            install(new M(DataEncoding.JAVA_SERIALIZATION));
        }
    }

    static final class M extends AbstractModule {

        private final DataEncoding enc;

        M(DataEncoding enc) {
            this.enc = enc;
        }

        @Override
        protected void configure() {
            install(new ProtocolModule(1, 1, enc).bind(INBOUND, InHandler.class).bind(OUTBOUND, OutHandler.class));
            bind(String.class).annotatedWith(Names.named(SETTINGS_KEY_SCTP_PORT))
                    .toInstance("" + (port = new Random().nextInt(500) + 8000));
            bind(Starter.class).asEagerSingleton();
            bind(ErrorHandler.class).toInstance(errors);
            bind(CountDownLatch.class).toInstance(new CountDownLatch(1));
        }

        static class Starter {

            @Inject
            public void Starter(SctpServer server) throws InterruptedException {
                AtomicReference<ChannelFuture> ref = new AtomicReference<>();
                ChannelFuture fut = server.start(ref);
                assertNotNull(ref.get());
                ref.get().sync();
                Thread.sleep(2000);
            }
        }
    }

    static Thing newThing(int ix, String what) {
        Thing thing = new Thing();
        thing.index = ix;
        thing.what = what;
        return thing;
    }

    static class Thing implements Serializable {

        public String what;
        public int index;

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 79 * hash + Objects.hashCode(this.what);
            hash = 79 * hash + this.index;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Thing other = (Thing) obj;
            if (!Objects.equals(this.what, other.what)) {
                return false;
            }
            return this.index == other.index;
        }

        @Override
        public String toString() {
            return "Thing{" + "what=" + what + ", index=" + index + '}';
        }
    }

    static class OtherThing implements Serializable {

        public final String data;

        @JsonCreator
        public OtherThing(@JsonProperty("data") String data) {
            this.data = data;
        }

        @Override
        public String toString() {
            return "OtherThing{" + "data=" + data + '}';
        }

        @Override
        public int hashCode() {
            int hash = 3;
            hash = 71 * hash + Objects.hashCode(this.data);
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final OtherThing other = (OtherThing) obj;
            return Objects.equals(this.data, other.data);
        }
    }

    static final EH errors = new EH();

    static class EH implements ErrorHandler {

        private Throwable t;

        @Override
        public void onError(ChannelHandlerContext ctx, Throwable t) {
            this.t = t;
        }

        public void maybeThrow() throws Throwable {
            if (t != null) {
                Throwable tt = t;
                t = null;
                throw tt;
            }
        }

    }
}