/** * Copyright 2015 Netflix, Inc. * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.hystrix.util; import com.netflix.hystrix.HystrixTimerThreadPoolProperties; import com.netflix.hystrix.strategy.HystrixPlugins; import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy; import com.netflix.hystrix.util.HystrixTimer.ScheduledExecutor; import com.netflix.hystrix.util.HystrixTimer.TimerListener; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.lang.ref.Reference; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.Assert.*; public class HystrixTimerTest { @Before public void setUp() { HystrixTimer timer = HystrixTimer.getInstance(); HystrixTimer.reset(); HystrixPlugins.reset(); } @After public void tearDown() { HystrixPlugins.reset(); } @Test public void testSingleCommandSingleInterval() { HystrixTimer timer = HystrixTimer.getInstance(); TestListener l1 = new TestListener(50, "A"); timer.addTimerListener(l1); TestListener l2 = new TestListener(50, "B"); timer.addTimerListener(l2); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // we should have 7 or more 50ms ticks within 500ms System.out.println("l1 ticks: " + l1.tickCount.get()); System.out.println("l2 ticks: " + l2.tickCount.get()); assertTrue(l1.tickCount.get() > 7); assertTrue(l2.tickCount.get() > 7); } @Test public void testSingleCommandMultipleIntervals() { HystrixTimer timer = HystrixTimer.getInstance(); TestListener l1 = new TestListener(100, "A"); timer.addTimerListener(l1); TestListener l2 = new TestListener(10, "B"); timer.addTimerListener(l2); TestListener l3 = new TestListener(25, "C"); timer.addTimerListener(l3); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // we should have 3 or more 100ms ticks within 500ms System.out.println("l1 ticks: " + l1.tickCount.get()); assertTrue(l1.tickCount.get() >= 3); // but it can't be more than 6 assertTrue(l1.tickCount.get() < 6); // we should have 30 or more 10ms ticks within 500ms System.out.println("l2 ticks: " + l2.tickCount.get()); assertTrue(l2.tickCount.get() > 30); assertTrue(l2.tickCount.get() < 550); // we should have 15-20 25ms ticks within 500ms System.out.println("l3 ticks: " + l3.tickCount.get()); assertTrue(l3.tickCount.get() > 14); assertTrue(l3.tickCount.get() < 25); } @Test public void testSingleCommandRemoveListener() { HystrixTimer timer = HystrixTimer.getInstance(); TestListener l1 = new TestListener(50, "A"); timer.addTimerListener(l1); TestListener l2 = new TestListener(50, "B"); Reference<TimerListener> l2ref = timer.addTimerListener(l2); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // we should have 7 or more 50ms ticks within 500ms System.out.println("l1 ticks: " + l1.tickCount.get()); System.out.println("l2 ticks: " + l2.tickCount.get()); assertTrue(l1.tickCount.get() > 7); assertTrue(l2.tickCount.get() > 7); // remove l2 l2ref.clear(); // reset counts l1.tickCount.set(0); l2.tickCount.set(0); // wait for time to pass again try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // we should have 7 or more 50ms ticks within 500ms System.out.println("l1 ticks: " + l1.tickCount.get()); System.out.println("l2 ticks: " + l2.tickCount.get()); // l1 should continue ticking assertTrue(l1.tickCount.get() > 7); // we should have no ticks on l2 because we removed it System.out.println("tickCount.get(): " + l2.tickCount.get() + " on l2: " + l2); assertEquals(0, l2.tickCount.get()); } @Test public void testReset() { HystrixTimer timer = HystrixTimer.getInstance(); TestListener l1 = new TestListener(50, "A"); timer.addTimerListener(l1); ScheduledExecutor ex = timer.executor.get(); assertFalse(ex.executor.isShutdown()); // perform reset which should shut it down HystrixTimer.reset(); assertTrue(ex.executor.isShutdown()); assertNull(timer.executor.get()); // assert it starts up again on use TestListener l2 = new TestListener(50, "A"); timer.addTimerListener(l2); ScheduledExecutor ex2 = timer.executor.get(); assertFalse(ex2.executor.isShutdown()); // reset again to shutdown what we just started HystrixTimer.reset(); // try resetting again to make sure it's idempotent (ie. doesn't blow up on an NPE) HystrixTimer.reset(); } @Test public void testThreadPoolSizeDefault() { HystrixTimer hystrixTimer = HystrixTimer.getInstance(); hystrixTimer.startThreadIfNeeded(); assertEquals(Runtime.getRuntime().availableProcessors(), hystrixTimer.executor.get().getThreadPool().getCorePoolSize()); } @Test public void testThreadPoolSizeConfiguredWithBuilder() { HystrixTimerThreadPoolProperties.Setter builder = HystrixTimerThreadPoolProperties.Setter().withCoreSize(1); final HystrixTimerThreadPoolProperties props = new HystrixTimerThreadPoolProperties(builder) { }; HystrixPropertiesStrategy strategy = new HystrixPropertiesStrategy() { @Override public HystrixTimerThreadPoolProperties getTimerThreadPoolProperties() { return props; } }; HystrixPlugins.getInstance().registerPropertiesStrategy(strategy); HystrixTimer hystrixTimer = HystrixTimer.getInstance(); hystrixTimer.startThreadIfNeeded(); assertEquals(1, hystrixTimer.executor.get().getThreadPool().getCorePoolSize()); } private static class TestListener implements TimerListener { private final int interval; AtomicInteger tickCount = new AtomicInteger(); TestListener(int interval, String value) { this.interval = interval; } @Override public void tick() { tickCount.incrementAndGet(); } @Override public int getIntervalTimeInMilliseconds() { return interval; } } public static void main(String args[]) { PlayListener l1 = new PlayListener(); PlayListener l2 = new PlayListener(); PlayListener l3 = new PlayListener(); PlayListener l4 = new PlayListener(); PlayListener l5 = new PlayListener(); Reference<TimerListener> ref = HystrixTimer.getInstance().addTimerListener(l1); HystrixTimer.getInstance().addTimerListener(l2); HystrixTimer.getInstance().addTimerListener(l3); HystrixTimer.getInstance().addTimerListener(l4); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } ref.clear(); HystrixTimer.getInstance().addTimerListener(l5); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("counter: " + l1.counter); System.out.println("counter: " + l2.counter); System.out.println("counter: " + l3.counter); System.out.println("counter: " + l4.counter); System.out.println("counter: " + l5.counter); } public static class PlayListener implements TimerListener { int counter = 0; @Override public void tick() { counter++; } @Override public int getIntervalTimeInMilliseconds() { return 10; } } }