下面列出了org.mockito.InOrder#verifyNoMoreInteractions ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Test
void testExecuteShouldUseCookieStoreFromContext() throws IOException
{
CookieStore cookieStore = mock(CookieStore.class);
when(httpTestContext.getCookieStore()).thenReturn(Optional.of(cookieStore));
HttpResponse httpResponse = mockHttpResponse(URL);
httpRequestExecutor.executeHttpRequest(HttpMethod.GET, URL, Optional.empty());
verify(httpClient).execute(argThat(HttpUriRequest.class::isInstance),
argThat(e -> e != null && e.getAttribute("http.cookie-store") != null));
InOrder orderedHttpTestContext = inOrder(httpTestContext);
verifyHttpTestContext(orderedHttpTestContext, httpResponse);
orderedHttpTestContext.verify(httpTestContext).releaseRequestData();
orderedHttpTestContext.verifyNoMoreInteractions();
assertThat(logger.getLoggingEvents(), equalTo(List.of(createResponseTimeLogEvent(httpResponse))));
}
@Test
void clickElementNotClickableStaleReferenceExceptionNotChrome()
{
when(webDriverManager.isTypeAnyOf(WebDriverType.CHROME)).thenReturn(false);
mockBodySearch();
WebDriverException e = new WebDriverException(ELEMENT_IS_NOT_CLICKABLE_AT_POINT);
WebDriverException e2 = new WebDriverException(STALE_EXCEPTION);
doThrow(e).doThrow(e2).when(webElement).click();
ClickResult result = mouseActions.click(webElement);
verify(webElement, never()).sendKeys("");
assertFalse(result.isNewPageLoaded());
InOrder ordered = inOrder(javascriptActions, alertActions, eventBus, webUiContext, softAssert);
ordered.verify(javascriptActions).scrollElementIntoViewportCenter(webElement);
ordered.verify(softAssert).recordFailedAssertion(COULD_NOT_CLICK_ERROR_MESSAGE + e2);
ordered.verifyNoMoreInteractions();
}
private void verifyWebElement(int clickAttempts, boolean alertPresent, boolean newPageLoaded, ClickResult result)
{
verify(webElement, times(clickAttempts)).click();
assertTrue(result.isClicked());
assertEquals(newPageLoaded, result.isNewPageLoaded());
InOrder ordered = inOrder(javascriptActions, alertActions, waitActions, eventBus, webUiContext);
ordered.verify(javascriptActions).scrollElementIntoViewportCenter(webElement);
ordered.verify(alertActions).isAlertPresent();
if (!alertPresent)
{
ordered.verify(waitActions).waitForPageLoad();
ordered.verify(alertActions).waitForAlert(webDriver);
ordered.verify(eventBus)
.post(ArgumentMatchers.<PageLoadEndEvent>argThat(arg -> arg.isNewPageLoaded() == newPageLoaded));
}
ordered.verifyNoMoreInteractions();
}
@Test
void testExecuteCommandsViaSftpSuccessfully() throws Exception
{
ChannelSftp channel = mock(ChannelSftp.class);
String pwd = "/Users";
when(channel.pwd()).thenReturn(pwd).thenReturn(pwd);
ServerConfiguration serverConfiguration = new ServerConfiguration();
serverConfiguration.setAgentForwarding(true);
Commands commands = new Commands("pwd; cd ~; pwd");
SftpOutput sftpOutput = sftpExecutor.executeCommand(serverConfiguration, commands, channel);
assertEquals(pwd + System.lineSeparator() + pwd, sftpOutput.getResult());
InOrder ordered = inOrder(channel);
ordered.verify(channel).setAgentForwarding(serverConfiguration.isAgentForwarding());
ordered.verify(channel).connect();
ordered.verify(channel).pwd();
ordered.verify(channel).cd("~");
ordered.verify(channel).pwd();
ordered.verifyNoMoreInteractions();
verifyNoInteractions(softAssert);
}
@Test
public void startSuccessful() throws Exception {
IndexingApplication subject =
new IndexingApplication.Builder(mockConnector, new String[] {})
.setIndexingService(mockIndexingService)
.setHelper(mockHelper)
.build();
subject.start();
InOrder inOrder = inOrder(mockRuntime, mockHelper, mockTraverserBuilder, mockTraverser);
inOrder.verify(mockHelper).createShutdownHookThread(any(ShutdownHook.class));
inOrder.verify(mockHelper).getRuntimeInstance();
inOrder.verify(mockRuntime).addShutdownHook(mockShutdownThread);
inOrder.verify(mockHelper).createContextBuilderInstance();
inOrder.verify(mockHelper).createSchedulerBuilderInstance();
inOrder.verify(mockTraverserBuilder).setConnector(eq(mockConnector));
inOrder.verify(mockTraverserBuilder).setContext(eq(mockContext));
inOrder.verify(mockTraverserBuilder).setShutdownHolder(any());
inOrder.verify(mockTraverser).start();
inOrder.verifyNoMoreInteractions();
}
@Test
void clickElementNotClickableExceptionWithJsChrome()
{
when(webDriverManager.isTypeAnyOf(WebDriverType.CHROME)).thenReturn(true);
mockBodySearch();
WebDriverException e = new WebDriverException(OTHER_ELEMENT_WOULD_RECEIVE_CLICK);
doThrow(e).when(webElement).click();
ClickResult result = mouseActions.click(webElement);
assertFalse(result.isNewPageLoaded());
InOrder ordered = inOrder(javascriptActions, alertActions, eventBus, webUiContext, softAssert);
ordered.verify(javascriptActions).scrollElementIntoViewportCenter(webElement);
ordered.verify(javascriptActions).click(webElement);
ordered.verify(alertActions).waitForAlert(webDriver);
ordered.verify(eventBus).post(any(PageLoadEndEvent.class));
ordered.verifyNoMoreInteractions();
}
@Test
void testRunStoriesAsPaths()
{
BatchedEmbedder spy = createBatchedEmbedderSpy(true);
doNothing().when(spy).generateReportsView();
MetaFilter mockedFilter = mock(MetaFilter.class);
doReturn(mockedFilter).when(spy).metaFilter();
List<String> testStoryPaths = List.of(PATH);
EmbedderControls mockedEmbedderControls = mockEmbedderControls(spy);
when(mockedEmbedderControls.threads()).thenReturn(THREADS);
mockBatchExecutionConfiguration(true);
spy.runStoriesAsPaths(Map.of(BATCH, testStoryPaths));
InOrder ordered = inOrder(spy, embedderMonitor, storyManager, bddRunContext, bddVariableContext);
ordered.verify(spy).processSystemProperties();
ordered.verify(embedderMonitor).usingControls(mockedEmbedderControls);
List<ExecutorService> service = new ArrayList<>(1);
ordered.verify(spy).useExecutorService(argThat(service::add));
ordered.verify(bddRunContext).putRunningBatch(BATCH);
ordered.verify(storyManager).runStoriesAsPaths(eq(testStoryPaths), eq(mockedFilter), any(BatchFailures.class));
ordered.verify(bddVariableContext).clearVariables();
ordered.verify(bddRunContext).removeRunningBatch();
ordered.verify(spy).generateReportsView();
ordered.verifyNoMoreInteractions();
verifyExecutorService(service.get(0));
}
/**
* This is a somewhat contrived test case . The first committed offset should be the offset at (0), but this is
* checking if that isn't the latest (consumer is not up-to-date) but somehow even got something committed. Its
* strange, but has been seen to happen with old consumers whose offset have fallen off the stream or other,
* strange cases given the asynchronous nature of the interactions between burrow and kafka.
*/
@Test
public void testSeekToBeginningForFirstOffset() throws Exception {
Clock clock = Clock.fixed(Instant.now(), Clock.systemDefaultZone().getZone());
long ts = clock.millis() - 1;
ConsumerRecords recordsOneMilliBefore = createConsumerRecordsAtTimestamps(ts);
Consumer kafka = mock(Consumer.class);
when(kafka.poll(Duration.ofSeconds(2))).thenReturn(recordsOneMilliBefore);
// this consumer is at the first position (offset 0), so we expect to go back one offset
FreshnessTracker.ConsumerOffset consumer =
new FreshnessTracker.ConsumerOffset("cluster", "group", "topic", 1, 0, false);
FreshnessMetrics metrics = new FreshnessMetrics();
FreshnessTracker work = new FreshnessTracker(consumer, kafka, metrics);
work.setClockForTesting(clock);
work.run();
InOrder ordered = inOrder(kafka);
// seeking the committed offset, but go back 1 to actual message
ordered.verify(kafka).seekToBeginning(Collections.singletonList(new TopicPartition("topic", 1)));
ordered.verify(kafka).poll(Duration.ofSeconds(2));
ordered.verifyNoMoreInteractions();
double noDelta = 0;
assertEquals("Freshness should be zero for no lag",
1, metrics.freshness.labels("cluster", "group", "topic", "1").get(), noDelta);
assertEquals(0, metrics.failed.labels("cluster", "group").get(), 0);
}
@Test
void shouldExecuteSubStepWithoutParameters()
{
StepResult stepResult = mock(StepResult.class);
InOrder ordered = inOrder(subStepsListener, step, stepResult);
when(step.perform(storyReporter, null)).thenReturn(stepResult);
subSteps.execute(Optional.empty());
ordered.verify(subStepsListener).beforeSubSteps();
ordered.verify(stepResult).describeTo(storyReporter);
ordered.verify(subStepsListener).afterSubSteps();
ordered.verifyNoMoreInteractions();
}
@Test
public void serviceConfigDisablesHealthCheckWhenRpcActive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, resolutionAttrs);
verify(origLb).handleResolvedAddressGroups(same(resolvedAddressList), same(resolutionAttrs));
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(subchannel).isSameAs(subchannels[0]);
InOrder inOrder = inOrder(origLb);
hcLbEventDelivery.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(origLb).handleSubchannelState(
same(subchannel), eq(ConnectivityStateInfo.forNonError(CONNECTING)));
inOrder.verifyNoMoreInteractions();
HealthImpl healthImpl = healthImpls[0];
assertThat(healthImpl.calls).hasSize(1);
ServerSideCall serverCall = healthImpl.calls.poll();
assertThat(serverCall.cancelled).isFalse();
// NameResolver gives an update without service config, thus health check will be disabled
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, Attributes.EMPTY);
// Health check RPC cancelled.
assertThat(serverCall.cancelled).isTrue();
// Subchannel uses original state
inOrder.verify(origLb).handleSubchannelState(
same(subchannel), eq(ConnectivityStateInfo.forNonError(READY)));
inOrder.verify(origLb).handleResolvedAddressGroups(
same(resolvedAddressList), same(Attributes.EMPTY));
verifyNoMoreInteractions(origLb);
assertThat(healthImpl.calls).isEmpty();
}
@Test
public void serviceConfigDisablesHealthCheckWhenRpcInactive() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, resolutionAttrs);
verify(origLb).handleResolvedAddressGroups(same(resolvedAddressList), same(resolutionAttrs));
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(subchannel).isSameAs(subchannels[0]);
InOrder inOrder = inOrder(origLb);
// Underlying subchannel is not READY initially
ConnectivityStateInfo underlyingErrorState =
ConnectivityStateInfo.forTransientFailure(
Status.UNAVAILABLE.withDescription("connection refused"));
hcLbEventDelivery.handleSubchannelState(subchannel, underlyingErrorState);
inOrder.verify(origLb).handleSubchannelState(same(subchannel), same(underlyingErrorState));
inOrder.verifyNoMoreInteractions();
// NameResolver gives an update without service config, thus health check will be disabled
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, Attributes.EMPTY);
inOrder.verify(origLb).handleResolvedAddressGroups(
same(resolvedAddressList), same(Attributes.EMPTY));
// Underlying subchannel is now ready
hcLbEventDelivery.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
// Since health check is disabled, READY state is propagated directly.
inOrder.verify(origLb).handleSubchannelState(
same(subchannel), eq(ConnectivityStateInfo.forNonError(READY)));
// and there is no health check activity.
assertThat(healthImpls[0].calls).isEmpty();
verifyNoMoreInteractions(origLb);
}
@Test
public void multiResource_cleanupGracefully() throws Throwable {
// setup
Resource resource1 = mock(Resource.class);
Resource resource2 = mock(Resource.class);
Resource resource3 = mock(Resource.class);
doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
doReturn(true).when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
Statement statement = mock(Statement.class);
InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
// run
grpcCleanup.register(resource1);
grpcCleanup.register(resource2);
grpcCleanup.register(resource3);
grpcCleanup.apply(statement, null /* description*/).evaluate();
// Verify.
inOrder.verify(statement).evaluate();
inOrder.verify(resource3).cleanUp();
inOrder.verify(resource2).cleanUp();
inOrder.verify(resource1).cleanUp();
inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verifyNoMoreInteractions();
verify(resource1, never()).forceCleanUp();
verify(resource2, never()).forceCleanUp();
verify(resource3, never()).forceCleanUp();
}
@Test
void shouldExecuteSubStepAndRethrowError()
{
StepResult stepResult = mock(StepResult.class);
InOrder ordered = inOrder(step, stepResult);
when(step.perform(storyReporter, null)).thenReturn(stepResult);
AssertionError error = new AssertionError();
when(stepResult.getFailure()).thenReturn(new UUIDExceptionWrapper(error));
AssertionError actual = assertThrows(AssertionError.class, () -> subSteps.execute(Optional.empty()));
assertEquals(error, actual);
ordered.verify(stepResult).describeTo(storyReporter);
ordered.verify(stepResult).getFailure();
ordered.verifyNoMoreInteractions();
}
@Test
void clickElementNotClickableExceptionStaleExceptionChrome()
{
when(webDriverManager.isTypeAnyOf(WebDriverType.CHROME)).thenReturn(true);
mockBodySearch();
WebDriverException e = new WebDriverException(ELEMENT_IS_NOT_CLICKABLE_AT_POINT);
WebDriverException e2 = new WebDriverException(STALE_EXCEPTION);
doThrow(e).doThrow(e2).when(webElement).click();
mouseActions.click(webElement);
InOrder ordered = inOrder(javascriptActions, alertActions, eventBus, webUiContext, softAssert);
ordered.verify(javascriptActions).scrollElementIntoViewportCenter(webElement);
ordered.verify(softAssert).recordFailedAssertion(COULD_NOT_CLICK_ERROR_MESSAGE + e2);
ordered.verifyNoMoreInteractions();
}
@Test
public void serviceConfigDisablesHealthCheckWhenRetryPending() {
Attributes resolutionAttrs = attrsWithHealthCheckService("TeeService");
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, resolutionAttrs);
verify(origLb).handleResolvedAddressGroups(same(resolvedAddressList), same(resolutionAttrs));
verifyNoMoreInteractions(origLb);
Subchannel subchannel = createSubchannel(0, Attributes.EMPTY);
assertThat(subchannel).isSameAs(subchannels[0]);
InOrder inOrder = inOrder(origLb);
hcLbEventDelivery.handleSubchannelState(subchannel, ConnectivityStateInfo.forNonError(READY));
inOrder.verify(origLb).handleSubchannelState(
same(subchannel), eq(ConnectivityStateInfo.forNonError(CONNECTING)));
inOrder.verifyNoMoreInteractions();
HealthImpl healthImpl = healthImpls[0];
assertThat(healthImpl.calls).hasSize(1);
// Server closes the stream without responding. Client in retry backoff
assertThat(clock.getPendingTasks()).isEmpty();
healthImpl.calls.poll().responseObserver.onCompleted();
assertThat(clock.getPendingTasks()).hasSize(1);
inOrder.verify(origLb).handleSubchannelState(
same(subchannel),
unavailableStateWithMsg(
"Health-check stream unexpectedly closed with " + Status.OK + " for 'TeeService'"));
// NameResolver gives an update without service config, thus health check will be disabled
hcLbEventDelivery.handleResolvedAddressGroups(resolvedAddressList, Attributes.EMPTY);
// Retry timer is cancelled
assertThat(clock.getPendingTasks()).isEmpty();
// No retry was attempted
assertThat(healthImpl.calls).isEmpty();
// Subchannel uses original state
inOrder.verify(origLb).handleSubchannelState(
same(subchannel), eq(ConnectivityStateInfo.forNonError(READY)));
inOrder.verify(origLb).handleResolvedAddressGroups(
same(resolvedAddressList), same(Attributes.EMPTY));
verifyNoMoreInteractions(origLb);
}
@Test
public void multiResource_awaitReleasedFails() throws Throwable {
// setup
Resource resource1 = mock(Resource.class);
Resource resource2 = mock(Resource.class);
Resource resource3 = mock(Resource.class);
doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
doReturn(false).when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
Statement statement = mock(Statement.class);
InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
// run
grpcCleanup.register(resource1);
grpcCleanup.register(resource2);
grpcCleanup.register(resource3);
boolean cleanupFailed = false;
try {
grpcCleanup.apply(statement, null /* description*/).evaluate();
} catch (AssertionError e) {
cleanupFailed = true;
}
// verify
assertTrue(cleanupFailed);
inOrder.verify(statement).evaluate();
inOrder.verify(resource3).cleanUp();
inOrder.verify(resource2).cleanUp();
inOrder.verify(resource1).cleanUp();
inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource2).forceCleanUp();
inOrder.verify(resource1).forceCleanUp();
inOrder.verifyNoMoreInteractions();
verify(resource3, never()).forceCleanUp();
verify(resource1, never()).awaitReleased(anyLong(), any(TimeUnit.class));
}
@Test
public void multiResource_awaitReleasedInterrupted() throws Throwable {
// setup
Resource resource1 = mock(Resource.class);
Resource resource2 = mock(Resource.class);
Resource resource3 = mock(Resource.class);
doReturn(true).when(resource1).awaitReleased(anyLong(), any(TimeUnit.class));
doThrow(new InterruptedException())
.when(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
doReturn(true).when(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
Statement statement = mock(Statement.class);
InOrder inOrder = inOrder(statement, resource1, resource2, resource3);
GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
// run
grpcCleanup.register(resource1);
grpcCleanup.register(resource2);
grpcCleanup.register(resource3);
boolean cleanupFailed = false;
try {
grpcCleanup.apply(statement, null /* description*/).evaluate();
} catch (InterruptedException e) {
cleanupFailed = true;
}
// verify
assertTrue(cleanupFailed);
assertTrue(Thread.interrupted());
inOrder.verify(statement).evaluate();
inOrder.verify(resource3).cleanUp();
inOrder.verify(resource2).cleanUp();
inOrder.verify(resource1).cleanUp();
inOrder.verify(resource3).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource2).awaitReleased(anyLong(), any(TimeUnit.class));
inOrder.verify(resource2).forceCleanUp();
inOrder.verify(resource1).forceCleanUp();
inOrder.verifyNoMoreInteractions();
verify(resource3, never()).forceCleanUp();
verify(resource1, never()).awaitReleased(anyLong(), any(TimeUnit.class));
}
/**
* Verify that if the first resolved address points to a server that cannot be connected, the call
* will end up with the second address which works.
*/
@Test
public void firstResolvedServerFailedToConnect() throws Exception {
final SocketAddress goodAddress = new SocketAddress() {
@Override public String toString() {
return "goodAddress";
}
};
final SocketAddress badAddress = new SocketAddress() {
@Override public String toString() {
return "badAddress";
}
};
InOrder inOrder = inOrder(mockLoadBalancer);
List<SocketAddress> resolvedAddrs = Arrays.asList(badAddress, goodAddress);
FakeNameResolverFactory nameResolverFactory =
new FakeNameResolverFactory.Builder(expectedUri)
.setServers(Collections.singletonList(new EquivalentAddressGroup(resolvedAddrs)))
.build();
channelBuilder.nameResolverFactory(nameResolverFactory);
createChannel();
// Start the call
ClientCall<String, Integer> call = channel.newCall(method, CallOptions.DEFAULT);
Metadata headers = new Metadata();
call.start(mockCallListener, headers);
executor.runDueTasks();
// Simulate name resolution results
EquivalentAddressGroup addressGroup = new EquivalentAddressGroup(resolvedAddrs);
inOrder.verify(mockLoadBalancer).handleResolvedAddressGroups(
eq(Arrays.asList(addressGroup)), eq(Attributes.EMPTY));
Subchannel subchannel = createSubchannelSafely(helper, addressGroup, Attributes.EMPTY);
when(mockPicker.pickSubchannel(any(PickSubchannelArgs.class)))
.thenReturn(PickResult.withSubchannel(subchannel));
subchannel.requestConnection();
inOrder.verify(mockLoadBalancer).handleSubchannelState(
same(subchannel), stateInfoCaptor.capture());
assertEquals(CONNECTING, stateInfoCaptor.getValue().getState());
// The channel will starts with the first address (badAddress)
verify(mockTransportFactory)
.newClientTransport(same(badAddress), any(ClientTransportOptions.class));
verify(mockTransportFactory, times(0))
.newClientTransport(same(goodAddress), any(ClientTransportOptions.class));
MockClientTransportInfo badTransportInfo = transports.poll();
// Which failed to connect
badTransportInfo.listener.transportShutdown(Status.UNAVAILABLE);
inOrder.verifyNoMoreInteractions();
// The channel then try the second address (goodAddress)
verify(mockTransportFactory)
.newClientTransport(same(goodAddress), any(ClientTransportOptions.class));
MockClientTransportInfo goodTransportInfo = transports.poll();
when(goodTransportInfo.transport.newStream(
any(MethodDescriptor.class), any(Metadata.class), any(CallOptions.class)))
.thenReturn(mock(ClientStream.class));
goodTransportInfo.listener.transportReady();
inOrder.verify(mockLoadBalancer).handleSubchannelState(
same(subchannel), stateInfoCaptor.capture());
assertEquals(READY, stateInfoCaptor.getValue().getState());
// A typical LoadBalancer will call this once the subchannel becomes READY
helper.updateBalancingState(READY, mockPicker);
// Delayed transport uses the app executor to create real streams.
executor.runDueTasks();
verify(goodTransportInfo.transport).newStream(same(method), same(headers),
same(CallOptions.DEFAULT));
// The bad transport was never used.
verify(badTransportInfo.transport, times(0)).newStream(any(MethodDescriptor.class),
any(Metadata.class), any(CallOptions.class));
}
@Test
public void expBackoff_maxBackoff_maxRetryAttempts() {
ClientStream mockStream1 = mock(ClientStream.class);
ClientStream mockStream2 = mock(ClientStream.class);
ClientStream mockStream3 = mock(ClientStream.class);
ClientStream mockStream4 = mock(ClientStream.class);
ClientStream mockStream5 = mock(ClientStream.class);
ClientStream mockStream6 = mock(ClientStream.class);
ClientStream mockStream7 = mock(ClientStream.class);
InOrder inOrder = inOrder(
mockStream1, mockStream2, mockStream3, mockStream4, mockStream5, mockStream6, mockStream7);
when(retriableStreamRecorder.newSubstream(anyInt())).thenReturn(
mockStream1, mockStream2, mockStream3, mockStream4, mockStream5, mockStream6, mockStream7);
retriableStream.start(masterListener);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(0);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor1 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream1).start(sublistenerCaptor1.capture());
inOrder.verifyNoMoreInteractions();
// retry1
sublistenerCaptor1.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_1), new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime((long) (INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM) - 1L, TimeUnit.SECONDS);
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(1L, TimeUnit.SECONDS);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(1);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor2 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream2).start(sublistenerCaptor2.capture());
inOrder.verifyNoMoreInteractions();
// retry2
sublistenerCaptor2.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_2), new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(
(long) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * FAKE_RANDOM) - 1L,
TimeUnit.SECONDS);
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(1L, TimeUnit.SECONDS);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(2);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor3 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream3).start(sublistenerCaptor3.capture());
inOrder.verifyNoMoreInteractions();
// retry3
sublistenerCaptor3.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_1), new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(
(long) (INITIAL_BACKOFF_IN_SECONDS * BACKOFF_MULTIPLIER * BACKOFF_MULTIPLIER * FAKE_RANDOM)
- 1L,
TimeUnit.SECONDS);
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(1L, TimeUnit.SECONDS);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(3);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor4 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream4).start(sublistenerCaptor4.capture());
inOrder.verifyNoMoreInteractions();
// retry4
sublistenerCaptor4.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_2), new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime((long) (MAX_BACKOFF_IN_SECONDS * FAKE_RANDOM) - 1L, TimeUnit.SECONDS);
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(1L, TimeUnit.SECONDS);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(4);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor5 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream5).start(sublistenerCaptor5.capture());
inOrder.verifyNoMoreInteractions();
// retry5
sublistenerCaptor5.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_2), new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime((long) (MAX_BACKOFF_IN_SECONDS * FAKE_RANDOM) - 1L, TimeUnit.SECONDS);
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime(1L, TimeUnit.SECONDS);
assertEquals(0, fakeClock.numPendingTasks());
verify(retriableStreamRecorder).newSubstream(5);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor6 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream6).start(sublistenerCaptor6.capture());
inOrder.verifyNoMoreInteractions();
// can not retry any more
verify(retriableStreamRecorder, never()).postCommit();
sublistenerCaptor6.getValue().closed(Status.fromCode(RETRIABLE_STATUS_CODE_1), new Metadata());
verify(retriableStreamRecorder).postCommit();
inOrder.verifyNoMoreInteractions();
}
@Test
public void transparentRetry() {
ClientStream mockStream1 = mock(ClientStream.class);
ClientStream mockStream2 = mock(ClientStream.class);
ClientStream mockStream3 = mock(ClientStream.class);
InOrder inOrder = inOrder(
retriableStreamRecorder,
mockStream1, mockStream2, mockStream3);
// start
doReturn(mockStream1).when(retriableStreamRecorder).newSubstream(0);
retriableStream.start(masterListener);
inOrder.verify(retriableStreamRecorder).newSubstream(0);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor1 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream1).start(sublistenerCaptor1.capture());
inOrder.verifyNoMoreInteractions();
// transparent retry
doReturn(mockStream2).when(retriableStreamRecorder).newSubstream(0);
sublistenerCaptor1.getValue()
.closed(Status.fromCode(NON_RETRIABLE_STATUS_CODE), REFUSED, new Metadata());
inOrder.verify(retriableStreamRecorder).newSubstream(0);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor2 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream2).start(sublistenerCaptor2.capture());
inOrder.verifyNoMoreInteractions();
verify(retriableStreamRecorder, never()).postCommit();
assertEquals(0, fakeClock.numPendingTasks());
// no more transparent retry
doReturn(mockStream3).when(retriableStreamRecorder).newSubstream(1);
sublistenerCaptor2.getValue()
.closed(Status.fromCode(RETRIABLE_STATUS_CODE_1), REFUSED, new Metadata());
assertEquals(1, fakeClock.numPendingTasks());
fakeClock.forwardTime((long) (INITIAL_BACKOFF_IN_SECONDS * FAKE_RANDOM), TimeUnit.SECONDS);
inOrder.verify(retriableStreamRecorder).newSubstream(1);
ArgumentCaptor<ClientStreamListener> sublistenerCaptor3 =
ArgumentCaptor.forClass(ClientStreamListener.class);
inOrder.verify(mockStream3).start(sublistenerCaptor3.capture());
inOrder.verifyNoMoreInteractions();
verify(retriableStreamRecorder, never()).postCommit();
assertEquals(0, fakeClock.numPendingTasks());
}