### Question:
DetermineCommonAncestorTask extends AbstractEthTask<BlockHeader> { public static DetermineCommonAncestorTask create( final ProtocolSchedule protocolSchedule, final ProtocolContext protocolContext, final EthContext ethContext, final EthPeer peer, final int headerRequestSize, final MetricsSystem metricsSystem) { return new DetermineCommonAncestorTask( protocolSchedule, protocolContext, ethContext, peer, headerRequestSize, metricsSystem); } private  DetermineCommonAncestorTask(
      final ProtocolSchedule protocolSchedule,
      final ProtocolContext protocolContext,
      final EthContext ethContext,
      final EthPeer peer,
      final int headerRequestSize,
      final MetricsSystem metricsSystem); static DetermineCommonAncestorTask create(
      final ProtocolSchedule protocolSchedule,
      final ProtocolContext protocolContext,
      final EthContext ethContext,
      final EthPeer peer,
      final int headerRequestSize,
      final MetricsSystem metricsSystem);  }### Answer:
@Test public void shouldFailIfPeerDisconnects() { final Block block = blockDataGenerator.nextBlock(localBlockchain.getChainHeadBlock()); localBlockchain.appendBlock(block, blockDataGenerator.receipts(block)); final RespondingEthPeer respondingEthPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager); final EthTask<BlockHeader> task = DetermineCommonAncestorTask.create( protocolSchedule, protocolContext, ethContext, respondingEthPeer.getEthPeer(), defaultHeaderRequestSize, metricsSystem); final AtomicReference<Throwable> failure = new AtomicReference<>(); final CompletableFuture<BlockHeader> future = task.run(); future.whenComplete( (response, error) -> { failure.set(error); }); respondingEthPeer.disconnect(DisconnectReason.CLIENT_QUITTING); assertThat(failure.get()).isNotNull(); final Throwable error = ExceptionUtils.rootCause(failure.get()); assertThat(error).isInstanceOf(EthTaskException.class); assertThat(((EthTaskException) error).reason()) .isEqualTo(EthTaskException.FailureReason.PEER_DISCONNECTED); }
@Test public void shouldHandleEmptyResponses() { final Blockchain remoteBlockchain = setupLocalAndRemoteChains(11, 11, 5); final RespondingEthPeer.Responder emptyResponder = RespondingEthPeer.emptyResponder(); final RespondingEthPeer.Responder fullResponder = RespondingEthPeer.blockchainResponder(remoteBlockchain); final RespondingEthPeer respondingEthPeer = EthProtocolManagerTestUtil.createPeer(ethProtocolManager); final EthTask<BlockHeader> task = DetermineCommonAncestorTask.create( protocolSchedule, protocolContext, ethContext, respondingEthPeer.getEthPeer(), defaultHeaderRequestSize, metricsSystem); final CompletableFuture<BlockHeader> future = task.run(); respondingEthPeer.respond(emptyResponder); assertThat(future).isNotDone(); respondingEthPeer.respondWhile(fullResponder, () -> !future.isDone()); assertThat(future).isDone(); assertThat(future).isNotCompletedExceptionally(); final BlockHeader expectedResult = remoteBlockchain.getBlockHeader(4).get(); assertThat(future).isCompletedWithValue(expectedResult); }
@Test public void returnsImmediatelyWhenThereIsNoWorkToDo() throws Exception { final RespondingEthPeer respondingEthPeer = spy(EthProtocolManagerTestUtil.createPeer(ethProtocolManager)); final EthPeer peer = spy(respondingEthPeer.getEthPeer()); final EthTask<BlockHeader> task = DetermineCommonAncestorTask.create( protocolSchedule, protocolContext, ethContext, peer, defaultHeaderRequestSize, metricsSystem); final CompletableFuture<BlockHeader> result = task.run(); assertThat(result).isCompletedWithValue(localGenesisBlock.getHeader()); verify(peer, times(0)).getHeadersByHash(any(), anyInt(), anyInt(), anyBoolean()); verify(peer, times(0)).getHeadersByNumber(anyLong(), anyInt(), anyInt(), anyBoolean()); verify(peer, times(0)).send(any()); }