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 {@link 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 if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) { 49 throw new IllegalStateException(latch + " not called in " + timeoutMs + " ms"); 50 } 51 } 52 53 /** 54 * Waits for a semaphore. 55 * 56 * @param timeoutMs how long to wait for 57 * 58 * @throws {@link IllegalStateException} if it times out. 59 */ await(@onNull Semaphore semaphore, long timeoutMs)60 public static void await(@NonNull Semaphore semaphore, long timeoutMs) 61 throws InterruptedException { 62 if (!semaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 63 throw new IllegalStateException(semaphore + " not released in " + timeoutMs + " ms"); 64 } 65 } 66 67 /** 68 * Silently waits for a latch to be counted down, without throwing any exception if it isn't. 69 * 70 * @param timeoutMs how long to wait for 71 * 72 * @return whether the latch was counted down. 73 */ silentAwait(@onNull CountDownLatch latch, long timeoutMs)74 public static boolean silentAwait(@NonNull CountDownLatch latch, long timeoutMs) { 75 boolean called; 76 try { 77 called = latch.await(timeoutMs, TimeUnit.MILLISECONDS); 78 if (!called) { 79 Log.w(TAG, latch + " not called in " + timeoutMs + " ms"); 80 } 81 } catch (InterruptedException e) { 82 Thread.currentThread().interrupt(); 83 Log.w(TAG, latch + " interrupted", e); 84 return false; 85 } 86 return called; 87 } 88 89 /** 90 * Gets the result of a future, or throw a {@link IllegalStateException} if it times out after 91 * {@value #ASYNC_TIMEOUT_MS} ms. 92 */ 93 @NonNull getResult(@onNull Future<T> future, @NonNull String messageFormat, @Nullable Object...messageArgs)94 public static <T> T getResult(@NonNull Future<T> future, 95 @NonNull String messageFormat, @Nullable Object...messageArgs) { 96 return getResult(future, ASYNC_TIMEOUT_MS, messageFormat, messageArgs); 97 } 98 99 /** 100 * Gets the result of a future, or throw a {@link IllegalStateException} if it times out. 101 */ 102 @NonNull getResult(@onNull Future<T> future, long timeoutMs, @NonNull String messageFormat, @Nullable Object...messageArgs)103 public static <T> T getResult(@NonNull Future<T> future, long timeoutMs, 104 @NonNull String messageFormat, @Nullable Object...messageArgs) { 105 String msg = String.format(Objects.requireNonNull(messageFormat, "messageFormat"), 106 messageArgs); 107 try { 108 return future.get(timeoutMs, TimeUnit.MILLISECONDS); 109 } catch (InterruptedException e) { 110 Thread.currentThread().interrupt(); 111 throw new IllegalStateException("future for '" + msg + "' interrupted", e); 112 } catch (TimeoutException e) { 113 throw new IllegalStateException("future for '" + msg + "' not called in " 114 + timeoutMs + "ms", e); 115 } catch (ExecutionException e) { 116 throw new IllegalStateException("failed to get future for '" + msg + "'", e); 117 } 118 } 119 JavaMockitoHelper()120 private JavaMockitoHelper() { 121 throw new UnsupportedOperationException("contains only static methods"); 122 } 123 } 124