OperationCallableImpl extends OperationCallable<RequestT, ResponseT, MetadataT> { @Override public OperationFuture<ResponseT, MetadataT> futureCall( RequestT request, ApiCallContext callContext) { ApiFuture<OperationSnapshot> initialFuture = initialCallable.futureCall(request, callContext); return futureCall(initialFuture, callContext); } OperationCallableImpl(
      UnaryCallable<RequestT, OperationSnapshot> initialCallable,
      RetryingExecutorWithContext<OperationSnapshot> executor,
      LongRunningClient longRunningClient,
      OperationCallSettings<RequestT, ResponseT, MetadataT> operationCallSettings); @Override OperationFuture<ResponseT, MetadataT> futureCall(
      RequestT request, ApiCallContext callContext); @Override OperationFuture<ResponseT, MetadataT> resumeFutureCall(
      String operationName, ApiCallContext callContext); @Override ApiFuture<Void> cancel(String operationName, ApiCallContext callContext);  }
@Test public void testFutureCallInitialDone() throws Exception { String opName = "testFutureCallInitialDone"; Color resp = getColor(0.5f); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureSuccessMetaSuccess(opName, future, resp, meta); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialError() throws Exception { String opName = "testFutureCallInitialError"; Color resp = getColor(1.0f); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.UNAVAILABLE, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureFailMetaFail(future, null, FakeStatusCode.of(StatusCode.Code.UNAVAILABLE)); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialDoneWithError() throws Exception { String opName = "testFutureCallInitialDoneWithError"; StatusCode errorCode = FakeStatusCode.of(StatusCode.Code.ALREADY_EXISTS); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, null, errorCode, meta, true, "Already exists error"); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); String errorMessage = "Operation with name \"" + opName + "\" failed with status = " + errorCode + " and message = " + "Already exists error"; assertFutureFailMetaSuccess( future, meta, FakeStatusCode.of(StatusCode.Code.ALREADY_EXISTS), errorMessage); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialDoneWrongType() throws Exception { String opName = "testFutureCallInitialDoneWrongType"; Currency resp = Currency.getInstance("USD"); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureFailMetaSuccess( future, meta, FakeStatusCode.of(StatusCode.Code.OK), "type mismatch: expected java.awt.Color, found java.util.Currency"); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialDoneMetaWrongType() throws Exception { String opName = "testFutureCallInitialDoneMetaWrongType"; Color resp = getColor(1.0f); Color meta = getColor(1.0f); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureSuccessMetaFail(future, resp, FakeStatusCode.of(StatusCode.Code.OK)); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialCancel() throws Exception { String opName = "testFutureCallInitialCancel"; OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation = getOperation(opName, null, null, null, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation); OperationCallableImpl<Integer, Color, Currency> callableImpl = Callables.longRunningOperationImpl( initialCallable, callSettings, initialContext, longRunningClient); OperationFutureImpl<Color, Currency> future = callableImpl.futureCall( new ListenableFutureToApiFuture<>( Futures.<OperationSnapshot>immediateCancelledFuture()), FakeCallContext.createDefault()); Exception exception = null; try { future.get(3, TimeUnit.SECONDS); } catch (CancellationException e) { exception = e; } assertThat(exception).isNotNull(); assertThat(future.isDone()).isTrue(); assertThat(future.isCancelled()).isTrue(); assertThat(future.getInitialFuture().isDone()).isTrue(); assertThat(future.getInitialFuture().isCancelled()).isTrue(); assertFutureCancelMetaCancel(future); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallInitialOperationUnexpectedFail() throws Exception { String opName = "testFutureCallInitialOperationUnexpectedFail"; OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation = getOperation(opName, null, null, null, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation); OperationCallableImpl<Integer, Color, Currency> callableImpl = Callables.longRunningOperationImpl( initialCallable, callSettings, initialContext, longRunningClient); RuntimeException thrownException = new RuntimeException(); ApiFuture<OperationSnapshot> initialFuture = ApiFutures.immediateFailedFuture(thrownException); OperationFuture<Color, Currency> future = callableImpl.futureCall(initialFuture, FakeCallContext.createDefault()); assertFutureFailMetaFail(future, RuntimeException.class, null); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallPollDoneOnFirst() throws Exception { String opName = "testFutureCallPollDoneOnFirst"; Color resp = getColor(0.5f); Currency meta = Currency.getInstance("UAH"); OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureSuccessMetaSuccess(opName, future, resp, meta); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallPollDoneOnSecond() throws Exception { String opName = "testFutureCallPollDoneOnSecond"; Color resp = getColor(0.5f); Currency meta1 = Currency.getInstance("UAH"); Currency meta2 = Currency.getInstance("USD"); OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation1 = getOperation(opName, null, null, meta1, false); OperationSnapshot resultOperation2 = getOperation(opName, resp, null, meta2, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation1, resultOperation2); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureSuccessMetaSuccess(opName, future, resp, meta2); assertThat(executor.getIterationsCount()).isEqualTo(1); }
@Test public void testFutureCallPollRPCTimeout() throws Exception { String opName = "testFutureCallPollRPCTimeout"; pollingAlgorithm = OperationTimedPollAlgorithm.create( FAST_RECHECKING_SETTINGS .toBuilder() .setInitialRpcTimeout(Duration.ofMillis(100)) .setMaxRpcTimeout(Duration.ofSeconds(1)) .setRpcTimeoutMultiplier(2) .setTotalTimeout(Duration.ofSeconds(5L)) .build(), clock); callSettings = callSettings.toBuilder().setPollingAlgorithm(pollingAlgorithm).build(); Color resp = getColor(0.5f); Currency meta1 = Currency.getInstance("UAH"); Currency meta2 = Currency.getInstance("USD"); OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation1 = getOperation(opName, null, null, meta1, false); OperationSnapshot resultOperation2 = getOperation(opName, null, null, meta1, false); OperationSnapshot resultOperation3 = getOperation(opName, resp, null, meta2, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = Mockito.mock(LongRunningClient.class); @SuppressWarnings("unchecked") UnaryCallable<String, OperationSnapshot> getOpCallable = Mockito.mock(UnaryCallable.class); ArgumentCaptor<ApiCallContext> callContextCaptor = ArgumentCaptor.forClass(ApiCallContext.class); Mockito.when(longRunningClient.getOperationCallable()).thenReturn(getOpCallable); Mockito.when(getOpCallable.futureCall(Mockito.<String>any(), callContextCaptor.capture())) .thenReturn(ApiFutures.immediateFuture(resultOperation1)) .thenReturn(ApiFutures.immediateFuture(resultOperation2)) .thenReturn(ApiFutures.immediateFuture(resultOperation3)); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); callable.futureCall(2, FakeCallContext.createDefault()).get(10, TimeUnit.SECONDS); List<Duration> actualTimeouts = Lists.newArrayList(); for (ApiCallContext callContext : callContextCaptor.getAllValues()) { actualTimeouts.add(callContext.getTimeout()); } List<Duration> expectedTimeouts = Lists.newArrayList(Duration.ofMillis(100), Duration.ofMillis(200), Duration.ofMillis(400)); assertThat(actualTimeouts).isEqualTo(expectedTimeouts); }
@Test public void testFutureCallContextPropagation() throws Exception { String opName = "testFutureCallContextPropagation"; Color resp = getColor(0.5f); Currency meta1 = Currency.getInstance("UAH"); Currency meta2 = Currency.getInstance("USD"); OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta2, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = Mockito.mock(LongRunningClient.class); @SuppressWarnings("unchecked") UnaryCallable<String, OperationSnapshot> getOpCallable = Mockito.mock(UnaryCallable.class); ArgumentCaptor<ApiCallContext> callContextCaptor = ArgumentCaptor.forClass(ApiCallContext.class); Mockito.when(longRunningClient.getOperationCallable()).thenReturn(getOpCallable); Mockito.when(getOpCallable.futureCall(Mockito.<String>any(), callContextCaptor.capture())) .thenReturn(ApiFutures.immediateFuture(resultOperation)); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); ApiCallContext callContext = FakeCallContext.createDefault().withTimeout(Duration.ofMillis(10)); callable.futureCall(2, callContext).get(10, TimeUnit.SECONDS); assertThat(callContextCaptor.getValue().getTimeout()).isEqualTo(Duration.ofMillis(10)); }
@Test public void testFutureCallPollDoneOnMany() throws Exception { final int iterationsCount = 1000; String opName = "testFutureCallPollDoneOnMany"; Color resp = getColor(0.5f); Currency meta = Currency.getInstance("UAH"); OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot[] pollOperations = new OperationSnapshot[iterationsCount]; for (int i = 0; i < iterationsCount - 1; i++) { pollOperations[i] = getOperation(opName, null, null, meta, false); } pollOperations[iterationsCount - 1] = getOperation(opName, resp, null, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, pollOperations); pollingAlgorithm = OperationTimedPollAlgorithm.create( FAST_RECHECKING_SETTINGS .toBuilder() .setTotalTimeout(Duration.ofMillis(iterationsCount)) .build(), clock); callSettings = callSettings.toBuilder().setPollingAlgorithm(pollingAlgorithm).build(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); Truth.assertThat(future.get(5, TimeUnit.SECONDS)).isEqualTo(resp); assertFutureSuccessMetaSuccess(opName, future, resp, meta); assertThat(executor.getIterationsCount()).isEqualTo(iterationsCount - 1); }
@Test public void testFutureCallPollError() throws Exception { String opName = "testFutureCallPollError"; Currency meta = Currency.getInstance("UAH"); Color resp = getColor(1.0f); OperationSnapshot initialOperation = getOperation(opName, resp, null, meta, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); OperationSnapshot resultOperation = getOperation(opName, resp, null, meta, false); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.ALREADY_EXISTS, resultOperation); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureFailMetaFail(future, null, FakeStatusCode.of(StatusCode.Code.ALREADY_EXISTS)); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallPollDoneWithError() throws Exception { String opName = "testFutureCallPollDoneWithError"; Currency meta = Currency.getInstance("UAH"); Color resp = getColor(1.0f); OperationSnapshot initialOperation = getOperation(opName, resp, null, meta, false, "Already exists error"); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); StatusCode errorCode = FakeStatusCode.of(StatusCode.Code.ALREADY_EXISTS); OperationSnapshot resultOperation = getOperation(opName, null, errorCode, meta, true, "Already exists error"); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); String errorMessage = "Operation with name \"" + opName + "\" failed with status = " + errorCode + " and message = " + "Already exists error"; assertFutureFailMetaSuccess( future, meta, FakeStatusCode.of(StatusCode.Code.ALREADY_EXISTS), errorMessage); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testFutureCallPollCancelOnTimeoutExceeded() throws Exception { String opName = "testFutureCallPollCancelOnPollingTimeoutExceeded"; OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation = getOperation(opName, null, null, null, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureCancelMetaCancel(future); assertThat(executor.getIterationsCount()).isEqualTo(5); }
@Test public void testFutureCallPollCancelOnLongTimeoutExceeded() throws Exception { final int iterationsCount = 1000; String opName = "testFutureCallPollCancelOnLongTimeoutExceeded"; OperationSnapshot initialOperation = getOperation(opName, null, null, null, false); OperationSnapshot[] pollOperations = new OperationSnapshot[iterationsCount]; for (int i = 0; i < iterationsCount; i++) { pollOperations[i] = getOperation(opName, null, null, null, false); } UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, pollOperations); pollingAlgorithm = OperationTimedPollAlgorithm.create( FAST_RECHECKING_SETTINGS.toBuilder().setTotalTimeout(Duration.ofMillis(1000L)).build(), clock); callSettings = callSettings.toBuilder().setPollingAlgorithm(pollingAlgorithm).build(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); assertFutureCancelMetaCancel(future); assertThat(executor.getIterationsCount()).isEqualTo(iterationsCount); }
@Test public void testFutureCancelInTheMiddle() throws Exception { int iterationsCount = 1000; String opName = "testCancelInTheMiddle"; Color resp = getColor(0.5f); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, null, null, null, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); OperationSnapshot[] pollOperations = new OperationSnapshot[iterationsCount]; for (int i = 0; i < iterationsCount - 1; i++) { pollOperations[i] = getOperation(opName, null, null, null, false); } pollOperations[iterationsCount - 1] = getOperation(opName, resp, null, meta, true); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, pollOperations); CountDownLatch retryScheduledLatch = new CountDownLatch(10); LatchCountDownScheduler scheduler = LatchCountDownScheduler.get(retryScheduledLatch, 0L, 1L); ClientContext schedulerContext = getClientContext(initialChannel, scheduler); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, schedulerContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); CancellationHelpers.cancelInThreadAfterLatchCountDown(future, retryScheduledLatch); assertFutureCancelMetaCancel(future); }
@Test public void testInitialServerSideCancel() throws Exception { String opName = "testInitialServerSideCancel"; StatusCode errorCode = FakeStatusCode.of(StatusCode.Code.CANCELLED); Currency meta = Currency.getInstance("UAH"); OperationSnapshot resultOperation = getOperation(opName, null, errorCode, meta, true); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, resultOperation); LongRunningClient longRunningClient = new UnsupportedOperationApi(); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); String errorMessage = "Operation with name \"" + opName + "\" failed with status = " + errorCode + " and message = " + "null"; assertFutureFailMetaSuccess( future, meta, FakeStatusCode.of(StatusCode.Code.CANCELLED), errorMessage); assertThat(executor.getIterationsCount()).isEqualTo(0); }
@Test public void testPollServerSideCancel() throws Exception { String opName = "testPollServerSideCancel"; StatusCode errorCode = FakeStatusCode.of(StatusCode.Code.CANCELLED); Currency meta = Currency.getInstance("UAH"); OperationSnapshot initialOperation = getOperation(opName, null, null, meta, false); UnaryCallable<Integer, OperationSnapshot> initialCallable = mockGetOpSnapshotCallable(StatusCode.Code.OK, initialOperation); OperationSnapshot resultOperation1 = getOperation(opName, null, null, null, false); OperationSnapshot resultOperation2 = getOperation(opName, null, errorCode, meta, true); LongRunningClient longRunningClient = mockGetOperation(StatusCode.Code.OK, resultOperation1, resultOperation2); OperationCallable<Integer, Color, Currency> callable = FakeCallableFactory.createOperationCallable( initialCallable, callSettings, initialContext, longRunningClient); OperationFuture<Color, Currency> future = callable.futureCall(2, FakeCallContext.createDefault()); String errorMessage = "Operation with name \"" + opName + "\" failed with status = " + errorCode + " and message = " + "null"; assertFutureFailMetaSuccess( future, meta, FakeStatusCode.of(StatusCode.Code.CANCELLED), errorMessage); assertThat(executor.getIterationsCount()).isEqualTo(1); }