• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import androidx.annotation.GuardedBy;
8 
9 import org.junit.rules.TestRule;
10 import org.junit.runner.Description;
11 import org.junit.runners.model.Statement;
12 
13 import org.chromium.base.TimeUtils.FakeClock;
14 
15 /** Causes fake times to be used in TimeUtils. */
16 public class FakeTimeTestRule implements TestRule {
17     private final Object mLock = new Object();
18 
19     // Milliseconds since booted, excluding deep sleep.
20     @GuardedBy("mLock")
21     private long mUptimeMillis;
22 
23     // Nanoseconds since booted, including deep sleep.
24     @GuardedBy("mLock")
25     private long mElapsedRealtimeNanos;
26 
27     // Per-thread CPU time.
28     @GuardedBy("mLock")
29     private ThreadLocal<Long> mThreadTimes;
30 
31     // epoch time.
32     @GuardedBy("mLock")
33     private long mCurrentTimeMillis;
34 
35     /** Resets to default time values. */
resetTimes()36     public void resetTimes() {
37         synchronized (mLock) {
38             mUptimeMillis = 10000;
39             mElapsedRealtimeNanos = 20000L * TimeUtils.NANOSECONDS_PER_MILLISECOND;
40             mCurrentTimeMillis = 1653000000000L; // May 19 2022 18:40:00 GMT-0400
41 
42             mThreadTimes =
43                     new ThreadLocal<Long>() {
44                         @Override
45                         protected Long initialValue() {
46                             return 0L;
47                         }
48                     };
49         }
50     }
51 
52     private final TimeUtils.FakeClock mFakeClock =
53             new FakeClock() {
54                 @Override
55                 public long uptimeMillis() {
56                     synchronized (mLock) {
57                         return mUptimeMillis;
58                     }
59                 }
60 
61                 @Override
62                 public long elapsedRealtimeNanos() {
63                     synchronized (mLock) {
64                         return mElapsedRealtimeNanos;
65                     }
66                 }
67 
68                 @Override
69                 public long currentThreadTimeMillis() {
70                     synchronized (mLock) {
71                         return mThreadTimes.get();
72                     }
73                 }
74 
75                 @Override
76                 public long currentTimeMillis() {
77                     synchronized (mLock) {
78                         return mCurrentTimeMillis;
79                     }
80                 }
81             };
82 
83     /** Advances uptime, elapsedRealtime, and the current thread's threadTime.. */
advanceMillis(long increment)84     public void advanceMillis(long increment) {
85         assert increment > 0 : "Negative increment: " + increment;
86         synchronized (mLock) {
87             mCurrentTimeMillis += increment;
88             mUptimeMillis += increment;
89             mElapsedRealtimeNanos += increment * TimeUtils.NANOSECONDS_PER_MILLISECOND;
90             mThreadTimes.set(mThreadTimes.get() + increment);
91         }
92     }
93 
94     /** Advances uptime and elapsedRealtime. */
sleepMillis(long duration)95     public void sleepMillis(long duration) {
96         assert duration > 0 : "Negative duration: " + duration;
97         synchronized (mLock) {
98             mCurrentTimeMillis += duration;
99             mUptimeMillis += duration;
100             mElapsedRealtimeNanos += duration * TimeUtils.NANOSECONDS_PER_MILLISECOND;
101         }
102     }
103 
104     /** Advances elapsedRealtime. */
deepSleepMillis(long duration)105     public void deepSleepMillis(long duration) {
106         assert duration > 0 : "Negative duration: " + duration;
107         synchronized (mLock) {
108             mCurrentTimeMillis += duration;
109             mElapsedRealtimeNanos += duration * TimeUtils.NANOSECONDS_PER_MILLISECOND;
110         }
111     }
112 
113     @Override
apply(Statement base, Description description)114     public Statement apply(Statement base, Description description) {
115         return new Statement() {
116             @Override
117             public void evaluate() throws Throwable {
118                 try {
119                     resetTimes();
120                     TimeUtils.sFakeClock = mFakeClock;
121                     base.evaluate();
122                 } finally {
123                     TimeUtils.sFakeClock = null;
124                 }
125             }
126         };
127     }
128 }
129