org.geoserver.cluster.hazelcast.HzSynchronizerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.cluster.hazelcast.HzSynchronizerTest.java

Source

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
 * (c) 2014 Boundless
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.cluster.hazelcast;

import static org.easymock.EasyMock.anyLong;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createMockBuilder;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.event.CatalogListener;
import org.geoserver.cluster.ClusterConfig;
import org.geoserver.cluster.ClusterConfigWatcher;
import org.geoserver.cluster.Event;
import org.geoserver.config.ConfigurationListener;
import org.geoserver.config.GeoServer;
import org.geoserver.platform.resource.Files;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resources;
import org.junit.Before;

import com.google.common.collect.Sets;
import com.hazelcast.core.Cluster;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.ITopic;
import com.hazelcast.core.Member;
import com.hazelcast.core.Message;
import com.hazelcast.core.MessageListener;

public abstract class HzSynchronizerTest {

    final public static String TOPIC_NAME = "geoserver.config";
    final public static String ACK_TOPIC_NAME = "geoserver.config.ack";
    final public static int SYNC_DELAY = 1;
    //protected void setUpSpring(List<String> springContextLocations) {

    // We're going to set up the synchronizer manually so ignore the spring context.
    //}

    public static Resource tmpDir() throws IOException {
        Resource root = Files.asResource(new File(System.getProperty("java.io.tmpdir", ".")));
        Resource directory = Resources.createRandom("tmp", "", root);

        do {
            FileUtils.forceDelete(directory.dir());
        } while (Resources.exists(directory));

        FileUtils.forceMkdir(directory.dir());

        return Files.asResource(directory.dir());
    }

    @Before
    @SuppressWarnings("unchecked")
    public void setUp() throws Exception {
        hz = createMock(HazelcastInstance.class);
        // Create a "partial mock" of the HzCluster
        cluster = createMockBuilder(HzCluster.class)
                .addMockedMethods("getHz", "isEnabled", "getRawCatalog", "getAckTimeoutMillis").createMock();
        topic = createMock(ITopic.class);
        ackTopic = createMock(ITopic.class);
        configWatcher = createMock(ClusterConfigWatcher.class);
        clusterConfig = createMock(ClusterConfig.class);

        captureTopicListener = new Capture<MessageListener<Event>>();
        captureAckTopicListener = new Capture<MessageListener<UUID>>();
        captureAckTopicPublish = new Capture<UUID>();

        localAddress = new InetSocketAddress(localAddress(42), 5000);
        remoteAddress = new InetSocketAddress(localAddress(54), 5000);

        catalog = createMock(Catalog.class);

        Cluster cluster = createMock(Cluster.class);
        Member localMember = createMock(Member.class);
        Member remoteMember = createMock(Member.class);

        expect(this.cluster.getHz()).andStubReturn(hz);
        expect(this.cluster.isEnabled()).andStubReturn(true);
        expect(this.cluster.getRawCatalog()).andStubReturn(catalog);
        ;
        expect(this.cluster.getAckTimeoutMillis()).andStubReturn(100);

        expect(hz.<Event>getTopic(TOPIC_NAME)).andStubReturn(topic);
        expect(topic.addMessageListener(capture(captureTopicListener))).andReturn("fake-id");
        expectLastCall().anyTimes();

        expect(hz.<UUID>getTopic(ACK_TOPIC_NAME)).andStubReturn(ackTopic);
        expect(ackTopic.addMessageListener(capture(captureAckTopicListener))).andReturn("fake-id");
        expectLastCall().anyTimes();

        ackTopic.publish(EasyMock.capture(captureAckTopicPublish));
        EasyMock.expectLastCall().andStubAnswer(new IAnswer<Object>() {

            @Override
            public Object answer() throws Throwable {
                Message<UUID> message = createMock(Message.class);
                expect(message.getMessageObject()).andStubReturn(captureAckTopicPublish.getValue());
                EasyMock.replay(message);
                for (MessageListener<UUID> listener : captureAckTopicListener.getValues()) {
                    listener.onMessage(message);
                }
                return null;
            }

        });

        expect(cluster.getLocalMember()).andStubReturn(localMember);
        expect(localMember.getSocketAddress()).andStubReturn(localAddress);
        expect(remoteMember.getSocketAddress()).andStubReturn(remoteAddress);
        expect(localMember.localMember()).andStubReturn(true);
        expect(remoteMember.localMember()).andStubReturn(false);

        expect(cluster.getMembers()).andStubReturn(Sets.newHashSet(localMember, remoteMember));

        EasyMock.replay(cluster, localMember, remoteMember);

        expect(hz.getCluster()).andStubReturn(cluster);

        expect(configWatcher.get()).andStubReturn(clusterConfig);

        expect(clusterConfig.getSyncDelay()).andStubReturn(SYNC_DELAY);

        geoServer = createMock(GeoServer.class);

        expect(geoServer.getCatalog()).andStubReturn(catalog);

        gsListenerCapture = new Capture<ConfigurationListener>();
        geoServer.addListener(capture(gsListenerCapture));
        expectLastCall().atLeastOnce();

        catListenerCapture = new Capture<CatalogListener>();
        catalog.addListener(capture(catListenerCapture));
        expectLastCall().atLeastOnce();

        executor = createMock(ScheduledExecutorService.class);
        captureExecutor = new Capture<Runnable>(CaptureType.ALL);
        expect(executor.schedule(capture(captureExecutor), anyLong(), (TimeUnit) anyObject())).andStubReturn(null);
    }

    protected static InetAddress localAddress(int i) throws Exception {
        return InetAddress.getByAddress(new byte[] { (byte) 192, (byte) 168, 0, (byte) i });
    }

    MessageListener<Event> getListener() {
        return captureTopicListener.getValue();
    }

    protected HazelcastInstance hz;
    protected HzCluster cluster;
    protected ITopic<Event> topic;
    protected ITopic<UUID> ackTopic;
    protected GeoServer geoServer;
    protected Catalog catalog;
    protected ClusterConfigWatcher configWatcher;
    protected ClusterConfig clusterConfig;
    protected ScheduledExecutorService executor;

    protected InetSocketAddress localAddress;
    protected InetSocketAddress remoteAddress;

    protected Capture<ConfigurationListener> gsListenerCapture;
    protected Capture<CatalogListener> catListenerCapture;
    protected Capture<MessageListener<Event>> captureTopicListener;
    protected Capture<MessageListener<UUID>> captureAckTopicListener;
    protected Capture<Runnable> captureExecutor;
    protected Capture<UUID> captureAckTopicPublish;

    public List<Object> myMocks() {
        return Arrays.asList(topic, ackTopic, configWatcher, clusterConfig, geoServer, catalog, hz, executor,
                cluster);
    }

    public HzSynchronizerTest() {
        super();
    }

    protected ScheduledExecutorService getMockExecutor() {
        return executor;
    }

    /**
     * Return the HzSynchronizer instance to be tested.  Override {@link HzSyncronizer#getExecutor}
     * to return {@link #getMockExecutor}.  Provide it with {@link #hz} and {@link #geoServer}.
     */
    protected abstract HzSynchronizer getSynchronizer();

    protected void initSynchronizer(HzSynchronizer sync) {
        sync.initialize(configWatcher);
    }

    protected GeoServer getGeoServer() {
        return geoServer;
    }

    protected Catalog getCatalog() {
        return catalog;
    }

    /**
     * Replay all the mocks on this test class, plus those specified
     * @param mocks
     */
    protected void replay(Object... mocks) {
        EasyMock.replay(myMocks().toArray());
        EasyMock.replay(mocks);
    }

    /**
     * Reset all the mocks on this test class, plus those specified
     * @param mocks
     */
    protected void reset(Object... mocks) {
        EasyMock.reset(myMocks().toArray());
        EasyMock.reset(mocks);
    }

    /**
     * Verify all the mocks on this test class, plus those specified
     * @param mocks
     */
    protected void verify(Object... mocks) {
        EasyMock.verify(myMocks().toArray());
        EasyMock.verify(mocks);
    }

    protected void waitForSync() throws Exception {

        //Thread.sleep(SYNC_DELAY*1000+500); // Convert to millis, then add a little extra to be sure

        List<Runnable> tasks = captureExecutor.getValues();

        for (Iterator<Runnable> i = tasks.iterator(); i.hasNext();) {
            Runnable task = i.next();
            i.remove();
            task.run();
        }
    }

    void assertAcked(UUID... eventId) {
        assertThat(captureAckTopicPublish.getValues(), hasItems(eventId));
    }
}