1823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang/* 2823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Copyright (C) 2009 The Android Open Source Project 3823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 4823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * you may not use this file except in compliance with the License. 6823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * You may obtain a copy of the License at 7823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 8823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * http://www.apache.org/licenses/LICENSE-2.0 9823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * 10823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Unless required by applicable law or agreed to in writing, software 11823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * distributed under the License is distributed on an "AS IS" BASIS, 12823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * See the License for the specific language governing permissions and 14823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * limitations under the License. 15823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 16823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 17823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangpackage com.android.common; 18823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 19823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.content.SharedPreferences; 20823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.test.AndroidTestCase; 21823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.test.suitebuilder.annotation.MediumTest; 22823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangimport android.test.suitebuilder.annotation.SmallTest; 23823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 24823b6f3516076b92f78c3fc27037d24bb514e653Ying Wangpublic class OperationSchedulerTest extends AndroidTestCase { 25823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang /** 26823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * OperationScheduler subclass which uses an artificial time. 27823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang * Set {@link #timeMillis} to whatever value you like. 28823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang */ 29823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private class TimeTravelScheduler extends OperationScheduler { 30823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang static final long DEFAULT_TIME = 1250146800000L; // 13-Aug-2009, 12:00:00 am 31823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public long timeMillis = DEFAULT_TIME; 32823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 33823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang @Override 34823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang protected long currentTimeMillis() { return timeMillis; } 35823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public TimeTravelScheduler() { super(getFreshStorage()); } 36823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 37823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 38823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang private SharedPreferences getFreshStorage() { 39823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0); 40823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang sp.edit().clear().commit(); 41823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang return sp; 42823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 43823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 44823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang @MediumTest 45823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public void testScheduler() throws Exception { 46823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang TimeTravelScheduler scheduler = new TimeTravelScheduler(); 47823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.Options options = new OperationScheduler.Options(); 48823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); 49823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(0, scheduler.getLastSuccessTimeMillis()); 50823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(0, scheduler.getLastAttemptTimeMillis()); 51823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 52823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeTrigger = scheduler.timeMillis; 53823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); 54823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); 55823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 56823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // It will schedule for the later of the trigger and the moratorium... 57823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setMoratoriumTimeMillis(beforeTrigger + 500000); 58823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); 59823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setMoratoriumTimeMillis(beforeTrigger + 1500000); 60823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 61823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 62823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Test enable/disable toggle 63823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setEnabledState(false); 64823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); 65823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setEnabledState(true); 66823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 67823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 68823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Backoff interval after an error 69823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeError = (scheduler.timeMillis += 100); 70823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onTransientError(); 71823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(0, scheduler.getLastSuccessTimeMillis()); 72823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 73823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 74823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.backoffFixedMillis = 1000000; 75823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.backoffIncrementalMillis = 500000; 76823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options)); 77823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 78823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Two errors: backoff interval increases 79823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang beforeError = (scheduler.timeMillis += 100); 80823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onTransientError(); 81823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 82823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options)); 83823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 84823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Reset transient error: no backoff interval 85823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.resetTransientError(); 86823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(0, scheduler.getLastSuccessTimeMillis()); 87823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 88823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 89823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 90823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Permanent error holds true even if transient errors are reset 91823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // However, we remember that the transient error was reset... 92823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onPermanentError(); 93823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); 94823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.resetTransientError(); 95823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); 96823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.resetPermanentError(); 97823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 98823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 99823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Success resets the trigger 100823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeSuccess = (scheduler.timeMillis += 100); 101823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onSuccess(); 102823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); 103823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis()); 104823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options)); 105823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 106823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // The moratorium is not reset by success! 107823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(0); 108823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options)); 109823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setMoratoriumTimeMillis(0); 110823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options)); 111823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 112823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Periodic interval after success 113823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.periodicIntervalMillis = 250000; 114823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(Long.MAX_VALUE); 115823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options)); 116823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 117823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Trigger minimum is also since the last success 118823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.minTriggerMillis = 1000000; 119823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options)); 120823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 121823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 1221ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker @MediumTest 1231ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker public void testExponentialBackoff() throws Exception { 1241ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker TimeTravelScheduler scheduler = new TimeTravelScheduler(); 1251ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker OperationScheduler.Options options = new OperationScheduler.Options(); 1261ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker options.backoffFixedMillis = 100; 1271ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker options.backoffIncrementalMillis = 1000; 1281ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker options.backoffExponentialMillis = 10000; 1291ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.setTriggerTimeMillis(0); 1301ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.setEnabledState(true); 1311ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 1321ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker // Backoff interval after an error 1331ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker long beforeError = (scheduler.timeMillis += 10); 1341ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.onTransientError(); 1351ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(0, scheduler.getLastSuccessTimeMillis()); 1361ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 1371ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError + 11100, scheduler.getNextTimeMillis(options)); 1381ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 1391ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker // Second error 1401ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker beforeError = (scheduler.timeMillis += 10); 1411ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.onTransientError(); 1421ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 1431ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError + 22100, scheduler.getNextTimeMillis(options)); 1441ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 1451ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker // Third error 1461ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker beforeError = (scheduler.timeMillis += 10); 1471ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.onTransientError(); 1481ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 1491ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError + 43100, scheduler.getNextTimeMillis(options)); 1501ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 1511ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker // Fourth error 1521ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker beforeError = (scheduler.timeMillis += 10); 1531ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker scheduler.onTransientError(); 1541ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 1551ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals(beforeError + 84100, scheduler.getNextTimeMillis(options)); 1561ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker } 1571ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 158823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang @SmallTest 159823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public void testParseOptions() throws Exception { 160823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.Options options = new OperationScheduler.Options(); 161823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals( 162823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]", 163823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.parseOptions("3600", options).toString()); 164823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 165823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals( 166823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]", 167823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString()); 168823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 169823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals( 170823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]", 171823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800", 172823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options).toString()); 173823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 174823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals( 175823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]", 176823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.parseOptions("", options).toString()); 1771ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker 1781ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker assertEquals( 1791ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker "OperationScheduler.Options[backoff=5.0+2.5+10.0 max=12345.6 min=7.0 period=3600.0]", 1801ad9f44796cad21c9d2166c33c3dd8ca3adc41b2Doug Zongker OperationScheduler.parseOptions("backoff=5.0++10.0 3600", options).toString()); 181823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 182823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 183823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang @SmallTest 184823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public void testMoratoriumWithHttpDate() throws Exception { 185823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang TimeTravelScheduler scheduler = new TimeTravelScheduler(); 186823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.Options options = new OperationScheduler.Options(); 187823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 188823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeTrigger = scheduler.timeMillis; 189823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(beforeTrigger + 1000000); 190823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); 191823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 192823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000); 193823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options)); 194823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 195823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeMoratorium = scheduler.timeMillis; 196823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertTrue(scheduler.setMoratoriumTimeHttp("3000")); 197823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long afterMoratorium = scheduler.timeMillis; 198823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options)); 199823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options)); 200823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 201823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.maxMoratoriumMillis = Long.MAX_VALUE / 2; 202823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertTrue(scheduler.setMoratoriumTimeHttp("Fri, 31 Dec 2030 23:59:59 GMT")); 203823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(1924991999000L, scheduler.getNextTimeMillis(options)); 204823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 205823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date")); 206823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 207823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 208823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang @SmallTest 209823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang public void testClockRollbackScenario() throws Exception { 210823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang TimeTravelScheduler scheduler = new TimeTravelScheduler(); 211823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang OperationScheduler.Options options = new OperationScheduler.Options(); 212823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang options.minTriggerMillis = 2000; 213823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 214823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // First, set up a scheduler with reasons to wait: a transient 215823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // error with backoff and a moratorium for a few minutes. 216823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 217823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeTrigger = scheduler.timeMillis; 218823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long triggerTime = beforeTrigger - 10000000; 219823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(triggerTime); 220823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); 221823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(0, scheduler.getLastAttemptTimeMillis()); 222823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 223823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeSuccess = (scheduler.timeMillis += 100); 224823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onSuccess(); 225823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setTriggerTimeMillis(triggerTime); 226823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis()); 227823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options)); 228823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 229823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeError = (scheduler.timeMillis += 100); 230823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.onTransientError(); 231823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError, scheduler.getLastAttemptTimeMillis()); 232823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options)); 233823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 234823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeMoratorium = (scheduler.timeMillis += 100); 235823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000); 236823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); 237823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 238823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // Now set the time back a few seconds. 239823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // The moratorium time should still be honored. 240823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000); 241823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options)); 242823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 243823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // The rollback also moved the last-attempt clock back to the rollback time. 244823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis()); 245823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 246823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // But if we set the time back more than a day, the moratorium 247823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // resets to the maximum moratorium (a day, by default), exposing 248823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // the original trigger time. 249823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000); 250823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); 251823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); 252823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang 253823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang // If we roll forward until after the re-set moratorium, then it expires. 254823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang scheduler.timeMillis = triggerTime + 5000000; 255823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(triggerTime, scheduler.getNextTimeMillis(options)); 256823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis()); 257823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis()); 258823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang } 259823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang} 260