CallService implements Precipice<TimeoutableResult, Rejected> { public <T> T call(Callable<T> callable) throws Exception { return call(callable, 1L); } CallService(GuardRail<TimeoutableResult, Rejected> guardRail); @Override GuardRail<TimeoutableResult, Rejected> guardRail(); T call(Callable<T> callable); T call(Callable<T> callable, long permitNumber);  }
@Test public void exceptionThrownIfControllerRejects() throws Exception { try { when(guardRail.acquirePermits(eq(1L), anyLong())).thenThrow(new RejectedException(Rejected.MAX_CONCURRENCY_LEVEL_EXCEEDED)); service.call(TestCallables.success(1)); fail(); } catch (RejectedException e) { assertEquals(Rejected.MAX_CONCURRENCY_LEVEL_EXCEEDED, e.reason); } try { when(guardRail.acquirePermits(eq(1L), anyLong())).thenThrow(new RejectedException(Rejected.CIRCUIT_OPEN)); service.call(TestCallables.success(1)); fail(); } catch (RejectedException e) { assertEquals(Rejected.CIRCUIT_OPEN, e.reason); } }
@Test public void callableIsExecuted() throws Exception { when(guardRail.acquirePermits(eq(1L), anyLong())).thenReturn(null); String expectedResult = "Success"; String result = service.call(TestCallables.success(1)); verify(releaseFunction).apply(eq(TimeoutableResult.SUCCESS), any(ExecutionContext.class)); assertEquals(expectedResult, result); }
@Test public void callableExceptionIsHandledAppropriately() throws Exception { when(guardRail.acquirePermits(eq(1L), anyLong())).thenReturn(null); RuntimeException exception = new RuntimeException(); try { service.call(TestCallables.erred(exception)); } catch (Exception e) { assertEquals(e, exception); } verify(releaseFunction).apply(eq(TimeoutableResult.ERROR), any(ExecutionContext.class)); }
@Test public void callableTimeoutExceptionIsHandledAppropriately() throws Exception { when(guardRail.acquirePermits(eq(1L), anyLong())).thenReturn(null); TimeoutException exception = new PrecipiceTimeoutException(); try { service.call(TestCallables.erred(exception)); } catch (Exception e) { assertEquals(exception, e); } verify(releaseFunction).apply(eq(TimeoutableResult.TIMEOUT), any(ExecutionContext.class)); }
@Test public void simulationTest() { final Random random = ThreadLocalRandom.current(); GuardRailBuilder<TimeoutableResult, SimulationRejected> builder = new GuardRailBuilder<TimeoutableResult, SimulationRejected>().name("Simulation") .resultCounts(new TotalCounts<TimeoutableResult>(TimeoutableResult.class)) .rejectedCounts(new TotalCounts<SimulationRejected>(SimulationRejected.class)) .resultLatency(new NoOpLatency<>(TimeoutableResult.class)); GuardRail<TimeoutableResult, SimulationRejected> guardRail = builder.build(); final CallService<SimulationRejected> callService = new CallService<>(guardRail); Map<TimeoutableResult, Callable<Long>> resultToCallable = new HashMap<>(); resultToCallable.put(TimeoutableResult.SUCCESS, new Callable<Long>() { @Override public Long call() throws Exception { long number = random.nextInt(10) + 1; try { callService.call(TestCallables.success(0L), number); } catch (RejectedException e) { } return number; } }); resultToCallable.put(TimeoutableResult.ERROR, new Callable<Long>() { @Override public Long call() { long number = random.nextInt(10) + 1; try { callService.call(TestCallables.erred(new IOException()), number); } catch (Exception e) { } return number; } }); resultToCallable.put(TimeoutableResult.TIMEOUT, new Callable<Long>() { @Override public Long call() { long number = random.nextInt(10) + 1; try { callService.call(TestCallables.erred(new PrecipiceTimeoutException()), number); } catch (Exception e) { } return number; } }); Simulation<TimeoutableResult> simulation = new Simulation<>(guardRail); simulation.run(resultToCallable); }