1 /*
2  * Copyright (C) 2019 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.compatibility.common.util;
18 
19 import static org.junit.Assert.fail;
20 
21 import java.util.concurrent.Callable;
22 
23 /** Test utility to check for or wait for a condition by polling. */
24 public abstract class PollingCheck {
25     public static final PollingCheckClock DEFAULT_CLOCK = new SystemClock();
26     private static final long TIME_SLICE = 50;
27 
28     /** Clock for polling. */
29     public interface PollingCheckClock {
currentTimeMillis()30         long currentTimeMillis();
31 
sleep(long millis)32         default void sleep(long millis) throws InterruptedException {
33             Thread.sleep(millis);
34         }
35     }
36 
37     private static class SystemClock implements PollingCheckClock {
38         @Override
currentTimeMillis()39         public long currentTimeMillis() {
40             return System.currentTimeMillis();
41         }
42     }
43 
44     /**
45      * Repeatedly check a condition.
46      *
47      * @param clock Clock used for checking time and sleeping between checks
48      * @param pollInterval Time interval to wait between checks
49      * @param timeout Timeout after which to stop checking
50      * @param condition Condition to check
51      * @return {@code true} if the condition became true within the timeout, {@code false} otherwise
52      * @throws Exception
53      */
check( PollingCheckClock clock, long pollInterval, long timeout, Callable<Boolean> condition)54     public static boolean check(
55             PollingCheckClock clock, long pollInterval, long timeout, Callable<Boolean> condition)
56             throws Exception {
57         long start = clock.currentTimeMillis();
58 
59         if (condition.call()) {
60             return true;
61         }
62 
63         while ((clock.currentTimeMillis() - start) < timeout) {
64             clock.sleep(pollInterval);
65 
66             if (condition.call()) {
67                 return true;
68             }
69         }
70 
71         return false;
72     }
73 
74     /**
75      * Repeatedly check a condition. Uses the default clock and polling interval.
76      *
77      * @param timeout Timeout after which to stop checking
78      * @param condition Condition to check
79      * @return {@code true} if the condition became true within the timeout, {@code false} otherwise
80      * @throws Exception
81      */
check(long timeout, Callable<Boolean> condition)82     public static boolean check(long timeout, Callable<Boolean> condition) throws Exception {
83         return check(DEFAULT_CLOCK, TIME_SLICE, timeout, condition);
84     }
85 
86     /**
87      * Repeatedly check a condition. Throws an {@link AssertionError} if the condition does not
88      * become {@code true} within the timeout.
89      *
90      * @param clock Clock used for checking time and sleeping between checks
91      * @param pollInterval Time interval to wait between checks
92      * @param timeout Timeout after which to stop checking
93      * @param condition Condition to check
94      * @throws Exception
95      */
check( PollingCheckClock clock, String message, long pollInterval, long timeout, Callable<Boolean> condition)96     public static void check(
97             PollingCheckClock clock,
98             String message,
99             long pollInterval,
100             long timeout,
101             Callable<Boolean> condition)
102             throws Exception {
103         if (!check(clock, pollInterval, timeout, condition)) {
104             fail(message);
105         }
106     }
107 
108     /**
109      * Repeatedly check a condition. Uses the default clock and polling interval. Throws an {@link
110      * AssertionError} if the condition does not become {@code true} within the timeout.
111      *
112      * @param timeout Timeout after which to stop checking
113      * @param condition Condition to check
114      * @throws Exception
115      */
check(String message, long timeout, Callable<Boolean> condition)116     public static void check(String message, long timeout, Callable<Boolean> condition)
117             throws Exception {
118         check(DEFAULT_CLOCK, message, TIME_SLICE, timeout, condition);
119     }
120 
121     /**
122      * Waits for a condition to become {@code true}. Throws an {@link AssertionError} if the
123      * condition does not become {@code true} within the timeout.
124      *
125      * @param clock Clock used for checking time and sleeping between checks
126      * @param pollInterval Time interval to wait between checks
127      * @param timeout Timeout after which to stop checking
128      * @param condition Condition to check
129      * @throws Exception
130      */
waitFor( PollingCheckClock clock, long pollInterval, long timeout, final Callable<Boolean> condition)131     public static void waitFor(
132             PollingCheckClock clock,
133             long pollInterval,
134             long timeout,
135             final Callable<Boolean> condition)
136             throws Exception {
137         check(clock, "Unexpected timeout waiting for condition", pollInterval, timeout, condition);
138     }
139 
140     /**
141      * Waits for a condition to become {@code true}. Uses the default clock and polling interval.
142      * Throws an {@link AssertionError} if the condition does not become {@code true} within the
143      * timeout.
144      *
145      * @param timeout Timeout after which to stop checking
146      * @param condition Condition to check
147      * @throws Exception
148      */
waitFor(long timeout, final Callable<Boolean> condition)149     public static void waitFor(long timeout, final Callable<Boolean> condition) throws Exception {
150         waitFor(DEFAULT_CLOCK, TIME_SLICE, timeout, condition);
151     }
152 }
153