|
46 | 46 | import com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList;
|
47 | 47 | import com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntSquarerCallable;
|
48 | 48 | import com.google.api.gax.rpc.testing.FakeBatchableApi.SquarerBatchingDescriptorV2;
|
| 49 | +import com.google.api.gax.rpc.testing.FakeCallContext; |
49 | 50 | import com.google.common.base.Stopwatch;
|
50 | 51 | import com.google.common.collect.ImmutableList;
|
51 | 52 | import com.google.common.collect.Queues;
|
@@ -931,6 +932,82 @@ public void testThrottlingNonBlocking() throws Exception {
|
931 | 932 | }
|
932 | 933 | }
|
933 | 934 |
|
| 935 | + /** |
| 936 | + * If the batcher's unary callable throws an exception when obtaining a response, then the |
| 937 | + * response .get() should throw the exception |
| 938 | + */ |
| 939 | + @Test |
| 940 | + public void testAddDoesNotHangIfExceptionThrowStartingACall() { |
| 941 | + BatchingDescriptor<Object, Object, Object, Object> batchingDescriptor = |
| 942 | + new BatchingDescriptor<Object, Object, Object, Object>() { |
| 943 | + @Override |
| 944 | + public BatchingRequestBuilder<Object, Object> newRequestBuilder(Object o) { |
| 945 | + return new BatchingRequestBuilder<Object, Object>() { |
| 946 | + @Override |
| 947 | + public void add(Object o) {} |
| 948 | + |
| 949 | + @Override |
| 950 | + public Object build() { |
| 951 | + return new Object(); |
| 952 | + } |
| 953 | + }; |
| 954 | + } |
| 955 | + |
| 956 | + @Override |
| 957 | + public void splitResponse(Object o, List<BatchEntry<Object, Object>> list) { |
| 958 | + for (BatchEntry<Object, Object> e : list) { |
| 959 | + e.getResultFuture().set(new Object()); |
| 960 | + } |
| 961 | + } |
| 962 | + |
| 963 | + @Override |
| 964 | + public void splitException(Throwable throwable, List<BatchEntry<Object, Object>> list) { |
| 965 | + for (BatchEntry<Object, Object> e : list) { |
| 966 | + e.getResultFuture().setException(new RuntimeException("fake")); |
| 967 | + } |
| 968 | + } |
| 969 | + |
| 970 | + @Override |
| 971 | + public long countBytes(Object o) { |
| 972 | + return 1; |
| 973 | + } |
| 974 | + }; |
| 975 | + |
| 976 | + UnaryCallable<Object, Object> unaryCallable = |
| 977 | + new UnaryCallable<Object, Object>() { |
| 978 | + @Override |
| 979 | + public ApiFuture<Object> futureCall(Object o, ApiCallContext apiCallContext) { |
| 980 | + throw new RuntimeException("this should bubble up"); |
| 981 | + } |
| 982 | + }; |
| 983 | + Object prototype = new Object(); |
| 984 | + BatchingSettings batchingSettings = |
| 985 | + BatchingSettings.newBuilder() |
| 986 | + .setDelayThreshold(Duration.ofSeconds(1)) |
| 987 | + .setElementCountThreshold(100L) |
| 988 | + .setRequestByteThreshold(100L) |
| 989 | + .setFlowControlSettings(FlowControlSettings.getDefaultInstance()) |
| 990 | + .build(); |
| 991 | + ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); |
| 992 | + FlowController flowController = new FlowController(batchingSettings.getFlowControlSettings()); |
| 993 | + ApiCallContext callContext = FakeCallContext.createDefault(); |
| 994 | + |
| 995 | + BatcherImpl<Object, Object, Object, Object> batcher = |
| 996 | + new BatcherImpl<>( |
| 997 | + batchingDescriptor, |
| 998 | + unaryCallable, |
| 999 | + prototype, |
| 1000 | + batchingSettings, |
| 1001 | + executor, |
| 1002 | + flowController, |
| 1003 | + callContext); |
| 1004 | + |
| 1005 | + ApiFuture<Object> f = batcher.add(new Object()); |
| 1006 | + Assert.assertThrows(ExecutionException.class, f::get); |
| 1007 | + // bubbles up |
| 1008 | + Assert.assertThrows(RuntimeException.class, batcher::close); |
| 1009 | + } |
| 1010 | + |
934 | 1011 | private void testElementTriggers(BatchingSettings settings) throws Exception {
|
935 | 1012 | underTest = createDefaultBatcherImpl(settings, null);
|
936 | 1013 | Future<Integer> result = underTest.add(4);
|
|
0 commit comments