Package org.apache.hedwig.client

Source Code of org.apache.hedwig.client.TestPubSubClient

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.hedwig.client;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import com.google.protobuf.ByteString;
import org.apache.hedwig.client.api.MessageHandler;
import org.apache.hedwig.client.conf.ClientConfiguration;
import org.apache.hedwig.client.HedwigClient;
import org.apache.hedwig.client.api.Publisher;
import org.apache.hedwig.client.api.Subscriber;
import org.apache.hedwig.exceptions.PubSubException;
import org.apache.hedwig.exceptions.PubSubException.ClientNotSubscribedException;
import org.apache.hedwig.protocol.PubSubProtocol.Message;
import org.apache.hedwig.protocol.PubSubProtocol.MessageSeqId;
import org.apache.hedwig.protocol.PubSubProtocol.PublishResponse;
import org.apache.hedwig.protocol.PubSubProtocol.SubscribeRequest.CreateOrAttach;
import org.apache.hedwig.protocol.PubSubProtocol.SubscriptionEvent;
import org.apache.hedwig.protocol.PubSubProtocol.SubscriptionOptions;
import org.apache.hedwig.server.PubSubServerStandAloneTestBase;
import org.apache.hedwig.util.Callback;
import org.apache.hedwig.util.ConcurrencyUtils;
import org.apache.hedwig.util.SubscriptionListener;
import org.apache.hedwig.util.HedwigSocketAddress;

@RunWith(Parameterized.class)
public class TestPubSubClient extends PubSubServerStandAloneTestBase {

    private static final int RETENTION_SECS_VALUE = 10;

    // Client side variables
    protected HedwigClient client;
    protected Publisher publisher;
    protected Subscriber subscriber;

    protected class RetentionServerConfiguration extends StandAloneServerConfiguration {
        @Override
        public boolean isStandalone() {
            return true;
        }

        @Override
        public int getRetentionSecs() {
            return RETENTION_SECS_VALUE;
        }
    }

    // SynchronousQueues to verify async calls
    private final SynchronousQueue<Boolean> queue = new SynchronousQueue<Boolean>();
    private final SynchronousQueue<Boolean> consumeQueue = new SynchronousQueue<Boolean>();
    private final SynchronousQueue<SubscriptionEvent> eventQueue =
        new SynchronousQueue<SubscriptionEvent>();

    class TestSubscriptionListener implements SubscriptionListener {
        SynchronousQueue<SubscriptionEvent> eventQueue;
        public TestSubscriptionListener() {
            this.eventQueue = TestPubSubClient.this.eventQueue;
        }
        public TestSubscriptionListener(SynchronousQueue<SubscriptionEvent> queue) {
            this.eventQueue = queue;
        }
        @Override
        public void processEvent(final ByteString topic, final ByteString subscriberId,
                                 final SubscriptionEvent event) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.debug("Event {} received for subscription(topic:{}, subscriber:{})",
                                 new Object[] { event, topic.toStringUtf8(), subscriberId.toStringUtf8() });
                    ConcurrencyUtils.put(TestSubscriptionListener.this.eventQueue, event);
                }
            }).start();
        }
    }

    // Test implementation of Callback for async client actions.
    class TestCallback implements Callback<Void> {

        @Override
        public void operationFinished(Object ctx, Void resultOfOperation) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (logger.isDebugEnabled())
                        logger.debug("Operation finished!");
                    ConcurrencyUtils.put(queue, true);
                }
            }).start();
        }

        @Override
        public void operationFailed(Object ctx, final PubSubException exception) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    logger.error("Operation failed!", exception);
                    ConcurrencyUtils.put(queue, false);
                }
            }).start();
        }
    }

    // Test implementation of subscriber's message handler.
    class TestMessageHandler implements MessageHandler {

        private final SynchronousQueue<Boolean> consumeQueue;

        public TestMessageHandler() {
            this.consumeQueue = TestPubSubClient.this.consumeQueue;
        }

        public TestMessageHandler(SynchronousQueue<Boolean> consumeQueue) {
            this.consumeQueue = consumeQueue;
        }

        public void deliver(ByteString topic, ByteString subscriberId, Message msg, Callback<Void> callback,
                            Object context) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (logger.isDebugEnabled())
                        logger.debug("Consume operation finished successfully!");
                    ConcurrencyUtils.put(TestMessageHandler.this.consumeQueue, true);
                }
            }).start();
            callback.operationFinished(context, null);
        }
    }

    @Parameters
    public static Collection<Object[]> configs() {
        return Arrays.asList(new Object[][] { { true }, { false } });
    }

    protected boolean isSubscriptionChannelSharingEnabled;

    public TestPubSubClient(boolean isSubscriptionChannelSharingEnabled) {
        this.isSubscriptionChannelSharingEnabled = isSubscriptionChannelSharingEnabled;
    }

    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();
        client = new HedwigClient(new ClientConfiguration() {
            @Override
            public HedwigSocketAddress getDefaultServerHedwigSocketAddress() {
                return getDefaultHedwigAddress();
            }

            @Override
            public boolean isSubscriptionChannelSharingEnabled() {
                return TestPubSubClient.this.isSubscriptionChannelSharingEnabled;
            }
        });
        publisher = client.getPublisher();
        subscriber = client.getSubscriber();
    }

    @Override
    @After
    public void tearDown() throws Exception {
        client.close();
        super.tearDown();
    }

    @Test(timeout=60000)
    public void testSyncPublish() throws Exception {
        boolean publishSuccess = true;
        try {
            publisher.publish(ByteString.copyFromUtf8("mySyncTopic"), Message.newBuilder().setBody(
                                  ByteString.copyFromUtf8("Hello Sync World!")).build());
        } catch (Exception e) {
            publishSuccess = false;
        }
        assertTrue(publishSuccess);
    }

    @Test(timeout=60000)
    public void testSyncPublishWithResponse() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("testSyncPublishWithResponse");
        ByteString subid = ByteString.copyFromUtf8("mysubid");

        final String prefix = "SyncMessage-";
        final int numMessages = 30;

        final Map<String, MessageSeqId> publishedMsgs =
            new HashMap<String, MessageSeqId>();

        final AtomicInteger numReceived = new AtomicInteger(0);
        final CountDownLatch receiveLatch = new CountDownLatch(1);
        final Map<String, MessageSeqId> receivedMsgs =
            new HashMap<String, MessageSeqId>();

        subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);
        subscriber.startDelivery(topic, subid, new MessageHandler() {
            synchronized public void deliver(ByteString topic, ByteString subscriberId,
                                             Message msg, Callback<Void> callback,
                                             Object context) {
                String str = msg.getBody().toStringUtf8();
                receivedMsgs.put(str, msg.getMsgId());
                if (numMessages == numReceived.incrementAndGet()) {
                    receiveLatch.countDown();
                }
                callback.operationFinished(context, null);
            }
        });

        for (int i=0; i<numMessages; i++) {
            String str = prefix + i;
            ByteString data = ByteString.copyFromUtf8(str);
            Message msg = Message.newBuilder().setBody(data).build();
            PublishResponse response = publisher.publish(topic, msg);
            assertNotNull(response);
            publishedMsgs.put(str, response.getPublishedMsgId());
        }

        assertTrue("Timed out waiting on callback for messages.",
                   receiveLatch.await(30, TimeUnit.SECONDS));
        assertEquals("Should be expected " + numMessages + " messages.",
                     numMessages, numReceived.get());
        assertEquals("Should be expected " + numMessages + " messages in map.",
                     numMessages, receivedMsgs.size());

        for (int i=0; i<numMessages; i++) {
            final String str = prefix + i;
            MessageSeqId pubId = publishedMsgs.get(str);
            MessageSeqId revId = receivedMsgs.get(str);
            assertTrue("Doesn't receive same message seq id for " + str,
                       pubId.equals(revId));
        }
    }

    @Test(timeout=60000)
    public void testAsyncPublish() throws Exception {
        publisher.asyncPublish(ByteString.copyFromUtf8("myAsyncTopic"), Message.newBuilder().setBody(
                                   ByteString.copyFromUtf8("Hello Async World!")).build(), new TestCallback(), null);
        assertTrue(queue.take());
    }

    @Test(timeout=60000)
    public void testAsyncPublishWithResponse() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("testAsyncPublishWithResponse");
        ByteString subid = ByteString.copyFromUtf8("mysubid");

        final String prefix = "AsyncMessage-";
        final int numMessages = 30;

        final AtomicInteger numPublished = new AtomicInteger(0);
        final CountDownLatch publishLatch = new CountDownLatch(1);
        final Map<String, MessageSeqId> publishedMsgs =
            new HashMap<String, MessageSeqId>();

        final AtomicInteger numReceived = new AtomicInteger(0);
        final CountDownLatch receiveLatch = new CountDownLatch(1);
        final Map<String, MessageSeqId> receivedMsgs =
            new HashMap<String, MessageSeqId>();

        subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);
        subscriber.startDelivery(topic, subid, new MessageHandler() {
            synchronized public void deliver(ByteString topic, ByteString subscriberId,
                                             Message msg, Callback<Void> callback,
                                             Object context) {
                String str = msg.getBody().toStringUtf8();
                receivedMsgs.put(str, msg.getMsgId());
                if (numMessages == numReceived.incrementAndGet()) {
                    receiveLatch.countDown();
                }
                callback.operationFinished(context, null);
            }
        });

        for (int i=0; i<numMessages; i++) {
            final String str = prefix + i;
            ByteString data = ByteString.copyFromUtf8(str);
            Message msg = Message.newBuilder().setBody(data).build();
            publisher.asyncPublishWithResponse(topic, msg, new Callback<PublishResponse>() {
                @Override
                public void operationFinished(Object ctx, PublishResponse response) {
                    publishedMsgs.put(str, response.getPublishedMsgId());
                    if (numMessages == numPublished.incrementAndGet()) {
                        publishLatch.countDown();
                    }
                }
                @Override
                public void operationFailed(Object ctx, final PubSubException exception) {
                    publishLatch.countDown();
                }
            }, null);
        }
        assertTrue("Timed out waiting on callback for publish requests.",
                   publishLatch.await(10, TimeUnit.SECONDS));
        assertEquals("Should be expected " + numMessages + " publishes.",
                     numMessages, numPublished.get());
        assertEquals("Should be expected " + numMessages + " publishe responses.",
                     numMessages, publishedMsgs.size());

        assertTrue("Timed out waiting on callback for messages.",
                   receiveLatch.await(30, TimeUnit.SECONDS));
        assertEquals("Should be expected " + numMessages + " messages.",
                     numMessages, numReceived.get());
        assertEquals("Should be expected " + numMessages + " messages in map.",
                     numMessages, receivedMsgs.size());

        for (int i=0; i<numMessages; i++) {
            final String str = prefix + i;
            MessageSeqId pubId = publishedMsgs.get(str);
            MessageSeqId revId = receivedMsgs.get(str);
            assertTrue("Doesn't receive same message seq id for " + str,
                       pubId.equals(revId));
        }
    }

    @Test(timeout=60000)
    public void testMultipleAsyncPublish() throws Exception {
        ByteString topic1 = ByteString.copyFromUtf8("myFirstTopic");
        ByteString topic2 = ByteString.copyFromUtf8("myNewTopic");

        publisher.asyncPublish(topic1, Message.newBuilder().setBody(ByteString.copyFromUtf8("Hello World!")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        publisher.asyncPublish(topic2, Message.newBuilder().setBody(ByteString.copyFromUtf8("Hello on new topic!"))
                               .build(), new TestCallback(), null);
        assertTrue(queue.take());
        publisher.asyncPublish(topic1, Message.newBuilder().setBody(
                                   ByteString.copyFromUtf8("Hello Again on old topic!")).build(), new TestCallback(), null);
        assertTrue(queue.take());
    }

    @Test(timeout=60000)
    public void testSyncSubscribe() throws Exception {
        boolean subscribeSuccess = true;
        try {
            subscriber.subscribe(ByteString.copyFromUtf8("mySyncSubscribeTopic"), ByteString.copyFromUtf8("1"), CreateOrAttach.CREATE_OR_ATTACH);
        } catch (Exception e) {
            subscribeSuccess = false;
        }
        assertTrue(subscribeSuccess);
    }

    @Test(timeout=60000)
    public void testAsyncSubscribe() throws Exception {
        subscriber.asyncSubscribe(ByteString.copyFromUtf8("myAsyncSubscribeTopic"), ByteString.copyFromUtf8("1"),
                                  CreateOrAttach.CREATE_OR_ATTACH, new TestCallback(), null);
        assertTrue(queue.take());
    }

    @Test(timeout=60000)
    public void testStartDeliveryAfterCloseSub() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("testStartDeliveryAfterCloseSub");
        ByteString subid = ByteString.copyFromUtf8("mysubid");
        subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);

        // Start delivery for the subscriber
        subscriber.startDelivery(topic, subid, new TestMessageHandler());

        // Now publish some messages for the topic to be consumed by the
        // subscriber.
        publisher.publish(topic, Message.newBuilder()
                                .setBody(ByteString.copyFromUtf8("Message #1")).build());
        assertTrue(consumeQueue.take());

        // Close subscriber for the subscriber
        subscriber.closeSubscription(topic, subid);

        // subscribe again
        subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);
        subscriber.startDelivery(topic, subid, new TestMessageHandler());

        publisher.publish(topic, Message.newBuilder()
                                .setBody(ByteString.copyFromUtf8("Message #2")).build());
        assertTrue(consumeQueue.take());
    }

    @Test(timeout=60000)
    public void testSubscribeAndConsume() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("myConsumeTopic");
        ByteString subscriberId = ByteString.copyFromUtf8("1");
        subscriber.asyncSubscribe(topic, subscriberId, CreateOrAttach.CREATE_OR_ATTACH, new TestCallback(), null);
        assertTrue(queue.take());

        // Start delivery for the subscriber
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());

        // Now publish some messages for the topic to be consumed by the
        // subscriber.
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #1")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #2")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #3")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #4")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #5")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());
    }

    @Test(timeout=60000)
    public void testAsyncSubscribeAndUnsubscribe() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("myAsyncUnsubTopic");
        ByteString subscriberId = ByteString.copyFromUtf8("1");
        subscriber.asyncSubscribe(topic, subscriberId, CreateOrAttach.CREATE_OR_ATTACH, new TestCallback(), null);
        assertTrue(queue.take());
        subscriber.asyncUnsubscribe(topic, subscriberId, new TestCallback(), null);
        assertTrue(queue.take());
    }

    @Test(timeout=60000)
    public void testSyncUnsubscribeWithoutSubscription() throws Exception {
        boolean unsubscribeSuccess = false;
        try {
            subscriber.unsubscribe(ByteString.copyFromUtf8("mySyncUnsubTopic"), ByteString.copyFromUtf8("1"));
        } catch (ClientNotSubscribedException e) {
            unsubscribeSuccess = true;
        } catch (Exception ex) {
            unsubscribeSuccess = false;
        }
        assertTrue(unsubscribeSuccess);
    }

    @Test(timeout=60000)
    public void testAsyncSubscribeAndCloseSubscription() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("myAsyncSubAndCloseSubTopic");
        ByteString subscriberId = ByteString.copyFromUtf8("1");
        subscriber.asyncSubscribe(topic, subscriberId, CreateOrAttach.CREATE_OR_ATTACH, new TestCallback(), null);
        assertTrue(queue.take());
        subscriber.closeSubscription(topic, subscriberId);
        assertTrue(true);
    }

    @Test(timeout=60000)
    public void testSubClosesubAndPublish() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("mySubClosesubAndPublish");
        ByteString subid = ByteString.copyFromUtf8("mysub");
        // to populate startServing/stopServing sequeuence
        for (int i=0; i<5; i++) {
            subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);
            subscriber.closeSubscription(topic, subid);
        }
        subscriber.subscribe(topic, subid, CreateOrAttach.CREATE_OR_ATTACH);
        subscriber.startDelivery(topic, subid, new TestMessageHandler());
        for (int i=0; i<3; i++) {
            publisher.asyncPublish(topic,
                Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #" + i)).build(),
                new TestCallback(), null);
            assertTrue(queue.take());
            assertTrue(consumeQueue.take());
        }
    }

    @Test(timeout=60000)
    public void testSyncSubscribeWithListener() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("mySyncSubscribeWithListener");
        ByteString subscriberId = ByteString.copyFromUtf8("mysub");
        subscriber.addSubscriptionListener(new TestSubscriptionListener());
        try {
            SubscriptionOptions options =
                SubscriptionOptions.newBuilder()
                .setCreateOrAttach(CreateOrAttach.CREATE_OR_ATTACH)
                .setEnableResubscribe(false).build();
            subscriber.subscribe(topic, subscriberId, options);
        } catch (PubSubException.ServiceDownException e) {
            fail("Should not reach here!");
        }
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());
        tearDownHubServer();
        assertEquals(SubscriptionEvent.TOPIC_MOVED, eventQueue.take());
    }

    @Test(timeout=60000)
    public void testAsyncSubscribeWithListener() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("myAsyncSubscribeWithListener");
        ByteString subscriberId = ByteString.copyFromUtf8("mysub");
        subscriber.addSubscriptionListener(new TestSubscriptionListener());
        SubscriptionOptions options =
            SubscriptionOptions.newBuilder()
            .setCreateOrAttach(CreateOrAttach.CREATE_OR_ATTACH)
            .setEnableResubscribe(false).build();
        subscriber.asyncSubscribe(topic, subscriberId, options,
                                  new TestCallback(), null);
        assertTrue(queue.take());
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());
        tearDownHubServer();
        assertEquals(SubscriptionEvent.TOPIC_MOVED, eventQueue.take());
    }

    @Test(timeout=60000)
    public void testSyncSubscribeForceAttach() throws Exception {
        ByteString topic = ByteString.copyFromUtf8("mySyncSubscribeForceAttach");
        ByteString subscriberId = ByteString.copyFromUtf8("mysub");
        subscriber.addSubscriptionListener(new TestSubscriptionListener());
        SubscriptionOptions options =
            SubscriptionOptions.newBuilder()
            .setCreateOrAttach(CreateOrAttach.CREATE_OR_ATTACH)
            .setForceAttach(true).setEnableResubscribe(false).build();
        try {
            subscriber.subscribe(topic, subscriberId, options);
        } catch (PubSubException.ServiceDownException e) {
            fail("Should not reach here!");
        }
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());

        // new a client
        HedwigClient client2 = new HedwigClient(new ClientConfiguration() {
                @Override
                public HedwigSocketAddress getDefaultServerHedwigSocketAddress() {
                    return getDefaultHedwigAddress();
                }
            });
        Subscriber subscriber2 = client2.getSubscriber();
        Publisher publisher2 = client2.getPublisher();
        SynchronousQueue<SubscriptionEvent> eventQueue2 =
            new SynchronousQueue<SubscriptionEvent>();
        subscriber2.addSubscriptionListener(new TestSubscriptionListener(eventQueue2));
        try {
            subscriber2.subscribe(topic, subscriberId, options);
        } catch (PubSubException.ServiceDownException e) {
            fail("Should not reach here!");
        }

        SynchronousQueue<Boolean> consumeQueue2 = new SynchronousQueue<Boolean>();
        subscriber2.startDelivery(topic, subscriberId, new TestMessageHandler(consumeQueue2));

        assertEquals(SubscriptionEvent.SUBSCRIPTION_FORCED_CLOSED, eventQueue.take());
        assertTrue(eventQueue2.isEmpty());

        // Now publish some messages for the topic to be consumed by the
        // subscriber.
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #1")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue2.take());
        assertTrue(consumeQueue.isEmpty());

        publisher2.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #2")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue2.take());
        assertTrue(consumeQueue.isEmpty());

        client2.close();
    }

    @Test(timeout=60000)
    public void testSyncSubscribeWithListenerWhenReleasingTopic() throws Exception {
        client.close();

        tearDownHubServer();
        startHubServer(new RetentionServerConfiguration());
        client = new HedwigClient(new ClientConfiguration() {
            @Override
            public HedwigSocketAddress getDefaultServerHedwigSocketAddress() {
                return getDefaultHedwigAddress();
            }

            @Override
            public boolean isSubscriptionChannelSharingEnabled() {
                return TestPubSubClient.this.isSubscriptionChannelSharingEnabled;
            }
        });
        publisher = client.getPublisher();
        subscriber = client.getSubscriber();

        ByteString topic = ByteString.copyFromUtf8("mySyncSubscribeWithListenerWhenReleasingTopic");
        ByteString subscriberId = ByteString.copyFromUtf8("mysub");
        subscriber.addSubscriptionListener(new TestSubscriptionListener());
        SubscriptionOptions options =
            SubscriptionOptions.newBuilder()
            .setCreateOrAttach(CreateOrAttach.CREATE_OR_ATTACH)
            .setForceAttach(false).setEnableResubscribe(false).build();
        try {
            subscriber.subscribe(topic, subscriberId, options);
        } catch (PubSubException.ServiceDownException e) {
            fail("Should not reach here!");
        }
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());

        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #1")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());
        assertTrue(consumeQueue.take());

        Thread.sleep(RETENTION_SECS_VALUE * 2);
        assertEquals(SubscriptionEvent.TOPIC_MOVED, eventQueue.take());
    }

    @Test
    public void testCloseSubscribeDuringResubscribe() throws Exception {
        client.close();

        final long reconnectWaitTime = 2000L;
        client = new HedwigClient(new ClientConfiguration() {
            @Override
            public HedwigSocketAddress getDefaultServerHedwigSocketAddress() {
                return getDefaultHedwigAddress();
            }

            @Override
            public boolean isSubscriptionChannelSharingEnabled() {
                return TestPubSubClient.this.isSubscriptionChannelSharingEnabled;
            }

            @Override
            public long getSubscribeReconnectRetryWaitTime() {
                return reconnectWaitTime;
            }
        });

        publisher = client.getPublisher();
        subscriber = client.getSubscriber();

        ByteString topic = ByteString.copyFromUtf8("testCloseSubscribeDuringResubscribe");
        ByteString subscriberId = ByteString.copyFromUtf8("mysub");
        subscriber.addSubscriptionListener(new TestSubscriptionListener());
        SubscriptionOptions options =
            SubscriptionOptions.newBuilder()
            .setCreateOrAttach(CreateOrAttach.CREATE_OR_ATTACH)
            .setForceAttach(false).setEnableResubscribe(true).build();
        subscriber.subscribe(topic, subscriberId, options);
        logger.info("Subscribed topic {}, subscriber {}.", topic.toStringUtf8(),
                    subscriberId.toStringUtf8());
        subscriber.startDelivery(topic, subscriberId, new TestMessageHandler());

        // tear down the hub server to let subscribe enter
        tearDownHubServer();
        logger.info("Tear down the hub server");

        // wait for client enter to resubscribe logic
        Thread.sleep(reconnectWaitTime / 2);

        // close sub
        subscriber.closeSubscription(topic, subscriberId);

        // start the hub server again
        startHubServer(conf);

        // publish a new message
        publisher.asyncPublish(topic, Message.newBuilder().setBody(ByteString.copyFromUtf8("Message #1")).build(),
                               new TestCallback(), null);
        assertTrue(queue.take());

        // wait for another reconnect time period
        assertNull("Should not receive any messages since the subscription has already been closed.",
                   consumeQueue.poll(reconnectWaitTime + reconnectWaitTime / 2, TimeUnit.MILLISECONDS));
    }

}
TOP

Related Classes of org.apache.hedwig.client.TestPubSubClient

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.