Pattern { public Sequence<C> getPrecipices(long permits) { return getPrecipices(permits, System.nanoTime()); } Pattern(Collection<C> precipices, PatternStrategy strategy);  Pattern(Collection<C> precipices, PatternStrategy strategy, SequenceFactory<C> sequenceFactory); Sequence<C> getPrecipices(long permits); Sequence<C> getPrecipices(long permits, long nanoTime); List<C> getAllPrecipices();  }
@Test public void getReturnsCorrectPrecipices() { Integer[] indices = {0, 1, 2}; SingleReaderArrayIterable iterable = getIterable(indices); when(strategy.nextIndices()).thenReturn(iterable); when(guardRail1.acquirePermits(1L, nanoTime)).thenReturn(null); when(guardRail2.acquirePermits(1L, nanoTime)).thenReturn(null); Sequence<Precipice<TimeoutableResult, Rejected>> all = pattern.getPrecipices(1L, nanoTime); List<Precipice<TimeoutableResult, Rejected>> controllableList = new ArrayList<>(); for (Precipice<TimeoutableResult, Rejected> item : all) { controllableList.add(item); } verifyZeroInteractions(precipice3); verifyZeroInteractions(guardRail3); assertEquals(2, controllableList.size()); assertSame(precipice1, controllableList.get(0)); assertSame(precipice2, controllableList.get(1)); }
@Test public void getAcquiresPermitsInTheCorrectOrder() { Integer[] indices = {2, 0, 1}; WritableCounts<Rejected> metrics = mock(WritableCounts.class); when(strategy.nextIndices()).thenReturn(getIterable(indices)); when(guardRail3.acquirePermits(1L, nanoTime)).thenReturn(null); when(guardRail1.acquirePermits(1L, nanoTime)).thenReturn(Rejected.CIRCUIT_OPEN); when(guardRail2.acquirePermits(1L, nanoTime)).thenReturn(null); when(guardRail1.getRejectedCounts()).thenReturn(metrics); Sequence<Precipice<TimeoutableResult, Rejected>> all = pattern.getPrecipices(1L, nanoTime); List<Precipice<TimeoutableResult, Rejected>> controllableList = new ArrayList<>(); for (Precipice<TimeoutableResult, Rejected> item : all) { controllableList.add(item); } assertEquals(2, controllableList.size()); assertSame(precipice3, controllableList.get(0)); assertSame(precipice2, controllableList.get(1)); }
@Test public void getOnlyReturnsTheNumberOfPrecipicesThatAreAvailable() { Integer[] indices = {2, 0, 1}; when(strategy.nextIndices()).thenReturn(getIterable(indices)); when(guardRail3.acquirePermits(1L, nanoTime)).thenReturn(Rejected.MAX_CONCURRENCY_LEVEL_EXCEEDED); when(guardRail1.acquirePermits(1L, nanoTime)).thenReturn(Rejected.CIRCUIT_OPEN); when(guardRail2.acquirePermits(1L, nanoTime)).thenReturn(null); Sequence<Precipice<TimeoutableResult, Rejected>> all = pattern.getPrecipices(1L, nanoTime); List<Precipice<TimeoutableResult, Rejected>> controllableList = new ArrayList<>(); for (Precipice<TimeoutableResult, Rejected> item : all) { controllableList.add(item); } assertEquals(1, controllableList.size()); assertSame(precipice2, controllableList.get(0)); }
@Test public void threadLocalFactoryMeansIteratorIsReusedAndThreadLocal() throws Exception { List<Precipice<TimeoutableResult, Rejected>> controllables = Arrays.asList(precipice1, precipice2, precipice3); pattern = new Pattern<>(controllables, strategy, new ThreadLocalSequenceFactory<Precipice<TimeoutableResult, Rejected>>()); final Integer[] indices = {2, 0, 1}; Executor executor = Executors.newCachedThreadPool(); when(strategy.nextIndices()).thenAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { return getIterable(indices); } }); when(guardRail3.acquirePermits(1L, nanoTime)).thenReturn(null); when(guardRail1.acquirePermits(1L, nanoTime)).thenReturn(null); when(guardRail2.acquirePermits(1L, nanoTime)).thenReturn(null); final Sequence<Precipice<TimeoutableResult, Rejected>> firstSequence = pattern.getPrecipices(1L, nanoTime); for (int i = 0; i < 10; ++i) { Sequence<Precipice<TimeoutableResult, Rejected>> sequence = pattern.getPrecipices(1L, nanoTime); assertSame("Should be the same reference.", firstSequence, sequence); } final ConcurrentHashMap<Sequence<Precipice<TimeoutableResult, Rejected>>, AtomicInteger> sequenceMap = new ConcurrentHashMap<>(); final CountDownLatch latch = new CountDownLatch(5); final CountDownLatch doneLatch = new CountDownLatch(5); for (int i = 0; i < 5; ++i) { executor.execute(new Runnable() { @Override public void run() { Sequence<Precipice<TimeoutableResult, Rejected>> first = pattern.getPrecipices(1L, nanoTime); if (sequenceMap.containsKey(first)) { fail("Set should not already contain this sequence."); } sequenceMap.put(first, new AtomicInteger(0)); latch.countDown(); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; ++i) { Sequence<Precipice<TimeoutableResult, Rejected>> sequence = pattern.getPrecipices(1L, nanoTime); sequenceMap.get(sequence).incrementAndGet(); assertSame("Should be the same reference.", first, sequence); } doneLatch.countDown(); } }); } doneLatch.await(); assertEquals(5, sequenceMap.size()); for (AtomicInteger count : sequenceMap.values()) { assertEquals(10, count.get()); } }