Package org.waveprotocol.box.server.waveserver

Source Code of org.waveprotocol.box.server.waveserver.WaveletStateTestBase

/**
* 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.waveserver;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.ArrayList;

import junit.framework.TestCase;

import org.waveprotocol.wave.federation.Proto.ProtocolAppliedWaveletDelta;
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.WaveletDelta;
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.util.escapers.jvm.JavaUrlCodec;
import org.waveprotocol.wave.federation.Proto;
import org.waveprotocol.box.common.ListReceiver;
import org.waveprotocol.box.common.Receiver;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Tests for {@link WaveletState} implementations.
*
* @author anorth@google.com (Alex North)
* @author akaplanov@gmail.com (Andrew Kaplanov)
*/
public abstract class WaveletStateTestBase extends TestCase {

  private static final WaveletName NAME = WaveletName.of(WaveId.of("example.com", "waveid"),
      WaveletId.of("example.com", "waveletid"));
  private static final ParticipantId AUTHOR = ParticipantId.ofUnsafe("author@example.com");
  private static final DeltaTestUtil UTIL = new DeltaTestUtil(AUTHOR);
  private static final long TS = 1234567890L;
  private static final long TS2 = TS + 1;
  private static final long TS3 = TS2 + 1;

  private static final IdURIEncoderDecoder URI_CODEC =
      new IdURIEncoderDecoder(new JavaUrlCodec());
  private static final HashedVersionFactory HASH_FACTORY = new HashedVersionFactoryImpl(URI_CODEC);
  private static final HashedVersion V0 = HASH_FACTORY.createVersionZero(NAME);


  /**
   * Creates a new, empty wavelet state.
   */
  protected abstract WaveletState createEmptyState(WaveletName name) throws Exception;

  /**
   * Waits for all pending persistence operations to be completed. All
   * persistence listener callbacks must be completed before this method
   * returns.
   */
  protected abstract void awaitPersistence() throws Exception;

  private WaveletDeltaRecord d1;
  private WaveletDeltaRecord d2;
  private WaveletDeltaRecord d3;

  private WaveletState target;

  @Override
  public void setUp() throws Exception {
    d1 = makeDelta(V0, TS, 2);
    d2 = makeDelta(d1.getResultingVersion(), TS2, 2);
    d3 = makeDelta(d2.getResultingVersion(), TS3, 1);

    target = createEmptyState(NAME);
  }

  public void testReportsWaveletName() {
    assertEquals(NAME, target.getWaveletName());
  }

  public void testEmptyStateIsEmpty() {
    assertNull(target.getSnapshot());
    assertEquals(V0, target.getCurrentVersion());
    assertEquals(V0, target.getHashedVersion(0));

    assertNull(target.getTransformedDelta(V0));
    assertNull(target.getAppliedDelta(V0));
  }

  public void testSnapshotMetadataReflectsDeltas() throws Exception {
    HashedVersion v2 = d1.getResultingVersion();
    appendDeltas(d1);

    assertEquals(v2, target.getCurrentVersion());
    ReadableWaveletData snapshot = target.getSnapshot();
    assertEquals(AUTHOR, snapshot.getCreator());
    assertEquals(v2, snapshot.getHashedVersion());
    assertEquals(TS, snapshot.getCreationTime());
    assertEquals(TS, snapshot.getLastModifiedTime());
    assertEquals(2, snapshot.getVersion());

    HashedVersion v4 = d2.getResultingVersion();
    appendDeltas(d2);

    assertEquals(v4, target.getCurrentVersion());
    snapshot = target.getSnapshot();
    assertEquals(v4, snapshot.getHashedVersion());
    assertEquals(4, snapshot.getVersion());
    // Last-modified-time doesn't change due to unworthiness.
  }

  public void testHashedVersionAccessibleOnDeltaBoundaries() throws Exception {
    appendDeltas(d1, d2, d3);
    assertEquals(V0, target.getHashedVersion(0));
    assertEquals(d1.getResultingVersion(), target.getHashedVersion(2));
    assertEquals(d2.getResultingVersion(), target.getHashedVersion(4));
    assertEquals(d3.getResultingVersion(), target.getHashedVersion(5));
    assertNull(target.getHashedVersion(1));
    assertNull(target.getHashedVersion(3));
    assertNull(target.getHashedVersion(6));
  }

  public void testDeltasAccessibleByBeginVersion() throws Exception {
    appendDeltas(d1, d2, d3);
    assertEquals(d1.getTransformedDelta(), target.getTransformedDelta(V0));
    assertEquals(d1.getAppliedDelta(), target.getAppliedDelta(V0));

    assertEquals(d2.getTransformedDelta(), target.getTransformedDelta(d1.getResultingVersion()));
    assertEquals(d2.getAppliedDelta(), target.getAppliedDelta(d1.getResultingVersion()));

    assertEquals(d3.getTransformedDelta(), target.getTransformedDelta(d2.getResultingVersion()));
    assertEquals(d3.getAppliedDelta(), target.getAppliedDelta(d2.getResultingVersion()));

    // Wrong hashes return null.
    assertNull(target.getTransformedDelta(HashedVersion.unsigned(0)));
    assertNull(target.getAppliedDelta(HashedVersion.unsigned(0)));
  }

  public void testDeltasAccesssibleByEndVersion() throws Exception {
    appendDeltas(d1, d2, d3);
    for (WaveletDeltaRecord d : Arrays.asList(d1, d2, d3)) {
      assertEquals(d.getTransformedDelta(),
          target.getTransformedDeltaByEndVersion(d.getResultingVersion()));
      assertEquals(d.getAppliedDelta(),
          target.getAppliedDeltaByEndVersion(d.getResultingVersion()));
    }

    // Wrong hashes return null.
    assertNull(target.getTransformedDeltaByEndVersion(
        HashedVersion.unsigned(d1.getResultingVersion().getVersion())));
    assertNull(target.getAppliedDeltaByEndVersion(
        HashedVersion.unsigned(d1.getResultingVersion().getVersion())));
  }

  public void testDeltaHistoryRequiresCorrectHash() throws Exception {
    appendDeltas(d1);
    target.persist(d1.getResultingVersion());
    Receiver<TransformedWaveletDelta> transformedDeltasReceiver =
        new ListReceiver<TransformedWaveletDelta>();
    Receiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>> appliedDeltasReceiver =
        new ListReceiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>>();
    // Wrong start hash.
    checkGetTransformedDeltasThrowsException(HashedVersion.unsigned(0), d1.getResultingVersion(), transformedDeltasReceiver,
        IllegalArgumentException.class);
    checkGetAppliedDeltasThrowsException(HashedVersion.unsigned(0), d1.getResultingVersion(), appliedDeltasReceiver,
        IllegalArgumentException.class);

    // Wrong end hash.
    checkGetTransformedDeltasThrowsException(V0, HashedVersion.unsigned(d1.getResultingVersion().getVersion()),
        transformedDeltasReceiver, IllegalArgumentException.class);
    checkGetAppliedDeltasThrowsException(V0, HashedVersion.unsigned(d1.getResultingVersion().getVersion()),
        appliedDeltasReceiver, IllegalArgumentException.class);
  }

  @SuppressWarnings("rawtypes")
  private void checkGetTransformedDeltasThrowsException(HashedVersion startVersion, HashedVersion endVersion,
      Receiver<TransformedWaveletDelta> receiver, Class exceptionClass) {
    try {
      target.getTransformedDeltaHistory(startVersion, endVersion, receiver);
      fail("Expected exception not thrown.");
    } catch (Exception ex) {
      assertEquals(IllegalArgumentException.class, exceptionClass);
    }
  }

  @SuppressWarnings("rawtypes")
  private void checkGetAppliedDeltasThrowsException(HashedVersion startVersion, HashedVersion endVersion,
      Receiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>> receiver, Class exceptionClass) {
    try {
      target.getAppliedDeltaHistory(startVersion, endVersion, receiver);
      fail("Expected exception not thrown.");
    } catch (Exception ex) {
      assertEquals(IllegalArgumentException.class, exceptionClass);
    }
  }

  public void testSingleDeltaHistoryAccessible() throws Exception {
    appendDeltas(d1);
    target.persist(d1.getResultingVersion());
    ListReceiver<TransformedWaveletDelta> transformedDeltasReceiver =
        new ListReceiver<TransformedWaveletDelta>();
    target.getTransformedDeltaHistory(V0, d1.getResultingVersion(), transformedDeltasReceiver);
    assertEquals(1, transformedDeltasReceiver.size());
    assertEquals(d1.getTransformedDelta(), transformedDeltasReceiver.get(0));

    ListReceiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>> appliedDeltasReceiver =
        new ListReceiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>>();
    target.getAppliedDeltaHistory(V0, d1.getResultingVersion(), appliedDeltasReceiver);
    assertEquals(1, appliedDeltasReceiver.size());
    assertEquals(d1.getAppliedDelta(), Iterables.getOnlyElement(appliedDeltasReceiver));
  }

  public void testDeltaHistoryQueriesCorrectHistory() throws Exception {
    appendDeltas(d1, d2, d3);
    target.persist(d3.getResultingVersion());

    checkHistoryForDeltas(d1);
    checkHistoryForDeltas(d1, d2);
    checkHistoryForDeltas(d2, d3);
    checkHistoryForDeltas(d1, d2, d3);
  }

  public void testDeltaHistoryInterruptQueriesCorrectHistory() throws Exception {
    appendDeltas(d1, d2, d3);
    target.persist(d3.getResultingVersion());

    checkHistoryForDeltasWithInterrupt(0, d1);
    checkHistoryForDeltasWithInterrupt(1, d1, d2);
    checkHistoryForDeltasWithInterrupt(2, d1, d2, d3);
  }

  /**
   * Checks that a request for the deltas spanning a contiguous sequence of
   * delta facets produces correct results.
   */
  private void checkHistoryForDeltas(WaveletDeltaRecord... deltas) {
    HashedVersion beginVersion = deltas[0].getAppliedAtVersion();
    HashedVersion endVersion = deltas[deltas.length - 1].getTransformedDelta().getResultingVersion();

    {
      List<TransformedWaveletDelta> expected = Lists.newArrayListWithExpectedSize(deltas.length);
      for (WaveletDeltaRecord d : deltas) {
        expected.add(d.getTransformedDelta());
      }
      ListReceiver<TransformedWaveletDelta> transformedDeltasReceiver =
        new ListReceiver<TransformedWaveletDelta>();
      target.getTransformedDeltaHistory(beginVersion, endVersion, transformedDeltasReceiver);
      assertTrue(Iterables.elementsEqual(expected, transformedDeltasReceiver));
    }
    {
      List<ByteStringMessage<ProtocolAppliedWaveletDelta>> expected =
          Lists.newArrayListWithExpectedSize(deltas.length);
      for (WaveletDeltaRecord d : deltas) {
        expected.add(d.getAppliedDelta());
      }
    ListReceiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>> appliedDeltasReceiver =
        new ListReceiver<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>>();
    target.getAppliedDeltaHistory(beginVersion, endVersion, appliedDeltasReceiver);
      assertTrue(Iterables.elementsEqual(expected, appliedDeltasReceiver));
    }
  }

private void checkHistoryForDeltasWithInterrupt(final int interruptIndex, WaveletDeltaRecord... deltas) {
    HashedVersion beginVersion = deltas[0].getAppliedAtVersion();
    HashedVersion endVersion = deltas[interruptIndex].getTransformedDelta().getResultingVersion();

    {
      List<TransformedWaveletDelta> expected = Lists.newArrayListWithExpectedSize(interruptIndex+1);
      for (int i=0; i <= interruptIndex; i++) {
        expected.add(deltas[i].getTransformedDelta());
      }
      final AtomicInteger index = new AtomicInteger(0);
      final List<TransformedWaveletDelta> transformedDeltas = new ArrayList<TransformedWaveletDelta>();
      target.getTransformedDeltaHistory(beginVersion, endVersion, new Receiver<TransformedWaveletDelta>() {

        @Override
        public boolean put(TransformedWaveletDelta delta) {
          transformedDeltas.add(delta);
          return index.getAndIncrement() < interruptIndex;
        }
      });
      assertTrue(Iterables.elementsEqual(expected, transformedDeltas));
    }
    {
      List<ByteStringMessage<ProtocolAppliedWaveletDelta>> expected =
          Lists.newArrayListWithExpectedSize(interruptIndex+1);
      for (int i=0; i <= interruptIndex; i++) {
        expected.add(deltas[i].getAppliedDelta());
      }
      final AtomicInteger index = new AtomicInteger(0);
      final List<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>> appliedDeltas =
          new ArrayList<ByteStringMessage<Proto.ProtocolAppliedWaveletDelta>>();
      target.getAppliedDeltaHistory(beginVersion, endVersion,
          new Receiver<ByteStringMessage<ProtocolAppliedWaveletDelta>>() {

        @Override
        public boolean put(ByteStringMessage<ProtocolAppliedWaveletDelta> delta) {
          appliedDeltas.add(delta);
          return index.getAndIncrement() < interruptIndex;
        }
      });
      assertTrue(Iterables.elementsEqual(expected, appliedDeltas));
    }
  }

  public void checkSingleDeltaPersistFutureDone() throws Exception {
    appendDeltas(d1);
    Future<Void> future = target.persist(d1.getResultingVersion());
    awaitPersistence();
    assertTrue(future.isDone());
    assertEquals(null, future.get());
    assertEquals(d1.getResultingVersion(), target.getLastPersistedVersion());
  }

  public void checkManyDeltasPersistFutureDone() throws Exception {
    appendDeltas(d1, d2, d3);
    Future<Void> future = target.persist(d3.getResultingVersion());
    awaitPersistence();
    assertTrue(future.isDone());
    assertEquals(null, future.get());
    assertEquals(d3.getResultingVersion(), target.getLastPersistedVersion());
  }

  public void testCanPersistOnlySomeDeltas() throws Exception {
    appendDeltas(d1, d2, d3);
    Future<Void> future = target.persist(d2.getResultingVersion());
    awaitPersistence();
    assertTrue(future.isDone());
    assertEquals(null, future.get());
    assertEquals(d2.getResultingVersion(), target.getLastPersistedVersion());

    future = target.persist(d3.getResultingVersion());
    awaitPersistence();
    assertTrue(future.isDone());
    assertEquals(null, future.get());
    assertEquals(d3.getResultingVersion(), target.getLastPersistedVersion());
  }

  /**
   * Applies a delta to the target.
   */
  private void appendDeltas(WaveletDeltaRecord... deltas) throws InvalidProtocolBufferException,
      OperationException {
    for (WaveletDeltaRecord delta : deltas) {
      target.appendDelta(delta);
    }
  }


  /**
   * Creates a delta of no-ops and builds the corresponding applied and
   * transformed delta objects.
   */
  private static WaveletDeltaRecord makeDelta(HashedVersion appliedAtVersion, long timestamp,
      int numOps) throws InvalidProtocolBufferException {
    // Use no-op delta so the ops can actually apply.
    WaveletDelta delta = UTIL.makeNoOpDelta(appliedAtVersion, timestamp, numOps);
    ByteStringMessage<ProtocolAppliedWaveletDelta> appliedDelta =
        WaveServerTestUtil.buildAppliedDelta(delta, timestamp);
    TransformedWaveletDelta transformedDelta =
        AppliedDeltaUtil.buildTransformedDelta(appliedDelta, delta);
    return new WaveletDeltaRecord(appliedAtVersion, appliedDelta, transformedDelta);
  }
}
TOP

Related Classes of org.waveprotocol.box.server.waveserver.WaveletStateTestBase

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.