/** * Connects the channel at the provided version. */ private void connectChannel(long version, byte[] signature) throws ChannelException { final HashedVersion signatureInfo = HashedVersion.of(version, signature); deltaChannel = new MockWaveletDeltaChannel(); cc = new ConcurrencyControl(ccLogger, signatureInfo); operationChannel = new OperationChannelImpl(opLogger, deltaChannel, cc, Accessibility.READ_WRITE); operationChannel.setListener(listener); operationChannel.onConnection(signatureInfo, signatureInfo); }
/** * Fails and reconnects the channel at the provided connection version and * current version. The channel is expected to provide a distinct version * matching the connect version. If expectRetransmission is not null expects * the channel to attempt to send that message on reconnection. */ private void reconnectChannel(long connectVersion, byte[] connectSignature, long currentVersion, byte[] currentSignature, WaveletDelta expectRetransmission) throws ChannelException { final HashedVersion connectHashedVersion = HashedVersion.of(connectVersion, connectSignature); final HashedVersion currentHashedVersion = HashedVersion.of(currentVersion, currentSignature); // Simulate failure elsewhere. operationChannel.reset(); // Check reconnect versions provided by the channel include the // version we'll reconnect at. List<HashedVersion> reconnectVersions = operationChannel.getReconnectVersions(); assertTrue(reconnectVersions.size() > 0); boolean matchedSignature = false; for (HashedVersion rcv : reconnectVersions) { if (connectVersion == rcv.getVersion() && connectSignature.equals(rcv.getHistoryHash())) { matchedSignature = true; } } assertTrue("No matching signature provided", matchedSignature); // Simulate reconnection reconnection message from delta channel. if (expectRetransmission != null) { deltaChannel.expectSend(expectRetransmission); } operationChannel.onConnection(connectHashedVersion, currentHashedVersion); }
public void testReconnectAfterCommit() throws Exception { final int initialVersion = 42; connectChannel(initialVersion, SIG1); sendAndCheckRandomOp(operationChannel, 42, SIG1); operationChannel.onAck(1, HashedVersion.of(43, SIG2)); // Take the fake op resulting from ack that updates version info. listener.checkOpsReceived(1); assertNotNull(operationChannel.receive()); listener.clear(); operationChannel.onCommit(43); // Causes cc to remove old operations from memory reconnectChannel(43, SIG2); // Receive next delta. TransformedWaveletDelta delta = createRandomTransformedDelta(43, 1, SIG3); operationChannel.onDelta(delta); listener.checkOpsReceived(1); assertNotNull(operationChannel.receive()); assertNull(operationChannel.receive()); checkExpectationsSatisfied(); }
/** * Tests reconnection where the server does not provide a matching * signature. Expect failure. */ public void testReconnectionFailure() throws ChannelException { final int initialVersion = 42; final byte[] initialSignature = SIG1; connectChannel(initialVersion, initialSignature); // Simulate failure operationChannel.reset(); // Server presents unknown reconnect version final HashedVersion reconnectVersion = HashedVersion.of(66, SIG2); try { operationChannel.onConnection(reconnectVersion, reconnectVersion); fail("Should have thrown ChannelException"); } catch (ChannelException expected) { } }
operationChannel.onDelta(createRandomTransformedDelta(42, 1, signature43)); assertNotNull(operationChannel.receive()); listener.clear(); operationChannel.onDelta(delta2); listener.checkOpsReceived(1); assertNotNull(operationChannel.receive()); listener.clear(); operationChannel.send(new WaveletOperation[] { delta3.get(0) }); listener.checkOpsReceived(0); operationChannel.onAck(1, HashedVersion.of(45, SIG5)); checkExpectationsSatisfied();
/** * Test receiving a simple delta that was committed. */ public void testSimpleReceive() throws ChannelException { final int initialVersion = 42; connectChannel(initialVersion, SIG1); operationChannel.onDelta(createRandomTransformedDelta(initialVersion, 1, SIG2)); listener.checkOpsReceived(1); listener.clear(); assertNotNull(operationChannel.receive()); listener.checkOpsReceived(0); // TODO(anorth): test OnCommit by mocking CC operationChannel.onCommit(initialVersion + 1); checkExpectationsSatisfied(); }
public void testSimpleSendAndAck() throws Exception { final int initialVersion = 42; connectChannel(initialVersion, SIG1); sendAndCheckRandomOp(operationChannel, initialVersion, SIG1); listener.clear(); HashedVersion signature = HashedVersion.of(43, SIG2); operationChannel.onAck(1, signature); // Listener should receive a version update op. listener.checkOpsReceived(1); WaveletOperation op = operationChannel.receive(); WaveletOperationContext context = op.getContext(); assertEquals(1, context.getVersionIncrement()); assertEquals(signature, context.getHashedVersion()); }
/** * Check that the client sends the correct last known signatures. */ public void testReconnectWhereAnAckWasNotCommittedCanBeRecovered() throws Exception { final int initialVersion = 42; connectChannel(initialVersion, SIG1); // Send op and expect an Ack. byte[] signature43 = SIG2; byte[] signature44 = SIG3; sendAndCheckRandomOp(operationChannel, 42, SIG1); operationChannel.onAck(1, HashedVersion.of(43, signature43)); // Send another op and expect an Ack. WaveletDelta delta2 = sendAndCheckRandomOp(operationChannel, 43, signature43); operationChannel.onAck(1, HashedVersion.of(44, signature44)); // send commit for first Ack. operationChannel.onCommit(43); // Check that we reconnect, the server went down and has a LCV of 43. // Channel will resend delta2. reconnectChannel(43, signature43, 43, signature43, delta2); deltaChannel.checkExpectationsSatisfied(); checkExpectationsSatisfied(); }
@Override public InternalOperationChannel create(WaveletDeltaChannel deltaChannel, WaveletId waveletId, HashedVersion startVersion, Accessibility accessibility) { ConcurrencyControl cc = new ConcurrencyControl(loggers.cc, startVersion); if (unsavedDataListenerFactory != null) { cc.setUnsavedDataListener(unsavedDataListenerFactory.create(waveletId)); } return new OperationChannelImpl(loggers.ops, deltaChannel, cc, accessibility); } };
/** * Test a simple connect then successful disconnection. */ public void testConnectThenDisconnectSuccess() throws ChannelException { connectChannel(10, SIG1); listener.checkOpsReceived(0); // Disconnect operationChannel.reset(); checkExpectationsSatisfied(); }
private WaveletDelta sendAndCheckRandomOp(OperationChannelImpl opChannel, long currentVersion, byte[] signature) throws ChannelException { WaveletDelta delta = UTIL.makeDelta(HashedVersion.of(currentVersion, signature), 0L, 1); deltaChannel.expectSend(delta); opChannel.send(new WaveletOperation[] {delta.get(0)}); return delta; }
/** * Test simple NACK and onDelta. * Nack is not supposed to happen, so it should be death. */ public void testSimpleNackAndReceive() throws Exception { final int initialVersion = 42; connectChannel(initialVersion, SIG1); sendAndCheckRandomOp(operationChannel, initialVersion, SIG1); listener.clear(); try { operationChannel.onNack(ResponseCode.OK, null, 43); fail("Should have thrown ChannelException"); } catch (ChannelException expected) { } checkExpectationsSatisfied(); }
/** * Test reconnect where there was an unACKed delta during the failure which * was not received by the server, expect the client to immediately resend the * delta. */ public void testReconnectWithPendingAckNotRecievedByServer() throws Exception { final int initialVersion = 42; final byte[] ackSignature = SIG2; connectChannel(initialVersion, SIG1); WaveletDelta delta = sendAndCheckRandomOp(operationChannel, 42, SIG1); // The server's version is still 42 when it responds. Expect a retransmission. reconnectChannel(initialVersion, SIG1, initialVersion, SIG1, delta); // Now ack. listener.checkOpsReceived(0); operationChannel.onAck(1, HashedVersion.of(43, ackSignature)); // There should be a fake op resulting from ack that updates version info listener.checkOpsReceived(1); checkExpectationsSatisfied(); }
operationChannel.onDelta(createRandomTransformedDelta(42, 1, signature43)); assertNotNull(operationChannel.receive()); listener.clear(); operationChannel.onDelta(delta2); listener.checkOpsReceived(1); assertNotNull(operationChannel.receive()); listener.clear(); operationChannel.send(new WaveletOperation[] { delta3.get(0) }); listener.checkOpsReceived(0); operationChannel.onAck(1, HashedVersion.of(45, SIG5)); checkExpectationsSatisfied();
/** * Test receiving a simple delta that was committed. */ public void testSimpleReceive() throws ChannelException { final int initialVersion = 42; connectChannel(initialVersion, SIG1); operationChannel.onDelta(createRandomTransformedDelta(initialVersion, 1, SIG2)); listener.checkOpsReceived(1); listener.clear(); assertNotNull(operationChannel.receive()); listener.checkOpsReceived(0); // TODO(anorth): test OnCommit by mocking CC operationChannel.onCommit(initialVersion + 1); checkExpectationsSatisfied(); }
public void testSimpleSendAndAck() throws Exception { final int initialVersion = 42; connectChannel(initialVersion, SIG1); sendAndCheckRandomOp(operationChannel, initialVersion, SIG1); listener.clear(); HashedVersion signature = HashedVersion.of(43, SIG2); operationChannel.onAck(1, signature); // Listener should receive a version update op. listener.checkOpsReceived(1); WaveletOperation op = operationChannel.receive(); WaveletOperationContext context = op.getContext(); assertEquals(1, context.getVersionIncrement()); assertEquals(signature, context.getHashedVersion()); }
/** * Tests reconnection where the server does not provide a matching * signature. Expect failure. */ public void testReconnectionFailure() throws ChannelException { final int initialVersion = 42; final byte[] initialSignature = SIG1; connectChannel(initialVersion, initialSignature); // Simulate failure operationChannel.reset(); // Server presents unknown reconnect version final HashedVersion reconnectVersion = HashedVersion.of(66, SIG2); try { operationChannel.onConnection(reconnectVersion, reconnectVersion); fail("Should have thrown ChannelException"); } catch (ChannelException expected) { } }