@Before public void prepare() { readFn = mock(TableReadFunction.class); writeFn = mock(TableWriteFunction.class); roTable = new AsyncRemoteTable<>(readFn, null); rwTable = new AsyncRemoteTable<>(readFn, writeFn); }
@Test(expected = NullPointerException.class) public void testFailOnNullReadFn() { new AsyncRemoteTable(null, null); }
this.retryExecutor = retryExecutor; AsyncReadWriteTable table = new AsyncRemoteTable(readFn, writeFn); if (readRateLimiter != null || writeRateLimiter != null) { table = new AsyncRateLimitedTable(tableId, table, readRateLimiter, writeRateLimiter, rateLimitingExecutor);
@Test public void testFlushAndClose() { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(100)); TableReadFunction readFn = mock(TableReadFunction.class); TableWriteFunction writeFn = mock(TableWriteFunction.class); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.flush(); verify(writeFn, times(1)).flush(); table.close(); verify(readFn, times(1)).close(); verify(writeFn, times(1)).close(); } }
@Test public void testFlushAndClose() { TableRateLimiter readRateLimiter = mock(TableRateLimiter.class); TableRateLimiter writeRateLimiter = mock(TableRateLimiter.class); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRateLimitedTable table = new AsyncRateLimitedTable("t1", delegate, readRateLimiter, writeRateLimiter, schedExec); table.init(TestRemoteTable.getMockContext()); table.flush(); verify(writeFn, times(1)).flush(); table.close(); verify(readFn, times(1)).close(); verify(writeFn, times(1)).close(); }
@Test public void testGetThrottling() throws Exception { TableRateLimiter readRateLimiter = mock(TableRateLimiter.class); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(CompletableFuture.completedFuture("bar")).when(readFn).getAsync(any()); Map<String, String> result = new HashMap<>(); result.put("foo", "bar"); doReturn(CompletableFuture.completedFuture(result)).when(readFn).getAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRateLimitedTable table = new AsyncRateLimitedTable("t1", delegate, readRateLimiter, null, schedExec); table.init(TestRemoteTable.getMockContext()); Assert.assertEquals("bar", table.getAsync("foo").get()); verify(readFn, times(1)).getAsync(any()); verify(readRateLimiter, times(1)).throttle(anyString()); verify(readRateLimiter, times(0)).throttle(anyList()); Assert.assertEquals(result, table.getAllAsync(Arrays.asList("")).get()); verify(readFn, times(1)).getAllAsync(any()); verify(readRateLimiter, times(1)).throttle(anyList()); verify(readRateLimiter, times(1)).throttle(anyString()); }
doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRateLimitedTable table = new AsyncRateLimitedTable("t1", delegate, readRateLimiter, writeRateLimiter, schedExec);
doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAsync(any()); doReturn(CompletableFuture.completedFuture(null)).when(writeFn).deleteAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn);
@Test public void testGetAllWithOneRetry() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(true).when(readFn).isRetriable(any()); AtomicInteger times = new AtomicInteger(); Map<String, String> map = new HashMap<>(); map.put("foo1", "bar1"); map.put("foo2", "bar2"); doAnswer(invocation -> { CompletableFuture<Map<String, String>> future = new CompletableFuture(); if (times.get() > 0) { future.complete(map); } else { times.incrementAndGet(); future.completeExceptionally(new RuntimeException("test exception")); } return future; }).when(readFn).getAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, policy, null, schedExec, readFn, null); table.init(TestRemoteTable.getMockContext()); assertEquals(map, table.getAllAsync(Arrays.asList("foo1", "foo2")).get()); verify(readFn, times(2)).getAllAsync(any()); assertEquals(1, table.readRetryMetrics.retryCount.getCount()); assertEquals(0, table.readRetryMetrics.successCount.getCount()); assertEquals(0, table.readRetryMetrics.permFailureCount.getCount()); assertTrue(table.readRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
@Test public void testPutAllWithOneRetry() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(true).when(writeFn).isRetriable(any()); AtomicInteger times = new AtomicInteger(); doAnswer(invocation -> { CompletableFuture<Map<String, String>> future = new CompletableFuture(); if (times.get() > 0) { future.complete(null); } else { times.incrementAndGet(); future.completeExceptionally(new RuntimeException("test exception")); } return future; }).when(writeFn).putAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); table.putAllAsync(Arrays.asList(new Entry(1, 2))).get(); verify(writeFn, times(2)).putAllAsync(any()); assertEquals(1, table.writeRetryMetrics.retryCount.getCount()); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(0, table.writeRetryMetrics.permFailureCount.getCount()); assertTrue(table.writeRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
@Test public void testPutWithRetryDisabled() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); policy.withStopAfterDelay(Duration.ofMillis(100)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(false).when(writeFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(writeFn).putAsync(any(), any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); try { table.putAsync("foo", "bar").get(); fail(); } catch (ExecutionException e) { } verify(writeFn, times(1)).putAsync(any(), any()); assertEquals(0, table.writeRetryMetrics.retryCount.getCount()); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(0, table.writeRetryMetrics.permFailureCount.getCount()); assertEquals(0, table.writeRetryMetrics.retryTimer.getSnapshot().getMax()); }
@Test public void testGetWithRetryDisabled() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(10)); policy.withStopAfterDelay(Duration.ofMillis(100)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(false).when(readFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(readFn).getAsync(anyString()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, policy, null, schedExec, readFn, null); table.init(TestRemoteTable.getMockContext()); try { table.getAsync("foo").get(); fail(); } catch (ExecutionException e) { } verify(readFn, times(1)).getAsync(any()); assertEquals(0, table.readRetryMetrics.retryCount.getCount()); assertEquals(0, table.readRetryMetrics.successCount.getCount()); assertEquals(0, table.readRetryMetrics.permFailureCount.getCount()); assertEquals(0, table.readRetryMetrics.retryTimer.getSnapshot().getMax()); }
@Test public void testPutWithPermFailureOnTimeout() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(5)); policy.withStopAfterDelay(Duration.ofMillis(100)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(true).when(writeFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(readFn).getAsync(anyString()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); try { table.putAsync("foo", "bar").get(); fail(); } catch (ExecutionException e) { } verify(writeFn, atLeast(3)).putAsync(any(), any()); assertTrue(table.writeRetryMetrics.retryCount.getCount() >= 3); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(1, table.writeRetryMetrics.permFailureCount.getCount()); assertTrue(table.writeRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
@Test public void testGetWithoutRetry() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(100)); TableReadFunction readFn = mock(TableReadFunction.class); doReturn(true).when(readFn).isRetriable(any()); doReturn(CompletableFuture.completedFuture("bar")).when(readFn).getAsync(any()); Map<String, String> result = new HashMap<>(); result.put("foo", "bar"); doReturn(CompletableFuture.completedFuture(result)).when(readFn).getAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, policy, null, schedExec, readFn, null); int times = 0; table.init(TestRemoteTable.getMockContext()); verify(readFn, times(1)).init(any()); assertEquals("bar", table.getAsync("foo").get()); verify(readFn, times(1)).getAsync(any()); assertEquals(++times, table.readRetryMetrics.successCount.getCount()); assertEquals(result, table.getAllAsync(Arrays.asList("foo")).get()); verify(readFn, times(1)).getAllAsync(any()); assertEquals(++times, table.readRetryMetrics.successCount.getCount()); assertEquals(0, table.readRetryMetrics.retryCount.getCount()); assertEquals(0, table.readRetryMetrics.retryTimer.getSnapshot().getMax()); assertEquals(0, table.readRetryMetrics.permFailureCount.getCount()); assertNull(table.writeRetryMetrics); table.close(); verify(readFn, times(1)).close(); }
@Test public void testGetWithPermFailureOnTimeout() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(5)); policy.withStopAfterDelay(Duration.ofMillis(100)); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(true).when(readFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(readFn).getAsync(anyString()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, policy, null, schedExec, readFn, null); table.init(TestRemoteTable.getMockContext()); try { table.getAsync("foo").get(); fail(); } catch (ExecutionException e) { } verify(readFn, atLeast(3)).getAsync(any()); assertTrue(table.readRetryMetrics.retryCount.getCount() >= 3); assertEquals(0, table.readRetryMetrics.successCount.getCount()); assertEquals(1, table.readRetryMetrics.permFailureCount.getCount()); assertTrue(table.readRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
@Test public void testGetWithPermFailureOnMaxCount() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(5)); policy.withStopAfterAttempts(10); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); doReturn(true).when(readFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(readFn).getAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, null); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, policy, null, schedExec, readFn, null); table.init(TestRemoteTable.getMockContext()); try { table.getAsync("foo").get(); fail(); } catch (ExecutionException e) { } verify(readFn, atLeast(11)).getAsync(any()); assertEquals(10, table.readRetryMetrics.retryCount.getCount()); assertEquals(0, table.readRetryMetrics.successCount.getCount()); assertEquals(1, table.readRetryMetrics.permFailureCount.getCount()); assertTrue(table.readRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }
@Test public void testPutWithPermFailureOnMaxCount() throws Exception { TableRetryPolicy policy = new TableRetryPolicy(); policy.withFixedBackoff(Duration.ofMillis(5)); policy.withStopAfterAttempts(10); TableReadFunction<String, String> readFn = mock(TableReadFunction.class); TableWriteFunction<String, String> writeFn = mock(TableWriteFunction.class); doReturn(true).when(writeFn).isRetriable(any()); CompletableFuture<String> future = new CompletableFuture(); future.completeExceptionally(new RuntimeException("test exception")); doReturn(future).when(writeFn).putAllAsync(any()); AsyncReadWriteTable delegate = new AsyncRemoteTable(readFn, writeFn); AsyncRetriableTable table = new AsyncRetriableTable("t1", delegate, null, policy, schedExec, readFn, writeFn); table.init(TestRemoteTable.getMockContext()); try { table.putAllAsync(Arrays.asList(new Entry(1, 2))).get(); fail(); } catch (ExecutionException e) { } verify(writeFn, atLeast(11)).putAllAsync(any()); assertEquals(10, table.writeRetryMetrics.retryCount.getCount()); assertEquals(0, table.writeRetryMetrics.successCount.getCount()); assertEquals(1, table.writeRetryMetrics.permFailureCount.getCount()); assertTrue(table.writeRetryMetrics.retryTimer.getSnapshot().getMax() > 0); }