use of com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList in project gax-java by googleapis.
the class BatcherImplTest method testClosedBatchersAreNotLogged.
/**
* Validates the absence of warning in case {@link BatcherImpl} is garbage collected after being
* closed.
*
* <p>Note:This test cannot run concurrently with other tests that use Batchers.
*/
@Test
public void testClosedBatchersAreNotLogged() throws Exception {
// Clean out the existing instances
final long DELAY_TIME = 30L;
int actualRemaining = 0;
for (int retry = 0; retry < 3; retry++) {
System.gc();
System.runFinalization();
actualRemaining = BatcherReference.cleanQueue();
if (actualRemaining == 0) {
break;
}
Thread.sleep(DELAY_TIME * (1L << retry));
}
assertThat(actualRemaining).isAtMost(0);
// Capture logs
final List<LogRecord> records = new ArrayList<>(1);
Logger batcherLogger = Logger.getLogger(BatcherImpl.class.getName());
Filter oldFilter = batcherLogger.getFilter();
batcherLogger.setFilter(new Filter() {
@Override
public boolean isLoggable(LogRecord record) {
synchronized (records) {
records.add(record);
}
return false;
}
});
try {
// Create a bunch of batchers that will garbage collected after being closed
for (int i = 0; i < 1_000; i++) {
BatcherImpl<Integer, Integer, LabeledIntList, List<Integer>> batcher = createDefaultBatcherImpl(batchingSettings, null);
batcher.add(1);
if (i % 2 == 0) {
batcher.close();
} else {
batcher.closeAsync();
}
}
// Run GC a few times to give the batchers a chance to be collected
for (int retry = 0; retry < 100; retry++) {
System.gc();
System.runFinalization();
BatcherReference.cleanQueue();
Thread.sleep(10);
}
synchronized (records) {
assertThat(records).isEmpty();
}
} finally {
// reset logging
batcherLogger.setFilter(oldFilter);
}
}
use of com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList in project gax-java by googleapis.
the class BatcherImplTest method testElementsNotLeaking.
/**
* Validates that the elements are not leaking to multiple batches
*/
@Test(timeout = 500)
public void testElementsNotLeaking() throws Exception {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
ScheduledExecutorService multiThreadExecutor = Executors.newScheduledThreadPool(20);
final AtomicBoolean isDuplicateElement = new AtomicBoolean(false);
final ConcurrentMap<Integer, Boolean> map = new ConcurrentHashMap<>();
final UnaryCallable<LabeledIntList, List<Integer>> callable = new UnaryCallable<LabeledIntList, List<Integer>>() {
@Override
public ApiFuture<List<Integer>> futureCall(LabeledIntList request, ApiCallContext context) {
for (int val : request.ints) {
Boolean isPresent = map.putIfAbsent(val, Boolean.TRUE);
if (isPresent != null && isPresent) {
isDuplicateElement.set(true);
throw new AssertionError("Duplicate Element found");
}
}
return ApiFutures.immediateFuture(request.ints);
}
};
BatchingSettings settings = batchingSettings.toBuilder().setDelayThreshold(Duration.ofMillis(50)).build();
try (final BatcherImpl<Integer, Integer, LabeledIntList, List<Integer>> batcherTest = new BatcherImpl<>(SQUARER_BATCHING_DESC_V2, callable, labeledIntList, settings, EXECUTOR)) {
final Callable<Void> addElement = new Callable<Void>() {
@Override
public Void call() throws Exception {
int counter = 0;
while (!isDuplicateElement.get() && counter < 10_000) {
batcherTest.add(counter++);
}
return null;
}
};
final Callable<Void> sendBatch = new Callable<Void>() {
@Override
public Void call() throws InterruptedException {
batcherTest.flush();
return null;
}
};
// Started sequential element addition
Future<Void> future = singleThreadExecutor.submit(addElement);
for (int i = 0; !isDuplicateElement.get() && i < 3_000; i++) {
multiThreadExecutor.submit(sendBatch);
}
// Closing the resources
future.get();
assertThat(isDuplicateElement.get()).isFalse();
singleThreadExecutor.shutdown();
multiThreadExecutor.shutdown();
}
}
use of com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList in project gax-java by googleapis.
the class BatcherImplTest method testCloseRace.
@Test
public void testCloseRace() throws ExecutionException, InterruptedException, TimeoutException {
int iterations = 1_000_000;
ExecutorService executor = Executors.newFixedThreadPool(100);
try {
List<Future<?>> closeFutures = new ArrayList<>();
for (int i = 0; i < iterations; i++) {
final SettableApiFuture<List<Integer>> result = SettableApiFuture.create();
UnaryCallable<LabeledIntList, List<Integer>> callable = new UnaryCallable<LabeledIntList, List<Integer>>() {
@Override
public ApiFuture<List<Integer>> futureCall(LabeledIntList request, ApiCallContext context) {
return result;
}
};
final Batcher<Integer, Integer> batcher = new BatcherImpl<>(SQUARER_BATCHING_DESC_V2, callable, labeledIntList, batchingSettings, EXECUTOR);
batcher.add(1);
executor.execute(new Runnable() {
@Override
public void run() {
result.set(ImmutableList.of(1));
}
});
Future<?> f = executor.submit(new Runnable() {
@Override
public void run() {
try {
batcher.close();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
});
closeFutures.add(f);
}
// Make sure that none hang
for (Future<?> f : closeFutures) {
try {
// Should never take this long, but padded just in case this runs on a limited machine
f.get(1, TimeUnit.MINUTES);
} catch (TimeoutException e) {
assertWithMessage("BatcherImpl.close() is deadlocked").fail();
}
}
} finally {
executor.shutdownNow();
}
}
use of com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList in project gax-java by googleapis.
the class BatcherImplTest method testExceptionInDescriptorErrorHandling.
/**
* Resolves future results when {@link BatchingDescriptor#splitException} throws exception
*/
@Test
public void testExceptionInDescriptorErrorHandling() throws InterruptedException {
final RuntimeException fakeError = new RuntimeException("internal exception");
BatchingDescriptor<Integer, Integer, LabeledIntList, List<Integer>> descriptor = new SquarerBatchingDescriptorV2() {
@Override
public void splitResponse(List<Integer> batchResponse, List<BatchEntry<Integer, Integer>> batch) {
throw fakeError;
}
@Override
public void splitException(Throwable throwable, List<BatchEntry<Integer, Integer>> batch) {
throw fakeError;
}
};
underTest = new BatcherImpl<>(descriptor, callLabeledIntSquarer, labeledIntList, batchingSettings, EXECUTOR);
Future<Integer> result = underTest.add(2);
underTest.flush();
Throwable actualError = null;
try {
result.get();
} catch (ExecutionException ex) {
actualError = ex;
}
assertThat(actualError).hasCauseThat().isSameInstanceAs(fakeError);
try {
underTest.close();
} catch (Exception ex) {
actualError = ex;
}
assertThat(actualError).isInstanceOf(BatchingException.class);
}
use of com.google.api.gax.rpc.testing.FakeBatchableApi.LabeledIntList in project gax-java by googleapis.
the class BatcherImplTest method testExceptionInDescriptor.
/**
* Resolves future results when {@link BatchingDescriptor#splitResponse} throws exception.
*/
@Test
public void testExceptionInDescriptor() throws InterruptedException {
final RuntimeException fakeError = new RuntimeException("internal exception");
BatchingDescriptor<Integer, Integer, LabeledIntList, List<Integer>> descriptor = new SquarerBatchingDescriptorV2() {
@Override
public void splitResponse(List<Integer> batchResponse, List<BatchEntry<Integer, Integer>> batch) {
throw fakeError;
}
};
underTest = new BatcherImpl<>(descriptor, callLabeledIntSquarer, labeledIntList, batchingSettings, EXECUTOR);
Future<Integer> result = underTest.add(2);
underTest.flush();
Throwable actualError = null;
try {
result.get();
} catch (ExecutionException ex) {
actualError = ex;
}
assertThat(actualError).hasCauseThat().isSameInstanceAs(fakeError);
try {
underTest.close();
} catch (Exception batchingEx) {
actualError = batchingEx;
}
assertThat(actualError).isInstanceOf(BatchingException.class);
assertThat(actualError).hasMessageThat().contains("Batching finished with 1 batches failed to apply due to: 1 RuntimeException and 0 " + "partial failures.");
}
Aggregations