1 /* 2 * Copyright (C) 2020 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 android.car.test.mocks; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.util.Log; 21 22 import java.util.Objects; 23 import java.util.concurrent.CountDownLatch; 24 import java.util.concurrent.ExecutionException; 25 import java.util.concurrent.Future; 26 import java.util.concurrent.Semaphore; 27 import java.util.concurrent.TimeUnit; 28 import java.util.concurrent.TimeoutException; 29 30 /** 31 * Provides common Mockito calls for core Java classes. 32 */ 33 public final class JavaMockitoHelper { 34 35 static final long ASYNC_TIMEOUT_MS = 500; 36 37 private static final String TAG = JavaMockitoHelper.class.getSimpleName(); 38 39 /** 40 * Waits for a latch to be counted down. 41 * 42 * @param timeoutMs how long to wait for 43 * 44 * @throws IllegalStateException if it times out. 45 */ await(@onNull CountDownLatch latch, long timeoutMs)46 public static void await(@NonNull CountDownLatch latch, long timeoutMs) 47 throws InterruptedException { 48 Log.v(TAG, "waiting " + timeoutMs + "ms for latch " + latch); 49 if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) { 50 Log.e(TAG, "latch timed out"); 51 throw new IllegalStateException(latch + " not called in " + timeoutMs + " ms"); 52 } 53 } 54 55 /** 56 * Waits for a semaphore. 57 * 58 * @param timeoutMs how long to wait for 59 * 60 * @throws IllegalStateException if it times out. 61 */ await(@onNull Semaphore semaphore, long timeoutMs)62 public static void await(@NonNull Semaphore semaphore, long timeoutMs) 63 throws InterruptedException { 64 Log.v(TAG, "waiting " + timeoutMs + "ms for semaphore " + semaphore); 65 if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 66 Log.e(TAG, "semaphore timed out"); 67 throw new IllegalStateException(semaphore + " not released in " + timeoutMs + " ms"); 68 } 69 } 70 71 /** 72 * Silently waits for a latch to be counted down, without throwing any exception if it isn't. 73 * 74 * @param timeoutMs how long to wait for 75 * 76 * @return whether the latch was counted down. 77 */ silentAwait(@onNull CountDownLatch latch, long timeoutMs)78 public static boolean silentAwait(@NonNull CountDownLatch latch, long timeoutMs) { 79 boolean called; 80 try { 81 Log.v(TAG, "waiting " + timeoutMs + "ms for semaphore " + latch); 82 called = latch.await(timeoutMs, TimeUnit.MILLISECONDS); 83 if (!called) { 84 Log.w(TAG, latch + " not called in " + timeoutMs + " ms"); 85 } 86 } catch (InterruptedException e) { 87 Thread.currentThread().interrupt(); 88 Log.w(TAG, latch + " interrupted", e); 89 return false; 90 } 91 return called; 92 } 93 94 /** 95 * Gets the result of a future, or throw a {@link IllegalStateException} if it times out after 96 * {@value #ASYNC_TIMEOUT_MS} ms. 97 */ 98 @NonNull getResult(@onNull Future<T> future, @NonNull String messageFormat, @Nullable Object...messageArgs)99 public static <T> T getResult(@NonNull Future<T> future, 100 @NonNull String messageFormat, @Nullable Object...messageArgs) { 101 return getResult(future, ASYNC_TIMEOUT_MS, messageFormat, messageArgs); 102 } 103 104 /** 105 * Gets the result of a future, or throw a {@link IllegalStateException} if it times out. 106 */ 107 @NonNull getResult(@onNull Future<T> future, long timeoutMs, @NonNull String messageFormat, @Nullable Object...messageArgs)108 public static <T> T getResult(@NonNull Future<T> future, long timeoutMs, 109 @NonNull String messageFormat, @Nullable Object...messageArgs) { 110 String msg = String.format(Objects.requireNonNull(messageFormat, "messageFormat"), 111 messageArgs); 112 try { 113 return future.get(timeoutMs, TimeUnit.MILLISECONDS); 114 } catch (InterruptedException e) { 115 Thread.currentThread().interrupt(); 116 throw new IllegalStateException("future for '" + msg + "' interrupted", e); 117 } catch (TimeoutException e) { 118 throw new IllegalStateException("future for '" + msg + "' not called in " 119 + timeoutMs + "ms", e); 120 } catch (ExecutionException e) { 121 throw new IllegalStateException("failed to get future for '" + msg + "'", e); 122 } 123 } 124 JavaMockitoHelper()125 private JavaMockitoHelper() { 126 throw new UnsupportedOperationException("contains only static methods"); 127 } 128 } 129