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 com.android.server.timezonedetector.location; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 25 import java.time.Duration; 26 import java.util.ArrayList; 27 import java.util.Comparator; 28 import java.util.Objects; 29 import java.util.concurrent.Callable; 30 31 /** 32 * A ThreadingDomain that simulates idealized post() semantics. Execution takes place in zero time, 33 * exactly when scheduled, when the test code explicitly requests it. Execution takes place on the 34 * test's main thread. 35 */ 36 class TestThreadingDomain extends ThreadingDomain { 37 38 static class QueuedRunnable { 39 40 static final Comparator<? super QueuedRunnable> COMPARATOR = 41 (o1, o2) -> (int) (o1.executionTimeMillis - o2.executionTimeMillis); 42 43 @NonNull public final Runnable runnable; 44 @Nullable public final Object token; 45 public final long executionTimeMillis; 46 QueuedRunnable(@onNull Runnable runnable, @Nullable Object token, long executionTimeMillis)47 QueuedRunnable(@NonNull Runnable runnable, @Nullable Object token, 48 long executionTimeMillis) { 49 this.runnable = Objects.requireNonNull(runnable); 50 this.token = token; 51 this.executionTimeMillis = executionTimeMillis; 52 } 53 54 @Override toString()55 public String toString() { 56 return "QueuedRunnable{" 57 + "runnable=" + runnable 58 + ", token=" + token 59 + ", executionTimeMillis=" + executionTimeMillis 60 + '}'; 61 } 62 } 63 64 private long mCurrentTimeMillis; 65 private ArrayList<QueuedRunnable> mQueue = new ArrayList<>(); 66 TestThreadingDomain()67 TestThreadingDomain() { 68 // Pick an arbitrary time. 69 mCurrentTimeMillis = 123456L; 70 } 71 72 @Override getThread()73 Thread getThread() { 74 return Thread.currentThread(); 75 } 76 77 @Override post(Runnable r)78 void post(Runnable r) { 79 postDelayed(r, null, 0); 80 } 81 82 @Override postAndWait(Callable<V> callable, long durationMillis)83 <V> V postAndWait(Callable<V> callable, long durationMillis) { 84 throw new UnsupportedOperationException("Not implemented"); 85 } 86 87 @Override postDelayed(Runnable r, long delayMillis)88 void postDelayed(Runnable r, long delayMillis) { 89 postDelayed(r, null, delayMillis); 90 } 91 92 @Override postDelayed(Runnable r, Object token, long delayMillis)93 void postDelayed(Runnable r, Object token, long delayMillis) { 94 mQueue.add(new QueuedRunnable(r, token, mCurrentTimeMillis + delayMillis)); 95 mQueue.sort(QueuedRunnable.COMPARATOR); 96 } 97 98 @Override removeQueuedRunnables(Object token)99 void removeQueuedRunnables(Object token) { 100 mQueue.removeIf(runnable -> runnable.token != null && runnable.token == token); 101 } 102 removeAllQueuedRunnables()103 void removeAllQueuedRunnables() { 104 mQueue.clear(); 105 } 106 assertSingleDelayedQueueItem(Duration expectedDelay)107 void assertSingleDelayedQueueItem(Duration expectedDelay) { 108 assertQueueLength(1); 109 assertNextQueueItemIsDelayed(expectedDelay); 110 } 111 assertSingleImmediateQueueItem()112 void assertSingleImmediateQueueItem() { 113 assertQueueLength(1); 114 assertNextQueueItemIsImmediate(); 115 } 116 assertQueueLength(int expectedLength)117 void assertQueueLength(int expectedLength) { 118 assertEquals(expectedLength, mQueue.size()); 119 } 120 assertNextQueueItemIsImmediate()121 void assertNextQueueItemIsImmediate() { 122 assertTrue(getNextQueueItemDelayMillis() == 0); 123 } 124 assertNextQueueItemIsDelayed(Duration expectedDelay)125 private void assertNextQueueItemIsDelayed(Duration expectedDelay) { 126 assertEquals(getNextQueueItemDelayMillis(), expectedDelay.toMillis()); 127 } 128 assertQueueEmpty()129 void assertQueueEmpty() { 130 assertTrue(mQueue.isEmpty()); 131 } 132 getNextQueueItemDelayMillis()133 long getNextQueueItemDelayMillis() { 134 assertFalse(mQueue.isEmpty()); 135 return mQueue.get(0).executionTimeMillis - mCurrentTimeMillis; 136 } 137 executeNext()138 void executeNext() { 139 assertFalse(mQueue.isEmpty()); 140 QueuedRunnable queued = mQueue.remove(0); 141 142 mCurrentTimeMillis = queued.executionTimeMillis; 143 queued.runnable.run(); 144 } 145 } 146