1 /* 2 * Copyright (C) 2018 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 package com.android.compatibility.common.util; 17 18 import static junit.framework.Assert.fail; 19 20 import android.os.SystemClock; 21 import android.util.Log; 22 23 import java.util.function.BooleanSupplier; 24 25 public class TestUtils { 26 private static final String TAG = "CtsTestUtils"; 27 TestUtils()28 private TestUtils() { 29 } 30 31 public static final int DEFAULT_TIMEOUT_SECONDS = 30; 32 33 /** Print an error log and fail. */ failWithLog(String message)34 public static void failWithLog(String message) { 35 Log.e(TAG, message); 36 fail(message); 37 } 38 39 @FunctionalInterface 40 public interface BooleanSupplierWithThrow { getAsBoolean()41 boolean getAsBoolean() throws Exception; 42 } 43 44 @FunctionalInterface 45 public interface RunnableWithThrow { run()46 void run() throws Exception; 47 } 48 49 /** 50 * Wait until {@code predicate} is satisfied, or fail, with {@link #DEFAULT_TIMEOUT_SECONDS}. 51 */ waitUntil(String message, BooleanSupplierWithThrow predicate)52 public static void waitUntil(String message, BooleanSupplierWithThrow predicate) 53 throws Exception { 54 waitUntil(message, 0, predicate); 55 } 56 57 /** 58 * Wait until {@code predicate} is satisfied, or fail, with a given timeout. 59 */ waitUntil( String message, int timeoutSecond, BooleanSupplierWithThrow predicate)60 public static void waitUntil( 61 String message, int timeoutSecond, BooleanSupplierWithThrow predicate) 62 throws Exception { 63 if (timeoutSecond <= 0) { 64 timeoutSecond = DEFAULT_TIMEOUT_SECONDS; 65 } 66 int sleep = 125; 67 final long timeout = SystemClock.uptimeMillis() + timeoutSecond * 1000; 68 while (SystemClock.uptimeMillis() < timeout) { 69 if (predicate.getAsBoolean()) { 70 return; // okay 71 } 72 Thread.sleep(sleep); 73 sleep *= 5; 74 sleep = Math.min(2000, sleep); 75 } 76 failWithLog("Timeout: " + message); 77 } 78 79 /** 80 * Run a Runnable {@code r}, and if it throws, also run {@code onFailure}. 81 */ runWithFailureHook(RunnableWithThrow r, RunnableWithThrow onFailure)82 public static void runWithFailureHook(RunnableWithThrow r, RunnableWithThrow onFailure) 83 throws Exception { 84 if (r == null) { 85 throw new NullPointerException("r"); 86 } 87 if (onFailure == null) { 88 throw new NullPointerException("onFailure"); 89 } 90 try { 91 r.run(); 92 } catch (Throwable th) { 93 Log.e(TAG, "Caught exception: " + th, th); 94 onFailure.run(); 95 throw th; 96 } 97 } 98 99 /** 100 * Synchronized wait for a specified condition. 101 * 102 * @param notifyLock Lock that will be notified when the condition might have changed 103 * @param condition The condition to check 104 * @param timeoutMs The timeout in millis 105 * @param conditionName The name to include in the assertion. If null, will be given a default. 106 */ waitOn(Object notifyLock, BooleanSupplier condition, long timeoutMs, String conditionName)107 public static void waitOn(Object notifyLock, BooleanSupplier condition, 108 long timeoutMs, String conditionName) { 109 if (conditionName == null) conditionName = "condition"; 110 if (condition.getAsBoolean()) return; 111 112 synchronized (notifyLock) { 113 try { 114 long timeSlept = 0; 115 while (!condition.getAsBoolean() && timeSlept < timeoutMs) { 116 long sleepStart = SystemClock.uptimeMillis(); 117 notifyLock.wait(timeoutMs - timeSlept); 118 timeSlept += SystemClock.uptimeMillis() - sleepStart; 119 } 120 if (!condition.getAsBoolean()) { 121 throw new AssertionError("Timed out after " + timeSlept 122 + "ms waiting for: " + conditionName); 123 } 124 } catch (InterruptedException e) { 125 throw new RuntimeException(e); 126 } 127 } 128 } 129 } 130 131