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
122823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    @SmallTest
123823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    public void testParseOptions() throws Exception {
124823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang         OperationScheduler.Options options = new OperationScheduler.Options();
125823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang         assertEquals(
126823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]",
127823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 OperationScheduler.parseOptions("3600", options).toString());
128823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
129823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang         assertEquals(
130823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]",
131823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString());
132823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
133823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang         assertEquals(
134823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
135823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800",
136823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                         options).toString());
137823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
138823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang         assertEquals(
139823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
140823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang                 OperationScheduler.parseOptions("", options).toString());
141823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    }
142823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
143823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    @SmallTest
144823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    public void testMoratoriumWithHttpDate() throws Exception {
145823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        TimeTravelScheduler scheduler = new TimeTravelScheduler();
146823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        OperationScheduler.Options options = new OperationScheduler.Options();
147823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
148823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeTrigger = scheduler.timeMillis;
149823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
150823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
151823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
152823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000);
153823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options));
154823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
155823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeMoratorium = scheduler.timeMillis;
156823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertTrue(scheduler.setMoratoriumTimeHttp("3000"));
157823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long afterMoratorium = scheduler.timeMillis;
158823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options));
159823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options));
160823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
161823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        options.maxMoratoriumMillis = Long.MAX_VALUE / 2;
162823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertTrue(scheduler.setMoratoriumTimeHttp("Fri, 31 Dec 2030 23:59:59 GMT"));
163823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(1924991999000L, scheduler.getNextTimeMillis(options));
164823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
165823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date"));
166823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    }
167823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
168823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    @SmallTest
169823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    public void testClockRollbackScenario() throws Exception {
170823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        TimeTravelScheduler scheduler = new TimeTravelScheduler();
171823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        OperationScheduler.Options options = new OperationScheduler.Options();
172823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        options.minTriggerMillis = 2000;
173823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
174823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // First, set up a scheduler with reasons to wait: a transient
175823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // error with backoff and a moratorium for a few minutes.
176823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
177823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeTrigger = scheduler.timeMillis;
178823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long triggerTime = beforeTrigger - 10000000;
179823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.setTriggerTimeMillis(triggerTime);
180823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
181823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(0, scheduler.getLastAttemptTimeMillis());
182823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
183823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeSuccess = (scheduler.timeMillis += 100);
184823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.onSuccess();
185823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.setTriggerTimeMillis(triggerTime);
186823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
187823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options));
188823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
189823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeError = (scheduler.timeMillis += 100);
190823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.onTransientError();
191823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
192823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options));
193823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
194823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeMoratorium = (scheduler.timeMillis += 100);
195823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000);
196823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
197823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
198823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // Now set the time back a few seconds.
199823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // The moratorium time should still be honored.
200823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000);
201823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
202823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
203823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // The rollback also moved the last-attempt clock back to the rollback time.
204823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis());
205823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
206823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // But if we set the time back more than a day, the moratorium
207823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // resets to the maximum moratorium (a day, by default), exposing
208823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // the original trigger time.
209823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000);
210823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
211823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
212823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang
213823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        // If we roll forward until after the re-set moratorium, then it expires.
214823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        scheduler.timeMillis = triggerTime + 5000000;
215823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
216823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
217823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang        assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis());
218823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang    }
219823b6f3516076b92f78c3fc27037d24bb514e653Ying Wang}
220