/**
* Copyright 2009 Google Inc.
*
* Licensed 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.wave.examples.fedone.waveserver;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.Nullable;
import junit.framework.TestCase;
import org.waveprotocol.wave.examples.fedone.common.HashedVersion;
import org.waveprotocol.wave.examples.fedone.common.WaveletOperationSerializer;
import static org.waveprotocol.wave.examples.fedone.common.WaveletOperationSerializer.serialize;
import org.waveprotocol.wave.examples.fedone.waveserver.ClientFrontend.OpenListener;
import org.waveprotocol.wave.federation.Proto.ProtocolHashedVersion;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletDelta;
import org.waveprotocol.wave.federation.Proto.ProtocolWaveletOperation;
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.wave.NoOp;
import org.waveprotocol.wave.model.operation.wave.WaveletDelta;
import org.waveprotocol.wave.model.wave.ParticipantId;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Tests {@link UserManager}.
*
*
*/
public class UserManagerTest extends TestCase {
private static final WaveId W1 = new WaveId("waveId", "1");
private static final WaveId W2 = new WaveId("waveId", "2");
private static final WaveletId WA = new WaveletId("waveletId", "A");
private static final WaveletId WB = new WaveletId("waveletId", "B");
private static final WaveletName W1A = WaveletName.of(W1, WA);
private static final WaveletName W2A = WaveletName.of(W2, WA);
private static final WaveletName W2B = WaveletName.of(W2, WB);
private static final ParticipantId USER = new ParticipantId("user@host.com");
private static final ProtocolWaveletDelta DELTA =
serialize(new WaveletDelta(USER, ImmutableList.of(NoOp.INSTANCE, NoOp.INSTANCE)),
HashedVersion.UNSIGNED_VERSION_0);
private static final ProtocolHashedVersion END_VERSION = serialize(HashedVersion.unsigned(2));
private static final DeltaSequence DELTAS =
new DeltaSequence(ImmutableList.of(DELTA), END_VERSION);
private UserManager m;
@Override
protected void setUp() throws Exception {
super.setUp();
m = new UserManager();
}
/** Tests that adding an existing participant throws an exception. */
public void testAddExistingParticipant() {
m.addWavelet(W1A);
try {
m.addWavelet(W1A);
fail("Should have thrown IllegalStateException");
} catch (IllegalStateException expected) {
// pass
}
}
/** Tests that removing a non-participant throws an exception. */
public void testRemoveNonParticipant() {
try {
m.removeWavelet(W1A);
fail("Should have thrown IllegalStateException");
} catch (IllegalStateException expected) {
// pass
}
}
/** Tests that isParticipant() agrees with added and removed wavelets. */
public void testIsParticipant() {
assertFalse(m.isParticipant(W1A));
m.addWavelet(W2A);
assertFalse(m.isParticipant(W1A));
m.addWavelet(W1A);
assertTrue(m.isParticipant(W1A));
m.removeWavelet(W1A);
assertFalse(m.isParticipant(W1A));
}
/**
* Tests that {@link UserManager#getWaveletIds(WaveId)} accurately reflects
* the added and removed wavelets.
*/
public void testGetWaveletIds() {
assertEquals(ImmutableSet.<WaveletId>of(), m.getWaveletIds(W1));
m.addWavelet(W1A);
assertEquals(ImmutableSet.<WaveletId>of(WA), m.getWaveletIds(W1));
m.addWavelet(W2A);
assertEquals(ImmutableSet.<WaveletId>of(WA), m.getWaveletIds(W1));
assertEquals(ImmutableSet.<WaveletId>of(WA), m.getWaveletIds(W2));
m.addWavelet(W2B);
assertEquals(ImmutableSet.<WaveletId>of(WA, WB), m.getWaveletIds(W2));
m.removeWavelet(W1A);
assertEquals(ImmutableSet.<WaveletId>of(), m.getWaveletIds(W1));
}
/**
* Mock implementation that only implements toString() (for easy
* interpretation of test failures).
*/
private static class MockListener implements OpenListener {
private final String serializedForm;
public MockListener(String serializedForm) {
this.serializedForm = serializedForm;
}
@Override
public void onFailure(String errorMessage) {
throw new UnsupportedOperationException();
}
@Override
public void onUpdate(WaveletName waveletName,
@Nullable WaveletSnapshotAndVersions snapshot,
List<ProtocolWaveletDelta> deltas, @Nullable ProtocolHashedVersion endVersion,
@Nullable ProtocolHashedVersion committedVersion) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
return serializedForm;
}
}
/**
* Tests that {@link UserManager#matchSubscriptions(WaveletName)} accurately
* reflects subscription, independent of whether we actually are on any
* wavelets.
*/
public void testMatchSubscriptions() {
assertEquals(ImmutableList.<OpenListener>of(), m.matchSubscriptions(W1A));
OpenListener l1 = new MockListener("listener 1");
OpenListener l2 = new MockListener("listener 2");
OpenListener l3 = new MockListener("listener 3");
OpenListener l4 = new MockListener("listener 4");
OpenListener l5 = new MockListener("listener 5");
m.subscribe(W2, ImmutableSet.of(WA.serialise()), l1);
m.subscribe(W2, ImmutableSet.of(""), l2);
m.subscribe(W1, ImmutableSet.of("", WA.serialise()), l3);
m.subscribe(W2, ImmutableSet.of("nonexisting-prefix"), l4);
m.subscribe(W2, ImmutableSet.of("wav", "waveletId"), l5);
assertEquals(ImmutableList.of(l1, l2, l5), m.matchSubscriptions(W2A));
assertEquals(ImmutableList.of(l2, l5), m.matchSubscriptions(W2B));
m.addWavelet(W2B); // Doesn't make any difference
assertEquals(ImmutableList.of(l1, l2, l5), m.matchSubscriptions(W2A));
assertEquals(ImmutableList.of(l2, l5), m.matchSubscriptions(W2B));
}
/** Tests onUpdate() for a wavelet we're not a participant of. */
public void testOnUpdateForUnknownWavelet() {
try {
m.onUpdate(W1A, DELTAS);
fail("Should have thrown IllegalStateException");
} catch (IllegalStateException expected) {
// pass
}
}
/** Tests onCommit() for a wavelet we're not a participant of. */
public void testOnCommitForUnknownWavelet() {
try {
m.onCommit(W1A, serialize(HashedVersion.UNSIGNED_VERSION_0));
fail("Should have thrown IllegalStateException");
} catch (IllegalStateException expected) {
// pass
}
}
/**
* Tests that sending a single delta with the correct start version
* number 0 to a wavelet we're subscribed to succeeds.
*/
public void testUpdateSingleDeltaVersion() {
m.addWavelet(W1A);
m.onUpdate(W1A, DELTAS); // pass
}
/**
* Test that a second delta marked as version 2 = DELTA.getOperationCount()
* succeeds.
*/
public void testUpdateSeveralDeltas() {
// Check that test was set up correctly
assertEquals(2, DELTA.getOperationCount());
ProtocolWaveletOperation noOp = serialize(NoOp.INSTANCE);
ProtocolHashedVersion v2 =
WaveletOperationSerializer.serialize(HashedVersion.unsigned(2));
ProtocolWaveletDelta delta2 = ProtocolWaveletDelta.newBuilder().setAuthor(
USER.getAddress()).addOperation(noOp).setHashedVersion(v2).build();
m.addWavelet(W1A);
ProtocolHashedVersion endVersion2 = serialize(HashedVersion.unsigned(3));
m.onUpdate(W1A, new DeltaSequence(ImmutableList.of(DELTA, delta2), endVersion2)); // success
// Also succeeds when sending the two deltas via separate onUpdates()
m.addWavelet(W2A);
m.onUpdate(W2A, DELTAS); // success
m.onUpdate(W2A, new DeltaSequence(ImmutableList.of(delta2), endVersion2)); // success
}
/**
* Tests that subscribed listeners are only invoked from onUpdate when
* at least one delta is passed in.
*/
public void testListenersInvokedOnlyForNonemptyDeltas() {
final AtomicInteger updates = new AtomicInteger(0);
OpenListener listener = new MockListener("1") {
@Override
public void onUpdate(WaveletName waveletName,
@Nullable WaveletSnapshotAndVersions snapshot,
List<ProtocolWaveletDelta> deltas, @Nullable ProtocolHashedVersion endVersion,
@Nullable ProtocolHashedVersion committedVersion) {
updates.incrementAndGet();
assertEquals(DELTAS, new DeltaSequence(deltas, endVersion));
}
};
m.addWavelet(W1A);
m.subscribe(W1, ImmutableSet.of(""), listener);
m.onUpdate(W1A, DeltaSequence.empty(serialize(HashedVersion.UNSIGNED_VERSION_0)));
assertEquals(0, updates.get());
m.onUpdate(W1A, DELTAS);
assertEquals(1, updates.get());
}
}