Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.common;
     18 
     19 import android.content.SharedPreferences;
     20 import android.test.AndroidTestCase;
     21 import android.test.suitebuilder.annotation.MediumTest;
     22 import android.test.suitebuilder.annotation.SmallTest;
     23 
     24 public class OperationSchedulerTest extends AndroidTestCase {
     25     /**
     26      * OperationScheduler subclass which uses an artificial time.
     27      * Set {@link #timeMillis} to whatever value you like.
     28      */
     29     private class TimeTravelScheduler extends OperationScheduler {
     30         static final long DEFAULT_TIME = 1250146800000L;  // 13-Aug-2009, 12:00:00 am
     31         public long timeMillis = DEFAULT_TIME;
     32 
     33         @Override
     34         protected long currentTimeMillis() { return timeMillis; }
     35         public TimeTravelScheduler() { super(getFreshStorage()); }
     36     }
     37 
     38     private SharedPreferences getFreshStorage() {
     39         SharedPreferences sp = getContext().getSharedPreferences("OperationSchedulerTest", 0);
     40         sp.edit().clear().commit();
     41         return sp;
     42     }
     43 
     44     @MediumTest
     45     public void testScheduler() throws Exception {
     46         TimeTravelScheduler scheduler = new TimeTravelScheduler();
     47         OperationScheduler.Options options = new OperationScheduler.Options();
     48         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
     49         assertEquals(0, scheduler.getLastSuccessTimeMillis());
     50         assertEquals(0, scheduler.getLastAttemptTimeMillis());
     51 
     52         long beforeTrigger = scheduler.timeMillis;
     53         scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
     54         assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
     55 
     56         // It will schedule for the later of the trigger and the moratorium...
     57         scheduler.setMoratoriumTimeMillis(beforeTrigger + 500000);
     58         assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
     59         scheduler.setMoratoriumTimeMillis(beforeTrigger + 1500000);
     60         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
     61 
     62         // Test enable/disable toggle
     63         scheduler.setEnabledState(false);
     64         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
     65         scheduler.setEnabledState(true);
     66         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
     67 
     68         // Backoff interval after an error
     69         long beforeError = (scheduler.timeMillis += 100);
     70         scheduler.onTransientError();
     71         assertEquals(0, scheduler.getLastSuccessTimeMillis());
     72         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
     73         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
     74         options.backoffFixedMillis = 1000000;
     75         options.backoffIncrementalMillis = 500000;
     76         assertEquals(beforeError + 1500000, scheduler.getNextTimeMillis(options));
     77 
     78         // Two errors: backoff interval increases
     79         beforeError = (scheduler.timeMillis += 100);
     80         scheduler.onTransientError();
     81         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
     82         assertEquals(beforeError + 2000000, scheduler.getNextTimeMillis(options));
     83 
     84         // Reset transient error: no backoff interval
     85         scheduler.resetTransientError();
     86         assertEquals(0, scheduler.getLastSuccessTimeMillis());
     87         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
     88         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
     89 
     90         // Permanent error holds true even if transient errors are reset
     91         // However, we remember that the transient error was reset...
     92         scheduler.onPermanentError();
     93         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
     94         scheduler.resetTransientError();
     95         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
     96         scheduler.resetPermanentError();
     97         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
     98 
     99         // Success resets the trigger
    100         long beforeSuccess = (scheduler.timeMillis += 100);
    101         scheduler.onSuccess();
    102         assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
    103         assertEquals(beforeSuccess, scheduler.getLastSuccessTimeMillis());
    104         assertEquals(Long.MAX_VALUE, scheduler.getNextTimeMillis(options));
    105 
    106         // The moratorium is not reset by success!
    107         scheduler.setTriggerTimeMillis(0);
    108         assertEquals(beforeTrigger + 1500000, scheduler.getNextTimeMillis(options));
    109         scheduler.setMoratoriumTimeMillis(0);
    110         assertEquals(beforeSuccess, scheduler.getNextTimeMillis(options));
    111 
    112         // Periodic interval after success
    113         options.periodicIntervalMillis = 250000;
    114         scheduler.setTriggerTimeMillis(Long.MAX_VALUE);
    115         assertEquals(beforeSuccess + 250000, scheduler.getNextTimeMillis(options));
    116 
    117         // Trigger minimum is also since the last success
    118         options.minTriggerMillis = 1000000;
    119         assertEquals(beforeSuccess + 1000000, scheduler.getNextTimeMillis(options));
    120     }
    121 
    122     @MediumTest
    123     public void testExponentialBackoff() throws Exception {
    124         TimeTravelScheduler scheduler = new TimeTravelScheduler();
    125         OperationScheduler.Options options = new OperationScheduler.Options();
    126         options.backoffFixedMillis = 100;
    127         options.backoffIncrementalMillis = 1000;
    128         options.backoffExponentialMillis = 10000;
    129         scheduler.setTriggerTimeMillis(0);
    130         scheduler.setEnabledState(true);
    131 
    132         // Backoff interval after an error
    133         long beforeError = (scheduler.timeMillis += 10);
    134         scheduler.onTransientError();
    135         assertEquals(0, scheduler.getLastSuccessTimeMillis());
    136         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
    137         assertEquals(beforeError + 11100, scheduler.getNextTimeMillis(options));
    138 
    139         // Second error
    140         beforeError = (scheduler.timeMillis += 10);
    141         scheduler.onTransientError();
    142         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
    143         assertEquals(beforeError + 22100, scheduler.getNextTimeMillis(options));
    144 
    145         // Third error
    146         beforeError = (scheduler.timeMillis += 10);
    147         scheduler.onTransientError();
    148         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
    149         assertEquals(beforeError + 43100, scheduler.getNextTimeMillis(options));
    150 
    151         // Fourth error
    152         beforeError = (scheduler.timeMillis += 10);
    153         scheduler.onTransientError();
    154         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
    155         assertEquals(beforeError + 84100, scheduler.getNextTimeMillis(options));
    156     }
    157 
    158     @SmallTest
    159     public void testParseOptions() throws Exception {
    160          OperationScheduler.Options options = new OperationScheduler.Options();
    161          assertEquals(
    162                  "OperationScheduler.Options[backoff=0.0+5.0 max=86400.0 min=0.0 period=3600.0]",
    163                  OperationScheduler.parseOptions("3600", options).toString());
    164 
    165          assertEquals(
    166                  "OperationScheduler.Options[backoff=0.0+2.5 max=86400.0 min=0.0 period=3700.0]",
    167                  OperationScheduler.parseOptions("backoff=+2.5 3700", options).toString());
    168 
    169          assertEquals(
    170                  "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
    171                  OperationScheduler.parseOptions("max=12345.6 min=7 backoff=10 period=3800",
    172                          options).toString());
    173 
    174          assertEquals(
    175                 "OperationScheduler.Options[backoff=10.0+2.5 max=12345.6 min=7.0 period=3800.0]",
    176                  OperationScheduler.parseOptions("", options).toString());
    177 
    178          assertEquals(
    179                  "OperationScheduler.Options[backoff=5.0+2.5+10.0 max=12345.6 min=7.0 period=3600.0]",
    180                  OperationScheduler.parseOptions("backoff=5.0++10.0 3600", options).toString());
    181     }
    182 
    183     @SmallTest
    184     public void testMoratoriumWithHttpDate() throws Exception {
    185         TimeTravelScheduler scheduler = new TimeTravelScheduler();
    186         OperationScheduler.Options options = new OperationScheduler.Options();
    187 
    188         long beforeTrigger = scheduler.timeMillis;
    189         scheduler.setTriggerTimeMillis(beforeTrigger + 1000000);
    190         assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
    191 
    192         scheduler.setMoratoriumTimeMillis(beforeTrigger + 2000000);
    193         assertEquals(beforeTrigger + 2000000, scheduler.getNextTimeMillis(options));
    194 
    195         long beforeMoratorium = scheduler.timeMillis;
    196         assertTrue(scheduler.setMoratoriumTimeHttp("3000"));
    197         long afterMoratorium = scheduler.timeMillis;
    198         assertTrue(beforeMoratorium + 3000000 <= scheduler.getNextTimeMillis(options));
    199         assertTrue(afterMoratorium + 3000000 >= scheduler.getNextTimeMillis(options));
    200 
    201         options.maxMoratoriumMillis = Long.MAX_VALUE / 2;
    202         assertTrue(scheduler.setMoratoriumTimeHttp("Fri, 31 Dec 2030 23:59:59 GMT"));
    203         assertEquals(1924991999000L, scheduler.getNextTimeMillis(options));
    204 
    205         assertFalse(scheduler.setMoratoriumTimeHttp("not actually a date"));
    206     }
    207 
    208     @SmallTest
    209     public void testClockRollbackScenario() throws Exception {
    210         TimeTravelScheduler scheduler = new TimeTravelScheduler();
    211         OperationScheduler.Options options = new OperationScheduler.Options();
    212         options.minTriggerMillis = 2000;
    213 
    214         // First, set up a scheduler with reasons to wait: a transient
    215         // error with backoff and a moratorium for a few minutes.
    216 
    217         long beforeTrigger = scheduler.timeMillis;
    218         long triggerTime = beforeTrigger - 10000000;
    219         scheduler.setTriggerTimeMillis(triggerTime);
    220         assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
    221         assertEquals(0, scheduler.getLastAttemptTimeMillis());
    222 
    223         long beforeSuccess = (scheduler.timeMillis += 100);
    224         scheduler.onSuccess();
    225         scheduler.setTriggerTimeMillis(triggerTime);
    226         assertEquals(beforeSuccess, scheduler.getLastAttemptTimeMillis());
    227         assertEquals(beforeSuccess + 2000, scheduler.getNextTimeMillis(options));
    228 
    229         long beforeError = (scheduler.timeMillis += 100);
    230         scheduler.onTransientError();
    231         assertEquals(beforeError, scheduler.getLastAttemptTimeMillis());
    232         assertEquals(beforeError + 5000, scheduler.getNextTimeMillis(options));
    233 
    234         long beforeMoratorium = (scheduler.timeMillis += 100);
    235         scheduler.setMoratoriumTimeMillis(beforeTrigger + 1000000);
    236         assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
    237 
    238         // Now set the time back a few seconds.
    239         // The moratorium time should still be honored.
    240         long beforeRollback = (scheduler.timeMillis = beforeTrigger - 10000);
    241         assertEquals(beforeTrigger + 1000000, scheduler.getNextTimeMillis(options));
    242 
    243         // The rollback also moved the last-attempt clock back to the rollback time.
    244         assertEquals(scheduler.timeMillis, scheduler.getLastAttemptTimeMillis());
    245 
    246         // But if we set the time back more than a day, the moratorium
    247         // resets to the maximum moratorium (a day, by default), exposing
    248         // the original trigger time.
    249         beforeRollback = (scheduler.timeMillis = beforeTrigger - 100000000);
    250         assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
    251         assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
    252 
    253         // If we roll forward until after the re-set moratorium, then it expires.
    254         scheduler.timeMillis = triggerTime + 5000000;
    255         assertEquals(triggerTime, scheduler.getNextTimeMillis(options));
    256         assertEquals(beforeRollback, scheduler.getLastAttemptTimeMillis());
    257         assertEquals(beforeRollback, scheduler.getLastSuccessTimeMillis());
    258     }
    259 }
    260