org.mule.module.pubsubhubbub.HubTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.module.pubsubhubbub.HubTestCase.java

Source

/**
 * Mule PubSubHubbub Connector
 *
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 *
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package org.mule.module.pubsubhubbub;

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

import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.junit.Test;
import org.mule.api.MuleMessage;

public class HubTestCase extends AbstractPuSHTestCase {
    private static final String SUBSCRIBER_FLOW_NAME = "successfullSubscriberCallback";

    private enum Action {
        SUBSCRIBE, UNSUBSCRIBE;

        String asHubMode() {
            return toString().toLowerCase();
        }
    };

    private enum Verification {
        SYNC("204"), ASYNC("202");

        private final String expectedStatusCode;

        private Verification(final String expectedStatusCode) {
            this.expectedStatusCode = expectedStatusCode;
        }

        String asVerify() {
            return toString().toLowerCase();
        }

        String getExpectedStatusCode() {
            return expectedStatusCode;
        }
    }

    private static final String DEFAULT_CALLBACK_QUERY = "";
    private static final Map<String, List<String>> DEFAULT_SUBSCRIPTION_PARAMS = Collections.emptyMap();

    @Override
    protected String getConfigResources() {
        return "push-hub-tests-config.xml,publisher-stub-config.xml";
    }

    @Override
    protected void doSetUp() throws Exception {
        super.doSetUp();
        setupSubscriberFTC(SUBSCRIBER_FLOW_NAME, 1);
        setupPublisherFTC(1);
    }

    @Test
    public void testBadContentType() throws Exception {
        final Map<String, List<String>> subscriptionRequest = new HashMap<String, List<String>>();
        subscriptionRequest.put("hub.mode", Collections.singletonList("subscribe"));

        final MuleMessage response = sendRequestToHub(subscriptionRequest, "application/octet-stream");
        assertEquals("400", response.getInboundProperty("http.status"));
        assertEquals("Content type must be: application/x-www-form-urlencoded", response.getPayloadAsString());
    }

    @Test
    public void testUnknownHubMode() throws Exception {
        final Map<String, String> subscriptionRequest = new HashMap<String, String>();
        subscriptionRequest.put("hub.mode", "foo");

        final MuleMessage response = wrapAndSendRequestToHub(subscriptionRequest);
        assertEquals("400", response.getInboundProperty("http.status"));
        assertEquals("Unsupported hub mode: foo", response.getPayloadAsString());
    }

    @Test
    public void testWrongMultivaluedRequest() throws Exception {
        final Map<String, List<String>> subscriptionRequest = new HashMap<String, List<String>>();
        subscriptionRequest.put("hub.mode", Arrays.asList("subscribe", "unsubscribe"));

        final MuleMessage response = sendRequestToHub(subscriptionRequest);
        assertEquals("400", response.getInboundProperty("http.status"));
        assertTrue(StringUtils.startsWith(response.getPayloadAsString(),
                "Multivalued parameters are only supported for:"));
    }

    @Test
    public void testBadSubscriptionRequest() throws Exception {
        final Map<String, String> subscriptionRequest = new HashMap<String, String>();
        subscriptionRequest.put("hub.mode", "subscribe");
        // missing all other required parameters

        final MuleMessage response = wrapAndSendRequestToHub(subscriptionRequest);
        assertEquals("400", response.getInboundProperty("http.status"));
        assertEquals("Missing mandatory parameter: hub.callback", response.getPayloadAsString());
    }

    @Test
    public void testSubscriptionRequestWithTooBigASecret() throws Exception {
        final Map<String, String> subscriptionRequest = new HashMap<String, String>();
        subscriptionRequest.put("hub.mode", "subscribe");
        subscriptionRequest.put("hub.callback", "http://localhost:" + getSubscriberCallbacksPort() + "/cb-failure");
        subscriptionRequest.put("hub.topic", TEST_TOPIC);
        subscriptionRequest.put("hub.verify", "sync");
        subscriptionRequest.put("hub.secret", RandomStringUtils.randomAlphanumeric(200));

        final MuleMessage response = wrapAndSendRequestToHub(subscriptionRequest);
        assertEquals("400", response.getInboundProperty("http.status"));
        assertEquals("Maximum secret size is 200 bytes", response.getPayloadAsString());
    }

    @Test
    public void testFailedSynchronousSubscriptionConfirmation() throws Exception {
        final Map<String, String> subscriptionRequest = new HashMap<String, String>();
        subscriptionRequest.put("hub.mode", "subscribe");
        subscriptionRequest.put("hub.callback", "http://localhost:" + getSubscriberCallbacksPort() + "/cb-failure");
        subscriptionRequest.put("hub.topic", TEST_TOPIC);
        subscriptionRequest.put("hub.verify", "sync");

        final MuleMessage response = wrapAndSendRequestToHub(subscriptionRequest);
        assertEquals("500", response.getInboundProperty("http.status"));
    }

    @Test
    public void testSuccessfullSynchronousSubscription() throws Exception {
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE);
    }

    @Test
    public void testSuccessfullSynchronousSubscriptionWithVerifyToken() throws Exception {
        final Map<String, List<String>> extraSubscriptionParam = Collections.singletonMap("hub.verify_token",
                Collections.singletonList(RandomStringUtils.randomAlphanumeric(20)));
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE, extraSubscriptionParam);
    }

    @Test
    public void testSuccessfullSynchronousSubscriptionWithQueryParamInCallback() throws Exception {
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE, "?foo=bar");
    }

    @Test
    public void testSuccessfullSynchronousSubscriptionWithSecret() throws Exception {
        final Map<String, List<String>> extraSubscriptionParam = Collections.singletonMap("hub.secret",
                Collections.singletonList(RandomStringUtils.randomAlphanumeric(20)));
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE, extraSubscriptionParam);
    }

    @Test
    public void testSuccessfullSynchronousMultiTopicsSubscription() throws Exception {
        final Map<String, List<String>> extraSubscriptionParam = Collections.singletonMap("hub.topic",
                Arrays.asList("http://mulesoft.org/faketopic1", "http://mulesoft.org/faketopic2"));
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE, extraSubscriptionParam);
    }

    @Test
    public void testSuccessfullSynchronousResubscription() throws Exception {
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE);
        setupSubscriberFTC(SUBSCRIBER_FLOW_NAME, 1);
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE);
    }

    @Test
    public void testSuccessfullSynchronousUnsubscription() throws Exception {
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE);
        setupSubscriberFTC(SUBSCRIBER_FLOW_NAME, 1);
        doTestSuccessfullSynchronousVerifiableAction(Action.UNSUBSCRIBE);
    }

    @Test
    public void testSuccessfullAsynchronousUnsubscription() throws Exception {
        doTestSuccessfullVerifiableAction(Action.SUBSCRIBE, Verification.ASYNC, DEFAULT_SUBSCRIPTION_PARAMS,
                DEFAULT_CALLBACK_QUERY);
    }

    @Test
    public void testSuccessfullNewContentNotificationAndContentFetch() throws Exception {
        final String topicUrl = "http://localhost:" + getPublisherPort() + "/feeds/mouth/rss";
        doTestSuccessfullNewContentNotificationAndContentFetch(topicUrl);
    }

    @Test
    public void testSuccessfullNewMultiContentNotificationAndContentFetch() throws Exception {
        setupPublisherFTC(2);

        final Map<String, List<String>> subscriptionRequest = new HashMap<String, List<String>>();
        subscriptionRequest.put("hub.mode", Arrays.asList("publish"));
        subscriptionRequest.put("hub.url",
                Arrays.asList("http://localhost:" + getPublisherPort() + "/feeds/mouth/rss",
                        "http://localhost:" + getPublisherPort() + "/feeds/mouth/rss"));

        final MuleMessage response = sendRequestToHub(subscriptionRequest);
        assertEquals("204", response.getInboundProperty("http.status"));

        publisherCC.await(TimeUnit.SECONDS.toMillis(getTestTimeoutSecs()));
        final int receivedMessagesCount = publisherFTC.getReceivedMessagesCount();
        assertEquals(2, receivedMessagesCount);
        final Set<String> expectedMessages = new HashSet<String>(
                Arrays.asList("/feeds/mouth/rss", "/feeds/mouth/rss"));
        for (int i = 1; i <= receivedMessagesCount; i++) {
            assertTrue(expectedMessages.contains(publisherFTC.getReceivedMessage(i)));
        }
    }

    @Test
    public void testSuccessfullContentDistribution() throws Exception {
        final String topicUrl = getMouthTestTopic();
        final Map<String, List<String>> extraSubscriptionParam = Collections.singletonMap("hub.topic",
                Collections.singletonList(topicUrl));
        doTestSuccessfullSynchronousVerifiableAction(Action.SUBSCRIBE, extraSubscriptionParam);

        // reset the callback FTC latch
        setupSubscriberFTC(SUBSCRIBER_FLOW_NAME, 1);

        doTestSuccessfulContentDistribution(topicUrl);

        // the stub subscriber gives a on-behalf header
        assertEquals(123, dataStore.getTotalSubscriberCount(new URI(topicUrl)));
    }

    //
    // Supporting methods
    //
    private void doTestSuccessfullSynchronousVerifiableAction(final Action action) throws Exception {
        doTestSuccessfullSynchronousVerifiableAction(action, DEFAULT_CALLBACK_QUERY);
    }

    private void doTestSuccessfullSynchronousVerifiableAction(final Action action,
            final Map<String, List<String>> extraSubscriptionParam) throws Exception {
        doTestSuccessfullVerifiableAction(action, Verification.SYNC, extraSubscriptionParam,
                DEFAULT_CALLBACK_QUERY);
    }

    private void doTestSuccessfullSynchronousVerifiableAction(final Action action, final String callbackQuery)
            throws Exception {
        doTestSuccessfullVerifiableAction(action, Verification.SYNC, DEFAULT_SUBSCRIPTION_PARAMS, callbackQuery);
    }

    private void doTestSuccessfullVerifiableAction(final Action action, final Verification verification,
            final Map<String, List<String>> extraSubscriptionParam, final String callbackQuery) throws Exception {
        final String callback = "http://localhost:" + getSubscriberCallbacksPort() + "/cb-success" + callbackQuery;

        final Map<String, List<String>> subscriptionRequest = new HashMap<String, List<String>>();
        subscriptionRequest.put("hub.mode", Collections.singletonList(action.asHubMode()));
        subscriptionRequest.put("hub.callback", Collections.singletonList(callback));
        subscriptionRequest.put("hub.topic", Collections.singletonList(TEST_TOPIC));
        subscriptionRequest.put("hub.verify", Collections.singletonList(verification.asVerify()));
        subscriptionRequest.putAll(extraSubscriptionParam);

        final MuleMessage response = sendRequestToHub(subscriptionRequest);

        assertEquals(verification.getExpectedStatusCode(), response.getInboundProperty("http.status"));

        checkVerificationMessage(callbackQuery, subscriptionRequest);

        switch (action) {
        case SUBSCRIBE:
            checkTopicSubscriptionStored(callback, subscriptionRequest);
            break;

        case UNSUBSCRIBE:
            checkTopicSubscriptionCleared(callback, subscriptionRequest);
            break;

        default:
            throw new UnsupportedOperationException("no store check for action: " + action);
        }
    }

    private void checkVerificationMessage(final String callbackQuery,
            final Map<String, List<String>> subscriptionRequest) throws Exception {
        subscriberCC.await(TimeUnit.SECONDS.toMillis(getTestTimeoutSecs()));

        final Map<String, List<String>> subscriberVerifyParams = TestUtils
                .getUrlParameters(subscriberFTC.getLastReceivedMessage().toString());

        assertEquals(subscriptionRequest.get("hub.mode").get(0), subscriberVerifyParams.get("hub.mode").get(0));
        assertTrue(StringUtils.isNotBlank(subscriberVerifyParams.get("hub.challenge").get(0)));
        assertTrue(NumberUtils.isDigits(subscriberVerifyParams.get("hub.lease_seconds").get(0)));

        for (final String hubTopic : subscriptionRequest.get("hub.topic")) {
            assertTrue(subscriberVerifyParams.get("hub.topic").contains(hubTopic));
        }

        final String verifyToken = subscriptionRequest.get("hub.verify_token") != null
                ? subscriptionRequest.get("hub.verify_token").get(0)
                : null;
        if (StringUtils.isNotBlank(verifyToken)) {
            assertEquals(verifyToken, subscriberVerifyParams.get("hub.verify_token").get(0));
        } else {
            assertNull(subscriberVerifyParams.get("hub.verify_token"));
        }

        if (StringUtils.isNotBlank(callbackQuery)) {
            final Map<String, List<String>> queryParams = TestUtils.getUrlParameters(callbackQuery);
            for (final Entry<String, List<String>> queryParam : queryParams.entrySet()) {
                assertEquals(queryParam.getValue(), subscriberVerifyParams.get(queryParam.getKey()));
            }
        } else {
            assertNull(subscriberVerifyParams.get("foo"));
        }
    }
}