All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.aeron.StopStartSecondSubscriberTest Maven / Gradle / Ivy

There is a newer version: 1.24.0
Show newest version
/*
 * Copyright 2014-2017 Real Logic Ltd.
 *
 * 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.
 */
package io.aeron;

import org.junit.After;
import org.junit.Test;
import io.aeron.driver.MediaDriver;
import io.aeron.logbuffer.FragmentHandler;
import org.agrona.BitUtil;
import org.agrona.LangUtil;
import org.agrona.concurrent.UnsafeBuffer;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
 * Test that a second subscriber can be stopped and started again while data is being published.
 */
public class StopStartSecondSubscriberTest
{
    public static final String CHANNEL1 = "aeron:udp?endpoint=localhost:54325";
    public static final String CHANNEL2 = "aeron:udp?endpoint=localhost:54326";
    private static final int STREAM_ID1 = 1;
    private static final int STREAM_ID2 = 2;

    private MediaDriver driver1;
    private MediaDriver driver2;
    private Aeron publishingClient1;
    private Aeron subscribingClient1;
    private Aeron publishingClient2;
    private Aeron subscribingClient2;
    private Subscription subscription1;
    private Publication publication1;
    private Subscription subscription2;
    private Publication publication2;

    private final UnsafeBuffer buffer = new UnsafeBuffer(new byte[8192]);
    private final AtomicInteger subscriber1Count = new AtomicInteger();
    private final FragmentHandler fragmentHandler1 =
        (buffer, offset, length, header) -> subscriber1Count.getAndIncrement();
    private final AtomicInteger subscriber2Count = new AtomicInteger();
    private final FragmentHandler fragmentHandler2 =
        (buffer, offset, length, header) -> subscriber2Count.getAndIncrement();

    final MediaDriver.Context mediaDriverContext1 = new MediaDriver.Context();
    final MediaDriver.Context mediaDriverContext2 = new MediaDriver.Context();

    private void launch(final String channel1, final int stream1, final String channel2, final int stream2)
    {
        driver1 = MediaDriver.launchEmbedded(mediaDriverContext1);
        driver2 = MediaDriver.launchEmbedded(mediaDriverContext2);

        final Aeron.Context publishingAeronContext1 = new Aeron.Context();
        final Aeron.Context subscribingAeronContext1 = new Aeron.Context();
        final Aeron.Context publishingAeronContext2 = new Aeron.Context();
        final Aeron.Context subscribingAeronContext2 = new Aeron.Context();

        publishingAeronContext1.aeronDirectoryName(driver1.aeronDirectoryName());
        publishingAeronContext2.aeronDirectoryName(driver1.aeronDirectoryName());
        subscribingAeronContext1.aeronDirectoryName(driver2.aeronDirectoryName());
        subscribingAeronContext2.aeronDirectoryName(driver2.aeronDirectoryName());

        publishingClient1 = Aeron.connect(publishingAeronContext1);
        subscribingClient1 = Aeron.connect(subscribingAeronContext1);
        publishingClient2 = Aeron.connect(publishingAeronContext2);
        subscribingClient2 = Aeron.connect(subscribingAeronContext2);

        publication1 = publishingClient1.addPublication(channel1, stream1);
        subscription1 = subscribingClient1.addSubscription(channel1, stream1);
        publication2 = publishingClient2.addPublication(channel2, stream2);
        subscription2 = subscribingClient2.addSubscription(channel2, stream2);
    }

    @After
    public void closeEverything()
    {
        subscribingClient1.close();
        publishingClient1.close();
        subscribingClient2.close();
        publishingClient2.close();

        driver1.close();
        driver2.close();

        mediaDriverContext1.deleteAeronDirectory();
        mediaDriverContext2.deleteAeronDirectory();
    }

    @Test(timeout = 10000)
    public void shouldSpinUpAndShutdown()
    {
        launch(CHANNEL1, STREAM_ID1, CHANNEL2, STREAM_ID2);
    }

    @Test(timeout = 10000)
    public void shouldReceivePublishedMessage()
    {
        launch(CHANNEL1, STREAM_ID1, CHANNEL2, STREAM_ID2);

        buffer.putInt(0, 1);

        final int numMessagesPerPublication = 1;

        while (publication1.offer(buffer, 0, BitUtil.SIZE_OF_INT) < 0L)
        {
            Thread.yield();
        }

        while (publication2.offer(buffer, 0, BitUtil.SIZE_OF_INT) < 0L)
        {
            Thread.yield();
        }

        final AtomicInteger fragmentsRead1 = new AtomicInteger();
        final AtomicInteger fragmentsRead2 = new AtomicInteger();
        SystemTestHelper.executeUntil(
            () -> fragmentsRead1.get() >= numMessagesPerPublication &&
                fragmentsRead2.get() >= numMessagesPerPublication,
            (i) ->
            {
                fragmentsRead1.addAndGet(subscription1.poll(fragmentHandler1, 10));
                fragmentsRead2.addAndGet(subscription2.poll(fragmentHandler2, 10));
                Thread.yield();
            },
            Integer.MAX_VALUE,
            TimeUnit.MILLISECONDS.toNanos(9900));

        assertEquals(numMessagesPerPublication, subscriber1Count.get());
        assertEquals(numMessagesPerPublication, subscriber2Count.get());
    }

    @Test(timeout = 10000)
    public void shouldReceiveMessagesAfterStopStartOnSameChannelSameStream()
    {
        shouldReceiveMessagesAfterStopStart(CHANNEL1, STREAM_ID1, CHANNEL1, STREAM_ID1);
    }

    @Test(timeout = 10000)
    public void shouldReceiveMessagesAfterStopStartOnSameChannelDifferentStreams()
    {
        shouldReceiveMessagesAfterStopStart(CHANNEL1, STREAM_ID1, CHANNEL1, STREAM_ID2);
    }

    @Test(timeout = 10000)
    public void shouldReceiveMessagesAfterStopStartOnDifferentChannelsSameStream()
    {
        shouldReceiveMessagesAfterStopStart(CHANNEL1, STREAM_ID1, CHANNEL2, STREAM_ID1);
    }

    @Test(timeout = 10000)
    public void shouldReceiveMessagesAfterStopStartOnDifferentChannelsDifferentStreams()
    {
        shouldReceiveMessagesAfterStopStart(CHANNEL1, STREAM_ID1, CHANNEL2, STREAM_ID2);
    }

    private void doPublisherWork(final Publication publication, final AtomicBoolean running)
    {
        while (running.get())
        {
            while (running.get() && publication.offer(buffer, 0, BitUtil.SIZE_OF_INT) < 0L)
            {
                Thread.yield();
            }
        }
    }

    private void shouldReceiveMessagesAfterStopStart(
        final String channel1, final int stream1, final String channel2, final int stream2)
    {
        final ExecutorService executor = Executors.newFixedThreadPool(2);
        final int numMessages = 1;
        final AtomicInteger subscriber2AfterRestartCount = new AtomicInteger();
        final AtomicBoolean running = new AtomicBoolean(true);

        final FragmentHandler fragmentHandler2b =
            (buffer, offset, length, header) -> subscriber2AfterRestartCount.incrementAndGet();

        launch(channel1, stream1, channel2, stream2);

        buffer.putInt(0, 1);

        executor.execute(() -> doPublisherWork(publication1, running));
        executor.execute(() -> doPublisherWork(publication2, running));

        final AtomicInteger fragmentsRead1 = new AtomicInteger();
        final AtomicInteger fragmentsRead2 = new AtomicInteger();
        SystemTestHelper.executeUntil(
            () -> fragmentsRead1.get() >= numMessages && fragmentsRead2.get() >= numMessages,
            (i) ->
            {
                fragmentsRead1.addAndGet(subscription1.poll(fragmentHandler1, 1));
                fragmentsRead2.addAndGet(subscription2.poll(fragmentHandler2, 1));
                Thread.yield();
            },
            Integer.MAX_VALUE,
            TimeUnit.MILLISECONDS.toNanos(4900));

        assertTrue(subscriber1Count.get() >= numMessages);
        assertTrue(subscriber2Count.get() >= numMessages);

        // Stop the second subscriber
        subscription2.close();

        // Zero out the counters
        fragmentsRead1.set(0);
        fragmentsRead2.set(0);

        // Start the second subscriber again
        subscription2 = subscribingClient2.addSubscription(channel2, stream2);

        SystemTestHelper.executeUntil(
            () -> fragmentsRead1.get() >= numMessages && fragmentsRead2.get() >= numMessages,
            (i) ->
            {
                fragmentsRead1.addAndGet(subscription1.poll(fragmentHandler1, 1));
                fragmentsRead2.addAndGet(subscription2.poll(fragmentHandler2b, 1));
                Thread.yield();
            },
            Integer.MAX_VALUE,
            TimeUnit.MILLISECONDS.toNanos(4900));

        running.set(false);

        assertTrue("Expecting subscriber1 to receive messages the entire time",
            subscriber1Count.get() >= numMessages * 2);
        assertTrue("Expecting subscriber2 to receive messages before being stopped and started",
            subscriber2Count.get() >= numMessages);
        assertTrue("Expecting subscriber2 to receive messages after being stopped and started",
            subscriber2AfterRestartCount.get() >= numMessages);

        executor.shutdown();

        try
        {
            while (!executor.awaitTermination(1, TimeUnit.SECONDS))
            {
                System.err.println("Still awaiting termination");
            }
        }
        catch (final InterruptedException ex)
        {
            LangUtil.rethrowUnchecked(ex);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy