1085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki/* 2085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Copyright (C) 2010 The Android Open Source Project 3085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * 4085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 5085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * you may not use this file except in compliance with the License. 6085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * You may obtain a copy of the License at 7085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * 8085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 9085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * 10085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Unless required by applicable law or agreed to in writing, software 11085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 12085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * See the License for the specific language governing permissions and 14085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * limitations under the License. 15085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 16085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 17085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukipackage com.android.email; 18085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 19085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport android.os.Handler; 20085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport android.os.Message; 21085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport android.test.AndroidTestCase; 22085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 23085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport java.util.Timer; 24085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport java.util.TimerTask; 25085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport java.util.concurrent.BlockingQueue; 26085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukiimport java.util.concurrent.LinkedBlockingQueue; 27085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 28085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onukipublic class ThrottleTest extends AndroidTestCase { 29085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static final int MIN_TIMEOUT = 100; 30085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static final int MAX_TIMEOUT = 500; 31085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 32085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final CountingRunnable mRunnable = new CountingRunnable(); 33085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final MockClock mClock = new MockClock(); 34085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final MockTimer mTimer = new MockTimer(mClock); 35085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final Throttle mTarget = new Throttle("test", mRunnable, new CallItNowHandler(), 36085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki MIN_TIMEOUT, MAX_TIMEOUT, mClock, mTimer); 37085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 38085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 39085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Advance the clock. 40085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 41085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private void advanceClock(int milliseconds) { 42085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock.advance(milliseconds); 43085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTimer.runExpiredTasks(); 44085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 45085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 46085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 47085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Gets two events. They're far apart enough that the timeout won't be extended. 48085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 49085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void testSingleCalls() { 50085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 0 51085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 52085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(0); 53085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(0, mRunnable.mCounter); 54085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 55085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 99 56085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(99); 57085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(0, mRunnable.mCounter); // Still not called 58085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 59085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 100 60085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 61085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(1, mRunnable.mCounter); // Called 62085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 63085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 10100 64085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(10000); 65085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(1, mRunnable.mCounter); 66085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 67085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Do the same thing again. Should work in the same way. 68085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 69085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 0 70085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 71085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(0); 72085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(1, mRunnable.mCounter); 73085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 74085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 99 75085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(99); 76085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(1, mRunnable.mCounter); // Still not called 77085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 78085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 100 79085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 80085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(2, mRunnable.mCounter); // Called 81085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 82085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // T + 10100 83085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(10000); 84085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(2, mRunnable.mCounter); 85085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 86085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 87085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 88085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Gets 5 events in a row in a short period. 89085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * 90085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * We only roughly check the consequence, as the detailed spec isn't really important. 91085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Here, we check if the timeout is extended, and the callback get called less than 92085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * 5 times. 93085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 94085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void testMultiCalls() { 95085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 96085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 97085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 98085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 99085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 100085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 101085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 102085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(1); 103085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.onEvent(); 104085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 105085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Timeout should be extended 106085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertTrue(mTarget.getTimeoutForTest() > 100); 107085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 108085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Shouldn't result in 5 callback calls. 109085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki advanceClock(2000); 110085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertTrue(mRunnable.mCounter < 5); 111085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 112085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 113085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void testUpdateTimeout() { 114085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Check initial value 115085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(100, mTarget.getTimeoutForTest()); 116085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 117085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // First call -- won't change the timeout 118085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.updateTimeout(); 119085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(100, mTarget.getTimeoutForTest()); 120085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 121085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Call again in 10 ms -- will extend timeout. 122085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock.advance(10); 123085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.updateTimeout(); 124085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(200, mTarget.getTimeoutForTest()); 125085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 126085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Call again in TIMEOUT_EXTEND_INTERAVL ms -- will extend timeout. 127085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock.advance(Throttle.TIMEOUT_EXTEND_INTERVAL); 128085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.updateTimeout(); 129085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(400, mTarget.getTimeoutForTest()); 130085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 131085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Again -- timeout reaches max. 132085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock.advance(Throttle.TIMEOUT_EXTEND_INTERVAL); 133085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.updateTimeout(); 134085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(500, mTarget.getTimeoutForTest()); 135085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 136085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki // Call in TIMEOUT_EXTEND_INTERAVL + 1 ms -- timeout will get reset. 137085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock.advance(Throttle.TIMEOUT_EXTEND_INTERVAL + 1); 138085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTarget.updateTimeout(); 139085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki assertEquals(100, mTarget.getTimeoutForTest()); 140085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 141085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 142085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static class CountingRunnable implements Runnable { 143085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public int mCounter; 144085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 145085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki @Override 146085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void run() { 147085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mCounter++; 148085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 149085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 150085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 151085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 152085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Dummy {@link Handler} that executes {@link Runnable}s passed to {@link Handler#post} 153085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * immediately on the current thread. 154085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 155085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static class CallItNowHandler extends Handler { 156085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki @Override 157085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 158085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki msg.getCallback().run(); 159085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki return true; 160085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 161085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 162085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 163085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 164085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * Substitute for {@link Timer} that works based on the provided {@link Clock}. 165085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 166085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static class MockTimer extends Timer { 167085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final Clock mClock; 168085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 169085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private static class Entry { 170085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public long mScheduledTime; 171085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public TimerTask mTask; 172085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 173085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 174085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki private final BlockingQueue<Entry> mTasks = new LinkedBlockingQueue<Entry>(); 175085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 176085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public MockTimer(Clock clock) { 177085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mClock = clock; 178085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 179085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 180085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki @Override 181085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void schedule(TimerTask task, long delay) { 182085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki if (delay == 0) { 183085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki task.run(); 184085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } else { 185085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki Entry e = new Entry(); 186085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki e.mScheduledTime = mClock.getTime() + delay; 187085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki e.mTask = task; 188085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTasks.offer(e); 189085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 190085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 191085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki 192085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki /** 193085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * {@link MockTimer} can't know when the clock advances. This method must be called 194085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki * whenever the (mock) current time changes. 195085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki */ 196085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki public void runExpiredTasks() { 197085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki while (!mTasks.isEmpty()) { 198085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki Entry e = mTasks.peek(); 199085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki if (e.mScheduledTime > mClock.getTime()) { 200085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki break; 201085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 202085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki e.mTask.run(); 203085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki mTasks.poll(); 204085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 205085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 206085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki } 207085f7eb1219f270faa8317a5c6069a562213cb83Makoto Onuki} 208