CachingClientFactory extends ClientFactory<T> { public void getOrCreateClient( final String key, final Supplier<Future<T>> clientInstanceSupplier, final Handler<AsyncResult<T>> result) { getOrCreateClient(key, clientInstanceSupplier, result, 0); } CachingClientFactory(final Vertx vertx, final Predicate<T> livenessCheck); void removeClient(final String key); void removeClient(final String key, final Handler<T> postProcessor); boolean isEmpty(); T getClient(final String key); void getOrCreateClient(
            final String key,
            final Supplier<Future<T>> clientInstanceSupplier,
            final Handler<AsyncResult<T>> result);  }
@Test public void testGetOrCreateClientFailsIfSupplierFails(final VertxTestContext ctx) { final CachingClientFactory<Object> factory = new CachingClientFactory<>(vertx, o -> true); factory.getOrCreateClient( "bumlux", () -> Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE)), ctx.failing(t -> { ctx.verify(() -> { assertThat(((ServerErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE); }); ctx.completeNow(); })); }
@Test public void testGetOrCreateClientFailsIfInvokedConcurrently(final VertxTestContext ctx) { final CachingClientFactory<Object> factory = new CachingClientFactory<>(vertx, o -> true); final Promise<Object> creationResult = Promise.promise(); factory.getOrCreateClient( "bumlux", () -> Promise.promise().future(), creationResult); factory.getOrCreateClient( "bumlux", () -> { ctx.failNow(new AssertionError("should not create client concurrently")); return Future.succeededFuture(); }, ctx.failing(t -> { ctx.verify(() -> { assertThat(t).isInstanceOf(ServerErrorException.class); assertThat(ServiceInvocationException.extractStatusCode(t)).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE); verify(vertx, times(CachingClientFactory.MAX_CREATION_RETRIES)).setTimer(anyLong(), notNull()); }); ctx.completeNow(); })); }
@Test public void testGetOrCreateClientSucceedsOnRetry(final VertxTestContext ctx) { final CachingClientFactory<Object> factory = new CachingClientFactory<>(vertx, o -> true); final Promise<Object> creationResult = Promise.promise(); final Promise<Object> clientInstancePromise = Promise.promise(); factory.getOrCreateClient( "bumlux", () -> clientInstancePromise.future(), creationResult); when(vertx.setTimer(anyLong(), VertxMockSupport.anyHandler())).thenAnswer(invocation -> { clientInstancePromise.tryComplete(new Object()); final Handler<Void> task = invocation.getArgument(1); task.handle(null); return 1L; }); factory.getOrCreateClient( "bumlux", () -> { ctx.failNow(new AssertionError("should not create new client (cached one shall be used)")); return Future.succeededFuture(); }, ctx.succeeding(s -> { ctx.verify(() -> verify(vertx).setTimer(anyLong(), notNull())); ctx.completeNow(); })); }
@Test public void testGetOrCreateClientFailsWhenStateIsCleared(final VertxTestContext ctx) { final CachingClientFactory<Object> factory = new CachingClientFactory<>(vertx, o -> true); final Promise<Object> creationAttempt = Promise.promise(); factory.getOrCreateClient( "tenant", () -> { factory.clearState(); return Promise.promise().future(); }, creationAttempt); creationAttempt.future().onComplete(ctx.failing(t -> { factory.getOrCreateClient( "tenant", () -> Future.succeededFuture(new Object()), ctx.completing()); })); }
@Test public void testGetOrCreateClientWithClearStateCalledInBetween(final VertxTestContext ctx) { final CachingClientFactory<Object> factory = new CachingClientFactory<>(vertx, o -> true); final Promise<Object> creationFailure = Promise.promise(); final Promise<Object> creationAttempt = Promise.promise(); factory.getOrCreateClient( "tenant", () -> { factory.clearState(); creationFailure.fail("creation failure"); return creationFailure.future(); }, creationAttempt); creationAttempt.future().onComplete(ctx.failing(t -> { ctx.verify(() -> { assertThat(creationFailure.future().isComplete()).isTrue(); assertThat(((ServerErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE); }); ctx.completeNow(); })); }