Package org.waveprotocol.box.server.frontend

Source Code of org.waveprotocol.box.server.frontend.ClientFrontendImplTest

/**
* 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.waveprotocol.box.server.frontend;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import junit.framework.TestCase;

import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.waveprotocol.box.common.DeltaSequence;
import org.waveprotocol.box.common.ExceptionalIterator;
import org.waveprotocol.box.common.comms.WaveClientRpc.WaveletVersion;
import org.waveprotocol.box.server.common.CoreWaveletOperationSerializer;
import org.waveprotocol.box.server.frontend.ClientFrontend.OpenListener;
import org.waveprotocol.box.server.util.WaveletDataUtil;
import org.waveprotocol.box.server.waveserver.WaveServerException;
import org.waveprotocol.box.server.waveserver.WaveletProvider;
import org.waveprotocol.box.server.waveserver.WaveletProvider.SubmitRequestListener;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta;
import org.waveprotocol.wave.model.id.IdConstants;
import org.waveprotocol.wave.model.id.IdFilter;
import org.waveprotocol.wave.model.id.IdFilters;
import org.waveprotocol.wave.model.id.IdURIEncoderDecoder;
import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.model.operation.OperationException;
import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
import org.waveprotocol.wave.model.testing.DeltaTestUtil;
import org.waveprotocol.wave.model.version.HashedVersion;
import org.waveprotocol.wave.model.version.HashedVersionFactory;
import org.waveprotocol.wave.model.version.HashedVersionFactoryImpl;
import org.waveprotocol.wave.model.wave.ParticipantId;
import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
import org.waveprotocol.wave.model.wave.data.WaveletData;
import org.waveprotocol.wave.util.escapers.jvm.JavaUrlCodec;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
* Tests for {@link ClientFrontendImpl}.
*/
public class ClientFrontendImplTest extends TestCase {
  private static final IdURIEncoderDecoder URI_CODEC =
      new IdURIEncoderDecoder(new JavaUrlCodec());
  private static final HashedVersionFactory HASH_FACTORY =
      new HashedVersionFactoryImpl(URI_CODEC);

  private static final WaveId WAVE_ID = WaveId.of("example.com", "waveId");
  private static final WaveId INDEX_WAVE_ID = WaveId.of("indexdomain", "indexwave");
  private static final WaveletId W1 =
      WaveletId.of("example.com", IdConstants.CONVERSATION_ROOT_WAVELET);
  private static final WaveletId W2 = WaveletId.of("example.com", "conv+2");
  private static final WaveletName WN1 = WaveletName.of(WAVE_ID, W1);
  private static final WaveletName WN2 = WaveletName.of(WAVE_ID, W2);

  private static final ParticipantId USER = new ParticipantId("user@example.com");
  private static final DeltaTestUtil UTIL = new DeltaTestUtil(USER);

  private static final HashedVersion V0 = HASH_FACTORY.createVersionZero(WN1);
  private static final HashedVersion V1 = HashedVersion.unsigned(1L);
  private static final HashedVersion V2 = HashedVersion.unsigned(2L);

  private static final TransformedWaveletDelta DELTA = TransformedWaveletDelta.cloneOperations(
      USER, V1, 0, ImmutableList.of(UTIL.addParticipant(USER)));
  private static final DeltaSequence DELTAS = DeltaSequence.of(DELTA);
  private static final ProtocolWaveletDelta SERIALIZED_DELTA =
      CoreWaveletOperationSerializer.serialize(DELTA);
  private static final Collection<WaveletVersion> NO_KNOWN_WAVELETS =
      Collections.<WaveletVersion>emptySet();

  private ClientFrontendImpl clientFrontend;
  private WaveletProvider waveletProvider;

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    waveletProvider = mock(WaveletProvider.class);
    when(waveletProvider.getWaveletIds(any(WaveId.class))).thenReturn(ImmutableSet.<WaveletId>of());

    WaveletInfo waveletInfo = WaveletInfo.create(HASH_FACTORY, waveletProvider);
    clientFrontend = new ClientFrontendImpl(waveletProvider, waveletInfo);
  }

  public void testCannotOpenWavesWhenNotLoggedIn() throws Exception {
    OpenListener listener = mock(OpenListener.class);
    clientFrontend.openRequest(null, WAVE_ID, IdFilters.ALL_IDS, NO_KNOWN_WAVELETS, listener);
    verify(listener).onFailure("Not logged in");

    CommittedWaveletSnapshot snapshot = provideWavelet(WN1);
    clientFrontend.waveletUpdate(snapshot.snapshot, DELTAS);
    Mockito.verifyNoMoreInteractions(listener);
  }

  public void testOpenEmptyWaveReceivesChannelIdAndMarker() {
    OpenListener listener = openWave(IdFilters.ALL_IDS);
    verifyChannelId(listener);
    verifyMarker(listener, WAVE_ID);
  }

  public void testTwoSubscriptionsReceiveDifferentChannelIds() {
    OpenListener listener1 = openWave(IdFilters.ALL_IDS);
    String ch1 = verifyChannelId(listener1);

    OpenListener listener2 = openWave(IdFilters.ALL_IDS);
    String ch2 = verifyChannelId(listener2);

    assertFalse(ch1.equals(ch2));
  }

  public void testOpenWaveRecievesSnapshotsThenMarker() throws Exception {
    CommittedWaveletSnapshot snapshot1 = provideWavelet(WN1);
    CommittedWaveletSnapshot snapshot2 = provideWavelet(WN2);
    when(waveletProvider.getWaveletIds(WAVE_ID)).thenReturn(ImmutableSet.of(W1, W2));
    when(waveletProvider.checkAccessPermission(WN1, USER)).thenReturn(true);
    when(waveletProvider.checkAccessPermission(WN2, USER)).thenReturn(true);

    OpenListener listener = openWave(IdFilters.ALL_IDS);
    verify(listener).onUpdate(eq(WN1), eq(snapshot1), eq(DeltaSequence.empty()),
        eq(V0), isNullMarker(), any(String.class));
    verify(listener).onUpdate(eq(WN2), eq(snapshot2), eq(DeltaSequence.empty()),
        eq(V0), isNullMarker(), any(String.class));
    verifyMarker(listener, WAVE_ID);
  }

  /**
   * Tests that a snapshot not matching the subscription filter is not received.
   * @throws WaveServerException
   */
  @SuppressWarnings("unchecked") // Mock container
  public void testUnsubscribedSnapshotNotRecieved() throws Exception {
    OpenListener listener = openWave(IdFilter.ofPrefixes("non-existing"));
    verifyChannelId(listener);
    verifyMarker(listener, WAVE_ID);

    ReadableWaveletData wavelet = provideWavelet(WN1).snapshot;
    clientFrontend.waveletUpdate(wavelet, DELTAS);
    verify(listener, Mockito.never()).onUpdate(eq(WN1),
        any(CommittedWaveletSnapshot.class), Matchers.anyList(),
        any(HashedVersion.class), isNullMarker(), anyString());
  }

  /**
   * Tests that we get deltas.
   */
  public void testReceivedDeltasSentToClient() throws Exception {
    CommittedWaveletSnapshot snapshot = provideWavelet(WN1);
    when(waveletProvider.getWaveletIds(WAVE_ID)).thenReturn(ImmutableSet.of(W1));
    when(waveletProvider.checkAccessPermission(WN1, USER)).thenReturn(true);

    OpenListener listener = openWave(IdFilters.ALL_IDS);
    verify(listener).onUpdate(eq(WN1), eq(snapshot), eq(DeltaSequence.empty()),
        eq(V0), isNullMarker(), any(String.class));
    verifyMarker(listener, WAVE_ID);

    TransformedWaveletDelta delta = TransformedWaveletDelta.cloneOperations(USER, V2, 1234567890L,
        Arrays.asList(UTIL.noOp()));
    DeltaSequence deltas = DeltaSequence.of(delta);
    clientFrontend.waveletUpdate(snapshot.snapshot, deltas);
    verify(listener).onUpdate(eq(WN1), isNullSnapshot(), eq(deltas),
        isNullVersion(), isNullMarker(), anyString());
  }

  /**
   * Tests that submit requests are forwarded to the wavelet provider.
   */
  public void testSubmitForwardedToWaveletProvider() {
    OpenListener openListener = openWave(IdFilters.ALL_IDS);
    String channelId = verifyChannelId(openListener);

    SubmitRequestListener submitListener = mock(SubmitRequestListener.class);
    clientFrontend.submitRequest(USER, WN1, SERIALIZED_DELTA, channelId, submitListener);
    verify(waveletProvider).submitRequest(eq(WN1), eq(SERIALIZED_DELTA),
        any(SubmitRequestListener.class));
    verifyZeroInteractions(submitListener);
  }

  public void testCannotSubmitAsDifferentUser() {
    ParticipantId otherParticipant = new ParticipantId("another@example.com");
    OpenListener openListener = openWave(IdFilters.ALL_IDS);
    String channelId = verifyChannelId(openListener);

    SubmitRequestListener submitListener = mock(SubmitRequestListener.class);
    clientFrontend.submitRequest(otherParticipant, WN1, SERIALIZED_DELTA, channelId,
        submitListener);
    verify(submitListener).onFailure(anyString());
    verify(submitListener, never()).onSuccess(anyInt(), (HashedVersion) any(), anyLong());
  }

  /**
   * Tests that if we open the index wave, we don't get updates from the
   * original wave if they contain no interesting operations (add/remove
   * participant or text).
   */
  public void testUninterestingDeltasDontUpdateIndex() throws WaveServerException {
    provideWaves(Collections.<WaveId> emptySet());

    OpenListener listener = openWave(INDEX_WAVE_ID, IdFilters.ALL_IDS);
    verifyChannelId(listener);
    verifyMarker(listener, INDEX_WAVE_ID);

    HashedVersion v1 = HashedVersion.unsigned(1L);
    TransformedWaveletDelta delta = makeDelta(USER, v1, 0L, UTIL.noOp());
    DeltaSequence deltas = DeltaSequence.of(delta);

    WaveletData wavelet = WaveletDataUtil.createEmptyWavelet(WN1, USER, V0, 1234567890L);
    clientFrontend.waveletUpdate(wavelet, deltas);

    WaveletName dummyWaveletName = ClientFrontendImpl.createDummyWaveletName(INDEX_WAVE_ID);
    verify(listener, Mockito.never()).onUpdate(eq(dummyWaveletName),
        any(CommittedWaveletSnapshot.class),
        isDeltasStartingAt(0),
        any(HashedVersion.class), isNullMarker(), anyString());
  }

  /**
   * Opens a wave and returns a mock listener.
   */
  private ClientFrontend.OpenListener openWave(WaveId waveId, IdFilter filter) {
    OpenListener openListener = mock(OpenListener.class);
    clientFrontend.openRequest(USER, waveId, filter, NO_KNOWN_WAVELETS, openListener);
    return openListener;
  }

  private ClientFrontend.OpenListener openWave(IdFilter filter) {
    return openWave(WAVE_ID, filter);
  }

  private TransformedWaveletDelta makeDelta(ParticipantId author, HashedVersion endVersion,
      long timestamp, WaveletOperation... operations) {
    return TransformedWaveletDelta.cloneOperations(author, endVersion, timestamp,
        Arrays.asList(operations));
  }

  /**
   * Initialises the wavelet provider to provide a collection of waves.
   */
  private void provideWaves(Collection<WaveId> waves) throws WaveServerException {
    when(waveletProvider.getWaveIds()).thenReturn(
        ExceptionalIterator.FromIterator.<WaveId, WaveServerException> create(
            waves.iterator()));
  }

  /**
   * Prepares the wavelet provider to provide a new wavelet.
   *
   * @param name new wavelet name
   * @return the new wavelet snapshot
   */
  private CommittedWaveletSnapshot provideWavelet(WaveletName name) throws WaveServerException,
      OperationException {
    WaveletData wavelet = WaveletDataUtil.createEmptyWavelet(name, USER, V0, 1234567890L);
    DELTA.get(0).apply(wavelet);
    CommittedWaveletSnapshot snapshot = new CommittedWaveletSnapshot(wavelet, V0);
    when(waveletProvider.getSnapshot(name)).thenReturn(snapshot);
    when(waveletProvider.getWaveletIds(name.waveId)).thenReturn(ImmutableSet.of(name.waveletId));
    return snapshot;
  }

  /**
   * Verifies that the listener received a channel id.
   *
   * @return the channel id received
   */
  private static String verifyChannelId(OpenListener listener) {
    ArgumentCaptor<String> channelIdCaptor = ArgumentCaptor.forClass(String.class);
    verify(listener).onUpdate(any(WaveletName.class), isNullSnapshot(), eq(DeltaSequence.empty()),
        isNullVersion(), isNullMarker(), channelIdCaptor.capture());
    return channelIdCaptor.getValue();
  }

  /**
   * Verifies that the listener received a marker.
   */
  private static void verifyMarker(OpenListener listener, WaveId waveId) {
    ArgumentCaptor<WaveletName> waveletNameCaptor = ArgumentCaptor.forClass(WaveletName.class);
    verify(listener).onUpdate(waveletNameCaptor.capture(), isNullSnapshot(),
        eq(DeltaSequence.empty()), isNullVersion(), eq(true), (String) Mockito.isNull());
    assertEquals(waveId, waveletNameCaptor.getValue().waveId);
  }

  private static CommittedWaveletSnapshot isNullSnapshot() {
    return (CommittedWaveletSnapshot) Mockito.isNull();
  }

  private static HashedVersion isNullVersion() {
    return (HashedVersion) Mockito.isNull();
  }

  private static Boolean isNullMarker() {
    return (Boolean) Mockito.isNull();
  }

  private static List<TransformedWaveletDelta> isDeltasStartingAt(final long version) {
    return argThat(new ArgumentMatcher<List<TransformedWaveletDelta>>() {
      @Override
      public boolean matches(Object sequence) {
        if (sequence != null) {
          DeltaSequence s = (DeltaSequence) sequence;
          return (s.size() > 0) && (s.getStartVersion() == version);
        }
        return false;
      }
    });
  }
}
TOP

Related Classes of org.waveprotocol.box.server.frontend.ClientFrontendImplTest

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.