Package com.opengamma.web.analytics.push

Source Code of com.opengamma.web.analytics.push.CollectionMatcher

package com.opengamma.web.analytics.push;

import static org.mockito.Matchers.anyCollection;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;

import java.util.Collection;

import org.mockito.ArgumentMatcher;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.threeten.bp.Instant;

import com.google.common.collect.Lists;
import com.opengamma.core.change.ChangeEvent;
import com.opengamma.core.change.ChangeType;
import com.opengamma.id.UniqueId;
import com.opengamma.util.test.TestGroup;
import com.opengamma.web.analytics.rest.MasterType;

/**
* Test the subscription mechanism of {@link ClientConnection}.  Subscriptions are added for REST URLs.  When any
* event fires for a particular URL the URL is considered dirty and the client should re-request it.  Therefore there
* is no need to fire any more events for that URL until the client resubscribes.  So when any event fires for
* a URL all other subscriptions for that URL should be cleared.
*/
@Test(groups = TestGroup.UNIT)
public class ClientConnectionTest {

  private static final String USER_ID = "USER_ID";
  private static final String CLIENT_ID = "CLIENT_ID";
  private static final String TEST_URL1 = "TEST_URL1";
  private static final String TEST_URL2 = "TEST_URL2";
  private static final UniqueId _uid1 = UniqueId.of("Tst", "101");
  private static final UniqueId _uid2 = UniqueId.of("Tst", "102");

  private UpdateListener _listener;
  private ClientConnection _connection;

  @BeforeMethod
  public void setUp() throws Exception {
    _listener = mock(UpdateListener.class);
    ConnectionTimeoutTask timeoutTask = mock(ConnectionTimeoutTask.class);
    _connection = new ClientConnection(USER_ID, CLIENT_ID, _listener, timeoutTask);
  }

  /**
   * Checks that a listener to changes to an entity gets fired once and once only.
   */
  @Test
  public void subscribeToEntityEvent() {
    ChangeEvent event = new ChangeEvent(ChangeType.CHANGED, _uid1.getObjectId(), null, null, Instant.now());

    // send an event and make sure the _listener doesn't receive it before subscription
    _connection.entityChanged(event);
    verify(_listener, never()).itemsUpdated(anyCollection());

    // subscribe and verify the _listener receives the event
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.entityChanged(event);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));

    // send the event again and make sure the subscription has been cancelled
    _connection.entityChanged(event);
    verifyNoMoreInteractions(_listener);
  }

  @Test
  public void subscribeToMaster() {
    // send an event before subscription and check the listener doesn't receive it
    _connection.masterChanged(MasterType.PORTFOLIO);
    verify(_listener, never()).itemsUpdated(anyCollection());

    // subscribe and verify the listener receives the event
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.masterChanged(MasterType.PORTFOLIO);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));

    // send the event again and make sure the subscription has been cancelled
    _connection.masterChanged(MasterType.PORTFOLIO);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * Multiple URLs subscribing to the same entity should produce multiple updates when the entity changes.
   */
  @Test
  public void multipleSubscriptionsToEntity() {
    ChangeEvent event = new ChangeEvent(ChangeType.CHANGED, _uid1.getObjectId(), null, null, Instant.now());

    // subscribe and verify the listener receives the event
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.subscribe(_uid1, TEST_URL2);
    _connection.entityChanged(event);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1, TEST_URL2));

    // send the event again and make sure the subscription has been cancelled
    _connection.entityChanged(event);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * Multiple URLs subscribing to the same master should produce multiple updates when the master fires a change event.
   */
  @Test
  public void multipleSubscriptionsToMaster() {
    // subscribe and verify the listener receives the event
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL2);
    _connection.masterChanged(MasterType.PORTFOLIO);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1, TEST_URL2));

    // send the event again and make sure the subscription has been cancelled
    _connection.masterChanged(MasterType.PORTFOLIO);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * A particular URL should only have one event delivered no matter how many subscriptions it has.  After the
   * first event no more should be triggered until a new subscription is set up.
   */
  @Test
  public void multipeEntitySubscriptionsForSameUrl() {
    ChangeEvent event1 = new ChangeEvent(ChangeType.CHANGED, _uid1.getObjectId(), null, null, Instant.now());
    ChangeEvent event2 = new ChangeEvent(ChangeType.CHANGED, _uid2.getObjectId(), null, null, Instant.now());

    // subscribe and verify the listener receives the event
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.subscribe(_uid2, TEST_URL1);
    _connection.entityChanged(event1);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));

    // send an event for the other subscription and check nothing is delivered to the listener
    _connection.entityChanged(event2);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * A particular URL should only have one event delivered no matter how many subscriptions it has.  After the
   * first event no more should be triggered until a new subscription is set up.
   */
  @Test
  public void multipeMasterSubscriptionsForSameUrl() {
    // subscribe and verify the listener receives the event
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.subscribe(MasterType.POSITION, TEST_URL1);
    _connection.masterChanged(MasterType.PORTFOLIO);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));

    // send an event for the other subscribed master type and make sure the subscription has been cancelled
    _connection.masterChanged(MasterType.POSITION);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * If there is an entity and master subscription for the same URL then only one event should fire even
   * if both the entity and master are changed.
   */
  @Test
  public void masterAndEntitySubscriptionForSameUrlMasterChangesFirst() {
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.masterChanged(MasterType.PORTFOLIO);
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));
    _connection.entityChanged(new ChangeEvent(ChangeType.CHANGED, _uid1.getObjectId(), null, null, Instant.now()));
    verifyNoMoreInteractions(_listener);
  }

  /**
   * If there is an entity and master subscription for the same URL then only one event should fire even
   * if both the entity and master are changed.
   */
  @Test
  public void masterAndEntitySubscriptionForSameUrlEntityChangesFirst() {
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.entityChanged(new ChangeEvent(ChangeType.CHANGED, _uid1.getObjectId(), null, null, Instant.now()));
    verify(_listener).itemsUpdated(CollectionMatcher.collectionOf(TEST_URL1));
    _connection.masterChanged(MasterType.PORTFOLIO);
    verifyNoMoreInteractions(_listener);
  }

  /**
   * Checks that nothing happens when a subscription is set up for an entity and a different entity changes.
   */
  @Test
  public void subscriptionForDifferentEntity() {
    _connection.subscribe(_uid1, TEST_URL1);
    _connection.entityChanged(new ChangeEvent(ChangeType.CHANGED, _uid2.getObjectId(), null, null, Instant.now()));
    verifyZeroInteractions(_listener);
  }

  /**
   * Checks that nothing happens when a subscription is set up for a master and a different master changes.
   */
  @Test
  public void subscriptionForDifferentMaster() {
    _connection.subscribe(MasterType.PORTFOLIO, TEST_URL1);
    _connection.masterChanged(MasterType.POSITION);
    verifyZeroInteractions(_listener);
  }
}

/**
* <p>Matcher for checking an argument to a mock is a collection containing all of the specified items and nothing else.
* The order of the elements isn't important.</p>

* <em>I'm surprised this isn't already available in Mockito, although maybe it's there and I just can't find it.</em>

* @param <T> The type of items in the collection
*/
@SuppressWarnings("unchecked")
class CollectionMatcher<T> extends ArgumentMatcher<Collection<T>> {

  private final Collection<T> _expected;

  public CollectionMatcher(T... expectedItems) {
    _expected = Lists.newArrayList(expectedItems);
  }

  @Override
  public boolean matches(Object o) {
    Collection<T> result = Lists.newArrayList((Collection<T>) o);
    for (T expectedItem : _expected) {
      // every member of the expected collection must be present in the result
      if (!result.remove(expectedItem)) {
        return false;
      }
    }
    // if all members of the expected collection were in the result and after removing them the result is empty
    // the collections must have contained exactly the same elements
    return result.isEmpty();
  }

  static <T> Collection<T> collectionOf(T... items) {
    return argThat(new CollectionMatcher<T>(items));
  }
}
TOP

Related Classes of com.opengamma.web.analytics.push.CollectionMatcher

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.