GrpcClientCalls { public static <RequestT, ResponseT> ClientCall<RequestT, ResponseT> newCall( MethodDescriptor<RequestT, ResponseT> descriptor, ApiCallContext context) { if (!(context instanceof GrpcCallContext)) { throw new IllegalArgumentException( "context must be an instance of GrpcCallContext, but found " + context.getClass().getName()); } GrpcCallContext grpcContext = (GrpcCallContext) context; Preconditions.checkNotNull(grpcContext.getChannel()); CallOptions callOptions = grpcContext.getCallOptions(); Preconditions.checkNotNull(callOptions); if (grpcContext.getTimeout() != null) { Deadline newDeadline = Deadline.after(grpcContext.getTimeout().toMillis(), TimeUnit.MILLISECONDS); Deadline oldDeadline = callOptions.getDeadline(); if (oldDeadline == null || newDeadline.isBefore(oldDeadline)) { callOptions = callOptions.withDeadline(newDeadline); } } Channel channel = grpcContext.getChannel(); if (grpcContext.getChannelAffinity() != null && channel instanceof ChannelPool) { channel = ((ChannelPool) channel).getChannel(grpcContext.getChannelAffinity()); } if (!grpcContext.getExtraHeaders().isEmpty()) { ClientInterceptor interceptor = MetadataUtils.newAttachHeadersInterceptor(grpcContext.getMetadata()); channel = ClientInterceptors.intercept(channel, interceptor); } try (Scope ignored = grpcContext.getTracer().inScope()) { return channel.newCall(descriptor, callOptions); } } private  GrpcClientCalls(); static ClientCall<RequestT, ResponseT> newCall(
      MethodDescriptor<RequestT, ResponseT> descriptor, ApiCallContext context);  }
@Test public void testAffinity() throws IOException { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> clientCall0 = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall<Color, Money> clientCall1 = Mockito.mock(ClientCall.class); ManagedChannel channel0 = Mockito.mock(ManagedChannel.class); ManagedChannel channel1 = Mockito.mock(ManagedChannel.class); Mockito.when(channel0.newCall(Mockito.eq(descriptor), Mockito.<CallOptions>any())) .thenReturn(clientCall0); Mockito.when(channel1.newCall(Mockito.eq(descriptor), Mockito.<CallOptions>any())) .thenReturn(clientCall1); Channel pool = ChannelPool.create(2, new FakeChannelFactory(Arrays.asList(channel0, channel1))); GrpcCallContext context = GrpcCallContext.createDefault().withChannel(pool); ClientCall<Color, Money> gotCallA = GrpcClientCalls.newCall(descriptor, context.withChannelAffinity(0)); ClientCall<Color, Money> gotCallB = GrpcClientCalls.newCall(descriptor, context.withChannelAffinity(0)); ClientCall<Color, Money> gotCallC = GrpcClientCalls.newCall(descriptor, context.withChannelAffinity(1)); assertThat(gotCallA).isSameInstanceAs(gotCallB); assertThat(gotCallA).isNotSameInstanceAs(gotCallC); }
@Test public void testExtraHeaders() { Metadata emptyHeaders = new Metadata(); final Map<String, List<String>> extraHeaders = new HashMap<>(); extraHeaders.put( "header-key-1", ImmutableList.<String>of("header-value-11", "header-value-12")); extraHeaders.put("header-key-2", ImmutableList.<String>of("header-value-21")); MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); Mockito.doAnswer( new Answer<Void>() { public Void answer(InvocationOnMock invocation) { Metadata clientCallHeaders = (Metadata) invocation.getArguments()[1]; Metadata.Key<String> key1 = Metadata.Key.of("header-key-1", Metadata.ASCII_STRING_MARSHALLER); Metadata.Key<String> key2 = Metadata.Key.of("header-key-2", Metadata.ASCII_STRING_MARSHALLER); assertThat(clientCallHeaders.getAll(key1)) .containsExactly("header-value-11", "header-value-12"); assertThat(clientCallHeaders.getAll(key2)).containsExactly("header-value-21"); return null; } }) .when(mockClientCall) .start(Mockito.<ClientCall.Listener<Money>>any(), Mockito.<Metadata>any()); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), Mockito.<CallOptions>any())) .thenReturn(mockClientCall); GrpcCallContext context = GrpcCallContext.createDefault().withChannel(mockChannel).withExtraHeaders(extraHeaders); GrpcClientCalls.newCall(descriptor, context).start(mockListener, emptyHeaders); }
@Test public void testTimeoutToDeadlineConversion() { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); ArgumentCaptor<CallOptions> capturedCallOptions = ArgumentCaptor.forClass(CallOptions.class); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), capturedCallOptions.capture())) .thenReturn(mockClientCall); Duration timeout = Duration.ofSeconds(10); Deadline minExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); GrpcCallContext context = GrpcCallContext.createDefault().withChannel(mockChannel).withTimeout(timeout); GrpcClientCalls.newCall(descriptor, context).start(mockListener, new Metadata()); Deadline maxExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtLeast(minExpectedDeadline); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtMost(maxExpectedDeadline); }
@Test public void testTimeoutAfterDeadline() { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); ArgumentCaptor<CallOptions> capturedCallOptions = ArgumentCaptor.forClass(CallOptions.class); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), capturedCallOptions.capture())) .thenReturn(mockClientCall); Deadline priorDeadline = Deadline.after(5, TimeUnit.SECONDS); Duration timeout = Duration.ofSeconds(10); GrpcCallContext context = GrpcCallContext.createDefault() .withChannel(mockChannel) .withCallOptions(CallOptions.DEFAULT.withDeadline(priorDeadline)) .withTimeout(timeout); GrpcClientCalls.newCall(descriptor, context).start(mockListener, new Metadata()); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isEqualTo(priorDeadline); }
@Test public void testTimeoutBeforeDeadline() { MethodDescriptor<Color, Money> descriptor = FakeServiceGrpc.METHOD_RECOGNIZE; @SuppressWarnings("unchecked") ClientCall<Color, Money> mockClientCall = Mockito.mock(ClientCall.class); @SuppressWarnings("unchecked") ClientCall.Listener<Money> mockListener = Mockito.mock(ClientCall.Listener.class); @SuppressWarnings("unchecked") Channel mockChannel = Mockito.mock(ManagedChannel.class); ArgumentCaptor<CallOptions> capturedCallOptions = ArgumentCaptor.forClass(CallOptions.class); Mockito.when(mockChannel.newCall(Mockito.eq(descriptor), capturedCallOptions.capture())) .thenReturn(mockClientCall); Duration timeout = Duration.ofSeconds(5); Deadline subsequentDeadline = Deadline.after(10, TimeUnit.SECONDS); Deadline minExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); GrpcCallContext context = GrpcCallContext.createDefault() .withChannel(mockChannel) .withCallOptions(CallOptions.DEFAULT.withDeadline(subsequentDeadline)) .withTimeout(timeout); GrpcClientCalls.newCall(descriptor, context).start(mockListener, new Metadata()); Deadline maxExpectedDeadline = Deadline.after(timeout.getSeconds(), TimeUnit.SECONDS); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtLeast(minExpectedDeadline); Truth.assertThat(capturedCallOptions.getValue().getDeadline()).isAtMost(maxExpectedDeadline); }