/* Copyright (c) 2012 LinkedIn Corp. 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 http://www.apache.org/licenses/LICENSE-2.0 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. */ /* $Id$ */ package com.linkedin.util.degrader; import com.linkedin.util.clock.Clock; import com.linkedin.util.clock.SettableClock; import com.linkedin.util.clock.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.Date; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; /** * @author Swee Lim * @version $Revision$ */ public class TestDegrader { private static final Logger log = LoggerFactory.getLogger(TestDegrader.class); private static final String _defaultName = "degrader"; private static final long _defaultInterval = Time.milliseconds(5000); private static final DegraderImpl.LatencyToUse _defaultLatencyToUse = DegraderImpl.LatencyToUse.AVERAGE; private static final Double _defaultOverrideDropRate = -1.0; private static final Double _defaultMaxDropRate = 0.90; private static final long _defaultMaxDropDuration = Time.milliseconds(60000); private static final Double _defaultUpStep = 0.20; private static final Double _defaultDownStep = 0.25; private static final Integer _defaultMinCallCount = 1; private static final long _defaultHighLatency = Time.milliseconds(4000); private static final long _defaultLowLatency = Time.milliseconds(500); private static final Double _defaultHighErrorRate = 0.50; private static final Double _defaultLowErrorRate = 0.10; private static final long _defaultHighOutstanding = Time.milliseconds(10000); private static final long _defaultLowOutstanding = Time.milliseconds(500); private static final Integer _defaultMinOutstandingCount = 2; private static final DegraderImpl.LatencyToUse _testLatencyToUse = DegraderImpl.LatencyToUse.PCT99; private static final Double _testOverrideDropRate = 0.66; private static final Double _testMaxDropRate = 0.55; private static final long _testMaxDropDuration = Time.milliseconds(99999); private static final Double _testUpStep = 0.005; private static final Double _testDownStep = 0.006; private static final Integer _testMinCallCount = 13; private static final long _testHighLatency = Time.milliseconds(5555); private static final long _testLowLatency = Time.milliseconds(555); private static final Double _testHighErrorRate = 0.95; private static final Double _testLowErrorRate = 0.05; private static final long _testHighOutstanding = Time.milliseconds(15555); private static final long _testLowOutstanding = Time.milliseconds(1555); private static final Integer _testMinOutstandingCount = 23; private static final double _testInitialDropRate = 0.99; private static final double _testSlowStartThreshold = 0.2; private static final long _defaultMidLatency = Time.milliseconds((_defaultHighLatency + _defaultLowLatency) / 2); private SettableClock _clock; private CallTracker _callTracker; private DegraderImpl.Config _config; private DegraderImpl _degrader; private DegraderControl _control; private long _startTime; private long _lastSetClockToNextInterval; @BeforeMethod public void setUp() throws Exception { _clock = new SettableClock(); _callTracker = new CallTrackerImpl(_defaultInterval, _clock); _config = new DegraderImpl.Config(); _config.setName(_defaultName); _config.setCallTracker(_callTracker); _config.setClock(_clock); _config.setLatencyToUse(_defaultLatencyToUse); _config.setOverrideDropRate(_defaultOverrideDropRate); _config.setMaxDropRate(_defaultMaxDropRate); _config.setMaxDropDuration(_defaultMaxDropDuration); _config.setUpStep(_defaultUpStep); _config.setDownStep(_defaultDownStep); _config.setMinCallCount(_defaultMinCallCount); _config.setHighLatency(_defaultHighLatency); _config.setLowLatency(_defaultLowLatency); _config.setHighErrorRate(_defaultHighErrorRate); _config.setLowErrorRate(_defaultLowErrorRate); _config.setHighOutstanding(_defaultHighOutstanding); _config.setLowOutstanding(_defaultLowOutstanding); _config.setMinOutstandingCount(_defaultMinOutstandingCount); _degrader = new DegraderImpl(_config); _control = new DegraderControl(_degrader); _startTime = _clock.currentTimeMillis(); _lastSetClockToNextInterval = _startTime; if (log.isDebugEnabled()) { // debugging use only _callTracker.addStatsRolloverEventListener(new CallTracker.StatsRolloverEventListener() { public void onStatsRollover(CallTracker.StatsRolloverEvent event) { log.debug(event.getCallStats().toString()); } }); } } private static void assertConfigEquals(DegraderImpl.ImmutableConfig config1, DegraderImpl.ImmutableConfig config2) { assertTrue(config1.getClock() == config2.getClock()); assertTrue(config1.getLatencyToUse() == config2.getLatencyToUse()); assertTrue(config1.getOverrideDropRate() == config2.getOverrideDropRate()); assertTrue(config1.getMaxDropRate() == config2.getMaxDropRate()); assertTrue(config1.getMaxDropDuration() == config2.getMaxDropDuration()); assertTrue(config1.getUpStep() == config2.getUpStep()); assertTrue(config1.getDownStep() == config2.getDownStep()); assertTrue(config1.getMinCallCount() == config2.getMinCallCount()); assertTrue(config1.getHighLatency() == config2.getHighLatency()); assertTrue(config1.getLowLatency() == config2.getLowLatency()); assertTrue(config1.getHighErrorRate() == config2.getHighErrorRate()); assertTrue(config1.getLowErrorRate() == config2.getLowErrorRate()); assertTrue(config1.getHighOutstanding() == config2.getHighOutstanding()); assertTrue(config1.getLowOutstanding() == config2.getLowOutstanding()); assertTrue(config1.getMinOutstandingCount() == config2.getMinOutstandingCount()); } boolean checkDrop(double v) { return _degrader.checkDrop(v); } CallCompletion[] startCall(int count) { CallCompletion[] cc = new CallCompletion[count]; for (int i = 0; i < count; ++i) { cc[i] = _callTracker.startCall(); } return cc; } void endCall(CallCompletion[] cc, boolean isError) { for (int i = 0; i < cc.length; ++i) { if (isError) cc[i].endCallWithError(ErrorType.CLOSED_CHANNEL_EXCEPTION); else cc[i].endCall(); } } private void makeCall(int count, long latency, boolean isError) { long now = _clock.currentTimeMillis(); CallCompletion[] cc = startCall(count); _clock.setCurrentTimeMillis(now + latency); endCall(cc, isError); } private void advanceClock(long millis) { _clock.setCurrentTimeMillis(_clock.currentTimeMillis() + millis); } private void setClockToInterval(int intervalNo) { _clock.setCurrentTimeMillis(_startTime + _defaultInterval * intervalNo); } private void setClockToNextInterval() { long now = _clock.currentTimeMillis(); long interval = _defaultInterval; long newTime; if (now == _lastSetClockToNextInterval) { newTime = now + interval; } else { long offset = now - _startTime; newTime = (_startTime + ((offset + interval - 1) / interval) * interval); } _clock.setCurrentTimeMillis(newTime); _lastSetClockToNextInterval = newTime; } @Test public void testConfig() { DegraderImpl.Config config = new DegraderImpl.Config(); assertTrue(config.getClock() == DegraderImpl.DEFAULT_CLOCK); assertTrue(config.getLatencyToUse() == DegraderImpl.DEFAULT_LATENCY_TO_USE); assertTrue(config.getOverrideDropRate() == DegraderImpl.DEFAULT_OVERRIDE_DROP_RATE); assertTrue(config.getMaxDropRate() == DegraderImpl.DEFAULT_MAX_DROP_RATE); assertTrue(config.getMaxDropDuration() == DegraderImpl.DEFAULT_MAX_DROP_DURATION); assertTrue(config.getUpStep() == DegraderImpl.DEFAULT_UP_STEP); assertTrue(config.getDownStep() == DegraderImpl.DEFAULT_DOWN_STEP); assertTrue(config.getMinCallCount() == DegraderImpl.DEFAULT_MIN_CALL_COUNT); assertTrue(config.getHighLatency() == DegraderImpl.DEFAULT_HIGH_LATENCY); assertTrue(config.getLowLatency() == DegraderImpl.DEFAULT_LOW_LATENCY); assertTrue(config.getHighErrorRate() == DegraderImpl.DEFAULT_HIGH_ERROR_RATE); assertTrue(config.getLowErrorRate() == DegraderImpl.DEFAULT_LOW_ERROR_RATE); assertTrue(config.getHighOutstanding() == DegraderImpl.DEFAULT_HIGH_OUTSTANDING); assertTrue(config.getLowOutstanding() == DegraderImpl.DEFAULT_LOW_OUTSTANDING); assertTrue(config.getMinOutstandingCount() == DegraderImpl.DEFAULT_MIN_OUTSTANDING_COUNT); String testName = "aaaa"; config.setName(testName); assertTrue(config.getName() == testName); CallTracker testCallTracker = _callTracker; config.setCallTracker(testCallTracker); assertTrue(config.getCallTracker() == testCallTracker); Clock testClock = _clock; config.setClock(testClock); assertTrue(config.getClock() == testClock); config.setLatencyToUse(_testLatencyToUse); assertTrue(config.getLatencyToUse() == _testLatencyToUse); config.setOverrideDropRate(_testOverrideDropRate); assertTrue(config.getOverrideDropRate() == _testOverrideDropRate); config.setMaxDropRate(_testMaxDropRate); assertTrue(config.getMaxDropRate() == _testMaxDropRate); config.setMaxDropDuration(_testMaxDropDuration); assertTrue(config.getMaxDropDuration() == _testMaxDropDuration); config.setUpStep(_testUpStep); assertTrue(config.getUpStep() == _testUpStep); config.setDownStep(_testDownStep); assertTrue(config.getDownStep() == _testDownStep); config.setMinCallCount(_testMinCallCount); assertTrue(config.getMinCallCount() == _testMinCallCount); config.setHighLatency(_testHighLatency); assertTrue(config.getHighLatency() == _testHighLatency); config.setLowLatency(_testLowLatency); assertTrue(config.getLowLatency() == _testLowLatency); config.setHighErrorRate(_testHighErrorRate); assertTrue(config.getHighErrorRate() == _testHighErrorRate); config.setLowErrorRate(_testLowErrorRate); assertTrue(config.getLowErrorRate() == _testLowErrorRate); config.setHighOutstanding(_testHighOutstanding); assertTrue(config.getHighOutstanding() == _testHighOutstanding); config.setLowOutstanding(_testLowOutstanding); assertTrue(config.getLowOutstanding() == _testLowOutstanding); config.setMinOutstandingCount(_testMinOutstandingCount); assertTrue(config.getMinOutstandingCount() == _testMinOutstandingCount); config.setInitialDropRate(_testInitialDropRate); assertEquals(config.getInitialDropRate(), _testInitialDropRate); config.setSlowStartThreshold(_testSlowStartThreshold); assertEquals(config.getSlowStartThreshold(), _testSlowStartThreshold); DegraderImpl.ImmutableConfig immutableConfig = new DegraderImpl.ImmutableConfig(config); assertConfigEquals(immutableConfig, config); DegraderImpl.Config configFromImmutableConfig = new DegraderImpl.Config(immutableConfig); assertConfigEquals(configFromImmutableConfig, config); assertConfigEquals(configFromImmutableConfig, immutableConfig); } @Test public void testDegraderControlSetConfig() { assertConfigEquals(_config, _degrader.getConfig()); _control.setLatencyToUse(_testLatencyToUse.toString()); assertEquals(_control.getLatencyToUse(), _testLatencyToUse.toString()); _control.setOverrideDropRate(_testOverrideDropRate); assertTrue(_control.getOverrideDropRate() == _testOverrideDropRate); _control.setMaxDropRate(_testMaxDropRate); assertTrue(_control.getMaxDropRate() == _testMaxDropRate); _control.setMaxDropDuration(_testMaxDropDuration); assertEquals(_control.getMaxDropDuration(), _testMaxDropDuration); _control.setUpStep(_testUpStep); assertTrue(_control.getUpStep() == _testUpStep); _control.setDownStep(_testDownStep); assertTrue(_control.getDownStep() == _testDownStep); _control.setMinCallCount(_testMinCallCount); assertTrue(_control.getMinCallCount() == _testMinCallCount); _control.setHighLatency(_testHighLatency); assertEquals(_control.getHighLatency(), _testHighLatency); _control.setLowLatency(_testLowLatency); assertEquals(_control.getLowLatency(), _testLowLatency); _control.setHighErrorRate(_testHighErrorRate); assertTrue(_control.getHighErrorRate() == _testHighErrorRate); _control.setLowErrorRate(_testLowErrorRate); assertTrue(_control.getLowErrorRate() == _testLowErrorRate); _control.setHighOutstanding(_testHighOutstanding); assertEquals(_control.getHighOutstanding(), _testHighOutstanding); _control.setLowOutstanding(_testLowOutstanding); assertEquals(_control.getLowOutstanding(), _testLowOutstanding); _control.setMinOutstandingCount(_testMinOutstandingCount); assertTrue(_control.getMinOutstandingCount() == _testMinOutstandingCount); } @Test public void testDropRate() { DegraderImpl.Stats stats; long lastNotDroppedTime = _clock.currentTimeMillis(); checkDrop(0.0); makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); double expectedDropRate = _defaultUpStep; // 0.20 stats = _degrader.getStats(); assertEquals(1, stats.getCurrentCountTotal()); assertEquals(1, _control.getCurrentCountTotal()); assertEquals(0, stats.getCurrentDroppedCountTotal()); assertEquals(0, _control.getCurrentDroppedCountTotal()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertEquals(_clock.currentTimeMillis(), stats.getIntervalEndTime()); assertEquals(_defaultInterval, stats.getInterval()); assertEquals(0.0, stats.getDroppedRate()); assertEquals(1, stats.getCallCount()); assertEquals(_defaultHighLatency, stats.getLatency()); assertEquals(0.0, stats.getErrorRate()); assertEquals(0, stats.getOutstandingLatency()); assertEquals(0, stats.getOutstandingCount()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(2, stats.getCurrentCountTotal()); assertEquals(2, _control.getCurrentCountTotal()); assertEquals(1, stats.getCurrentDroppedCountTotal()); assertEquals(1, _control.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(3, stats.getCurrentCountTotal()); assertEquals(3, _control.getCurrentCountTotal()); assertEquals(1, stats.getCurrentDroppedCountTotal()); assertEquals(1, _control.getCurrentDroppedCountTotal()); makeCall(2, _defaultHighLatency, true); setClockToNextInterval(); expectedDropRate += _defaultUpStep; // 0.40 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertEquals(_clock.currentTimeMillis(), stats.getIntervalEndTime()); assertEquals(_defaultInterval, stats.getInterval()); assertEquals(0.50, stats.getDroppedRate()); assertEquals(2, stats.getCallCount()); assertEquals(_defaultHighLatency, stats.getLatency()); assertEquals(1.0, stats.getErrorRate()); assertEquals(0, stats.getOutstandingLatency()); assertEquals(0, stats.getOutstandingCount()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(4, stats.getCurrentCountTotal()); assertEquals(2, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(5, stats.getCurrentCountTotal()); assertEquals(2, stats.getCurrentDroppedCountTotal()); // check latency in between high and low makeCall(1, _defaultMidLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertEquals(_clock.currentTimeMillis(), stats.getIntervalEndTime()); assertEquals(_defaultInterval, stats.getInterval()); assertEquals(0.50, stats.getDroppedRate()); assertEquals(1, stats.getCallCount()); assertEquals(_defaultMidLatency, stats.getLatency()); assertEquals(0.0, stats.getErrorRate()); assertEquals(0, stats.getOutstandingLatency()); assertEquals(0, stats.getOutstandingCount()); assertEquals(new Date(_clock.currentTimeMillis()), _control.getIntervalEndTime()); assertEquals(_defaultInterval, _control.getInterval()); assertEquals(0.50, _control.getDroppedRate()); assertEquals(1, stats.getCallCount()); assertEquals(_defaultMidLatency, _control.getLatency()); assertEquals(0.0, _control.getErrorRate()); assertEquals(0, _control.getOutstandingLatency()); assertEquals(0, stats.getOutstandingCount()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(6, stats.getCurrentCountTotal()); assertEquals(3, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(7, stats.getCurrentCountTotal()); assertEquals(3, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); expectedDropRate += _defaultUpStep; // 0.60 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(8, stats.getCurrentCountTotal()); assertEquals(4, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(9, stats.getCurrentCountTotal()); assertEquals(4, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); expectedDropRate += _defaultUpStep; // 0.80 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(10, stats.getCurrentCountTotal()); assertEquals(5, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(11, stats.getCurrentCountTotal()); assertEquals(5, stats.getCurrentDroppedCountTotal()); // check MaxDropRate makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); expectedDropRate += _defaultUpStep; expectedDropRate = Math.min(expectedDropRate, _config.getMaxDropRate()); // 0.90 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(12, stats.getCurrentCountTotal()); assertEquals(6, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(13, stats.getCurrentCountTotal()); assertEquals(6, stats.getCurrentDroppedCountTotal()); long now = _clock.currentTimeMillis(); setClockToNextInterval(); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(14, stats.getCurrentCountTotal()); assertEquals(7, stats.getCurrentDroppedCountTotal()); // check MaxDropDuration _clock.setCurrentTimeMillis(now + _config.getMaxDropDuration()); assertFalse(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(15, stats.getCurrentCountTotal()); assertEquals(7, stats.getCurrentDroppedCountTotal()); _clock.setCurrentTimeMillis(now + _config.getMaxDropDuration() + 1000); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(16, stats.getCurrentCountTotal()); assertEquals(8, stats.getCurrentDroppedCountTotal()); _clock.setCurrentTimeMillis(now + _config.getMaxDropDuration() * 2); assertFalse(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(17, stats.getCurrentCountTotal()); assertEquals(8, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate -= _defaultDownStep; // 0.65 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(18, stats.getCurrentCountTotal()); assertEquals(9, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(19, stats.getCurrentCountTotal()); assertEquals(9, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate -= _defaultDownStep; // 0.40 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(20, stats.getCurrentCountTotal()); assertEquals(10, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(21, stats.getCurrentCountTotal()); assertEquals(10, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate -= _defaultDownStep; // 0.15 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertTrue(checkDrop(expectedDropRate - 0.05)); stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(22, stats.getCurrentCountTotal()); assertEquals(11, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); stats = _degrader.getStats(); lastNotDroppedTime = _clock.currentTimeMillis(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(23, stats.getCurrentCountTotal()); assertEquals(11, stats.getCurrentDroppedCountTotal()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate -= _defaultDownStep; // -0.10 expectedDropRate = Math.max(expectedDropRate, 0.0); // 0.00 stats = _degrader.getStats(); assertEquals(lastNotDroppedTime, stats.getLastNotDroppedTime()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertEquals(23, stats.getCurrentCountTotal()); assertEquals(11, stats.getCurrentDroppedCountTotal()); assertFalse(checkDrop(expectedDropRate + 0.05)); setClockToNextInterval(); long outstandingStartTime = _clock.currentTimeMillis(); CallCompletion[] cc = startCall(_config.getMinOutstandingCount()); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(_clock.currentTimeMillis(), stats.getIntervalEndTime()); assertEquals(_defaultInterval, stats.getInterval()); assertEquals(0.0, stats.getDroppedRate()); assertEquals(0, stats.getCallCount()); assertEquals(0, stats.getLatency()); assertEquals(0.0, stats.getErrorRate()); assertEquals(_clock.currentTimeMillis() - outstandingStartTime, stats.getOutstandingLatency()); assertEquals(_config.getMinOutstandingCount(), stats.getOutstandingCount()); assertEquals(new Date(_clock.currentTimeMillis()), _control.getIntervalEndTime()); assertEquals(_defaultInterval, _control.getInterval()); assertEquals(0.0, _control.getDroppedRate()); assertEquals(0, _control.getCallCount()); assertEquals(0, _control.getLatency()); assertEquals(0.0, _control.getErrorRate()); assertEquals(_defaultInterval, _control.getOutstandingLatency()); assertEquals(_config.getMinOutstandingCount(), _control.getOutstandingCount()); cc[0].endCallWithError(); // test MinOutstandingCount setClockToNextInterval(); expectedDropRate += _defaultUpStep; // 0.20 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); assertEquals(_clock.currentTimeMillis(), stats.getIntervalEndTime()); assertEquals(_defaultInterval, stats.getInterval()); assertEquals(0.0, stats.getDroppedRate()); assertEquals(1, stats.getCallCount()); assertEquals(_defaultInterval, stats.getLatency()); assertEquals(1.0, stats.getErrorRate()); assertEquals(_defaultInterval * 2, stats.getOutstandingLatency()); assertEquals(_config.getMinOutstandingCount() - 1, stats.getOutstandingCount()); assertEquals(new Date(_clock.currentTimeMillis()), _control.getIntervalEndTime()); assertEquals(_defaultInterval, _control.getInterval()); assertEquals(0.0, _control.getDroppedRate()); assertEquals(1, _control.getCallCount()); assertEquals(_defaultInterval, _control.getLatency()); assertEquals(1.0, _control.getErrorRate()); assertEquals(_defaultInterval * 2, _control.getOutstandingLatency()); assertEquals(_config.getMinOutstandingCount() - 1, _control.getOutstandingCount()); endCall(cc, false); setClockToNextInterval(); expectedDropRate += _defaultUpStep; // 0.40 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); // testMinCallCount _control.reset(); _control.setMinCallCount(4); expectedDropRate = 0.0; makeCall(3, _defaultHighLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(3, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(4, _defaultHighLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); expectedDropRate += _defaultUpStep; // 0.20 // actualMinCallCount = round(3.2) assertEquals(4, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(2, _defaultHighLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(2, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(3, _defaultHighLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); expectedDropRate += _defaultUpStep; // 0.40 // actualMinCallCount = round(2.4) assertEquals(3, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(1, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(2, _defaultLowLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); expectedDropRate -= _defaultDownStep; // 0.15 // actualMinCallCount = round(3.4) assertEquals(2, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(2, _defaultLowLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(2, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); makeCall(3, _defaultLowLatency, false); setClockToNextInterval(); stats = _degrader.getStats(); expectedDropRate -= _defaultDownStep; // -0.10 expectedDropRate = Math.max(0.0, expectedDropRate); // actualMinCallCount = round(3.4) assertEquals(3, stats.getCallCount()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); assertEquals(expectedDropRate, stats.getCurrentDropRate()); } @Test public void testAboveHigh() { DegraderImpl.Stats stats; double expectedDropRate; _control.setMinCallCount(10); // ErrorRate makeCall(4, _defaultLowLatency, true); makeCall(5, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate = 0; // errorRate < highErrorRate && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(5, _defaultLowLatency, true); makeCall(4, _defaultLowLatency, false); setClockToNextInterval(); expectedDropRate = 0; // errorRate >= highErrorRate && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(4, _defaultLowLatency, true); makeCall(6, _defaultLowLatency, false); setClockToNextInterval(); // errorRate < highErrorRate && callCount >= minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(5, _defaultLowLatency, true); makeCall(5, _defaultLowLatency, false); setClockToNextInterval(); // errorRate >= highErrorRate && callCount >= minCallCount expectedDropRate = _defaultUpStep; // 0.20 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); // Latency makeCall(7, _defaultMidLatency, false); setClockToNextInterval(); // latency < highLatency && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(8, _defaultMidLatency, false); // callCount == minCallCount setClockToNextInterval(); // latency < highLatency && callCount == minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(9, _defaultMidLatency, false); setClockToNextInterval(); // latency < highLatency && callCount > minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(7, _defaultHighLatency, false); setClockToNextInterval(); // latency >= highLatency && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(8, _defaultHighLatency, false); setClockToNextInterval(); // latency >= highLatency && callCount >= minCallCount expectedDropRate += _defaultUpStep; // 0.40 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); // Outstanding CallCompletion[] cc = startCall(1); advanceClock(_config.getHighOutstanding()); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); cc[0].endCall(); _degrader.reset(); _callTracker.reset(); stats = _degrader.getStats(); expectedDropRate = 0.0; // 0.00 assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); cc = startCall(_config.getMinOutstandingCount()); advanceClock(_config.getHighOutstanding()); expectedDropRate = _defaultUpStep; // 0.20 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); cc[0].endCall(); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); } @Test public void testBelowLow() { DegraderImpl.Stats stats; double expectedDropRate; double downStep = 0.10; _control.setMinCallCount(100); _control.setLowErrorRate(0.20); _control.setUpStep(_config.getMaxDropRate()); _control.setDownStep(downStep); makeCall(100, _defaultLowLatency, true); setClockToNextInterval(); expectedDropRate = _config.getMaxDropRate(); // 0.90 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); // ErrorRate makeCall(2, _defaultLowLatency, true); makeCall(7, _defaultLowLatency, false); setClockToNextInterval(); // errorRate > lowErroRate && callCount < minCallCall stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(1, _defaultLowLatency, true); makeCall(8, _defaultLowLatency, false); setClockToNextInterval(); // errorRate < lowErrorRate && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(3, _defaultLowLatency, true); makeCall(7, _defaultLowLatency, false); setClockToNextInterval(); // errorRate > lowErrorRate && callCount >= minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(2, _defaultLowLatency, true); makeCall(8, _defaultLowLatency, false); setClockToNextInterval(); // errorRate <= lowErrorRate && callCount >= minCallCount stats = _degrader.getStats(); expectedDropRate -= downStep; // 0.80 assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); // Latency makeCall(19, _defaultMidLatency, false); setClockToNextInterval(); // latency > lowLatency && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(20, _defaultMidLatency, false); // callCount == minCallCount setClockToNextInterval(); // latency > lowLatency && callCount == minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(21, _defaultMidLatency, false); // callCount > minCallCount setClockToNextInterval(); // latency > lowLatency && callCount > minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(19, _defaultLowLatency, false); setClockToNextInterval(); // latency <= lowLatency && callCount < minCallCount stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); makeCall(20, _defaultLowLatency, false); setClockToNextInterval(); // latency <= lowLatency && callCount == minCallCount expectedDropRate -= downStep; // 0.80 stats = _degrader.getStats(); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); // Outstanding advanceClock(_defaultInterval - (_defaultLowOutstanding - 10)); CallCompletion[] cc = startCall(19); setClockToNextInterval(); // outstanding < lowOutstanding && callCount < minCallCount stats = _degrader.getStats(); assertEquals(_defaultLowOutstanding - 10, stats.getOutstandingLatency()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); endCall(cc, false); advanceClock(_defaultInterval - (_defaultLowOutstanding + 10)); cc = startCall(20); setClockToNextInterval(); // outstanding <= lowOutstanding && callCount >= minCallCount stats = _degrader.getStats(); assertEquals(_defaultLowOutstanding + 10, stats.getOutstandingLatency()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); endCall(cc, false); setClockToNextInterval(); _control.setMinCallCount(1); advanceClock(_defaultInterval - (_defaultLowOutstanding - 10)); cc = startCall(_config.getMinOutstandingCount()); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(_defaultLowOutstanding - 10, stats.getOutstandingLatency()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); endCall(cc, false); advanceClock(_defaultInterval - _defaultLowOutstanding); cc = startCall(_config.getMinOutstandingCount()); setClockToNextInterval(); stats = _degrader.getStats(); expectedDropRate -= downStep; // 0.70 assertEquals(_defaultLowOutstanding, stats.getOutstandingLatency()); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); endCall(cc, false); setClockToNextInterval(); expectedDropRate -= downStep; // 0.60 setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(_defaultLowLatency, _defaultLowOutstanding); assertEquals(0, stats.getOutstandingLatency()); advanceClock(_defaultInterval - (_defaultLowOutstanding - 10)); cc = startCall(_config.getMinOutstandingCount() - 1); assertEquals(expectedDropRate, stats.getCurrentComputedDropRate()); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals((_defaultLowOutstanding - 10), stats.getOutstandingLatency()); endCall(cc, false); } private void makeCallRange(long begin, long end) { for (long i = begin; i < end; i++) { makeCall(1, i, false); } } @Test public void testLatencyToUse() { DegraderImpl.Stats stats; _control.setLatencyToUse("PCT50"); makeCallRange(1, 21); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(11, stats.getLatency()); _control.setLatencyToUse("PCT90"); makeCallRange(1, 21); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(18, stats.getLatency()); _control.setLatencyToUse("PCT95"); makeCallRange(1, 21); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(19, stats.getLatency()); _control.setLatencyToUse("PCT99"); makeCallRange(1, 21); setClockToNextInterval(); stats = _degrader.getStats(); assertEquals(20, stats.getLatency()); } @Test public void testOverrideDropRate() { double computedDropRate; makeCall(1, _defaultHighLatency, false); computedDropRate = _config.getUpStep(); // 0.20 setClockToNextInterval(); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); _control.setOverrideDropRate(0.10); assertEquals(0.10, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultMidLatency, false); setClockToNextInterval(); assertEquals(0.10, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); computedDropRate += _config.getUpStep(); // 0.40 assertEquals(0.10, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); computedDropRate -= _config.getDownStep(); // 0.15 assertEquals(0.10, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); _control.setOverrideDropRate(0.99); assertEquals(0.99, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultMidLatency, false); setClockToNextInterval(); assertEquals(0.99, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultHighLatency, false); setClockToNextInterval(); computedDropRate += _config.getUpStep(); // 0.35 assertEquals(0.99, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); makeCall(1, _defaultLowLatency, false); setClockToNextInterval(); computedDropRate -= _config.getDownStep(); // 0.10 assertEquals(0.99, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); _control.setOverrideDropRate(-0.01); assertEquals(computedDropRate, _control.getCurrentDropRate()); assertEquals(computedDropRate, _control.getCurrentComputedDropRate()); } @Test public void testInitialDropRate() { double expectedDropRate; _config.setInitialDropRate(_testInitialDropRate); _degrader = new DegraderImpl(_config); _control = new DegraderControl(_degrader); expectedDropRate = _config.getInitialDropRate(); // 0.99 assertTrue(checkDrop(expectedDropRate - 0.05)); makeCall(1, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // 0.74 setClockToNextInterval(); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(2, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // 0.49 setClockToNextInterval(); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(5, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // 0.24 setClockToNextInterval(); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(10, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // -0.01 expectedDropRate = Math.max(0.0d, expectedDropRate); // 0.0 setClockToNextInterval(); assertFalse(checkDrop(expectedDropRate + 0.05)); } @Test public void testSlowStartThreshold() { double expectedDropRate = 0.0; _config.setSlowStartThreshold(_testSlowStartThreshold); _config.setMaxDropRate(1.0d); // set max drop rate to 100% _degrader = new DegraderImpl(_config); _control = new DegraderControl(_degrader); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertFalse(checkDrop(expectedDropRate + 0.05)); // Stepping up makeCall(15, _defaultHighLatency, false); expectedDropRate += _config.getUpStep(); // 0.2 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(10, _defaultHighLatency, false); expectedDropRate += _config.getUpStep(); // 0.4 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(5, _defaultHighLatency, false); expectedDropRate += _config.getUpStep(); // 0.6 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(2, _defaultHighLatency, false); expectedDropRate += _config.getUpStep(); // 0.8 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); // Max drop rate makeCall(1, _defaultHighLatency, false); expectedDropRate += _config.getUpStep(); // 1.0 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate); assertTrue(checkDrop(expectedDropRate - 0.05)); // Slow start double transmissionRate = 0.01; // initial slow start transmission rate makeCall(1, _defaultLowLatency, false); expectedDropRate = 1 - transmissionRate; // 0.99 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); makeCall(1, _defaultLowLatency, false); transmissionRate *= 2; expectedDropRate = 1 - transmissionRate; // 0.98 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); makeCall(2, _defaultLowLatency, false); transmissionRate *= 2; expectedDropRate = 1 - transmissionRate; // 0.96 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); makeCall(4, _defaultLowLatency, false); transmissionRate *= 2; expectedDropRate = 1 - transmissionRate; // 0.92 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(8, _defaultLowLatency, false); transmissionRate *= 2; expectedDropRate = 1 - transmissionRate; // 0.84 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(16, _defaultLowLatency, false); transmissionRate *= 2; expectedDropRate = 1 - transmissionRate; // 0.68 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); // Stepping down makeCall(32, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // 0.43 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(57, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); // 0.18 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertTrue(checkDrop(expectedDropRate - 0.05)); assertFalse(checkDrop(expectedDropRate + 0.05)); makeCall(72, _defaultLowLatency, false); expectedDropRate -= _config.getDownStep(); expectedDropRate = Math.max(expectedDropRate, 0.0d); // 0.0 setClockToNextInterval(); assertEquals(_control.getCurrentComputedDropRate(), expectedDropRate, 10E-6); assertFalse(checkDrop(expectedDropRate + 0.05)); } }