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 
17 package com.android.server.people.data;
18 
19 import com.android.internal.util.Preconditions;
20 
21 import com.google.common.collect.ImmutableList;
22 
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.Delayed;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.ScheduledExecutorService;
31 import java.util.concurrent.ScheduledFuture;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 
35 /**
36  * Mock implementation of ScheduledExecutorService for testing. All commands will run
37  * synchronously. Commands passed to {@link #submit(Runnable)} and {@link #execute(Runnable)} will
38  * run immediately. Commands scheduled via {@link #schedule(Runnable, long, TimeUnit)} will run
39  * after calling {@link #fastForwardTime(long)}.
40  */
41 class MockScheduledExecutorService implements ScheduledExecutorService {
42 
43     private final List<Runnable> mExecutes = new ArrayList<>();
44     private final List<MockScheduledFuture<?>> mFutures = new ArrayList<>();
45     private long mTimeElapsedMillis = 0;
46 
47     /**
48      * Advances fake time, runs all the commands for which the delay has expired.
49      */
fastForwardTime(long millis)50     long fastForwardTime(long millis) {
51         mTimeElapsedMillis += millis;
52         ImmutableList<MockScheduledFuture<?>> futuresCopy = ImmutableList.copyOf(mFutures);
53         mFutures.clear();
54         long totalExecuted = 0;
55         for (MockScheduledFuture<?> future : futuresCopy) {
56             if (future.getDelay() < mTimeElapsedMillis) {
57                 future.getRunnable().run();
58                 mExecutes.add(future.getRunnable());
59                 totalExecuted += 1;
60             } else {
61                 mFutures.add(future);
62             }
63         }
64         return totalExecuted;
65     }
66 
getExecutes()67     List<Runnable> getExecutes() {
68         return mExecutes;
69     }
70 
getFutures()71     List<MockScheduledFuture<?>> getFutures() {
72         return mFutures;
73     }
74 
resetTimeElapsedMillis()75     void resetTimeElapsedMillis() {
76         mTimeElapsedMillis = 0;
77     }
78 
79     /**
80      * Fakes a schedule execution of {@link Runnable}. The command will be executed by an explicit
81      * call to {@link #fastForwardTime(long)}.
82      */
83     @Override
schedule(Runnable command, long delay, TimeUnit unit)84     public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
85         Preconditions.checkState(unit == TimeUnit.MILLISECONDS);
86         MockScheduledFuture<?> future = new MockScheduledFuture<>(command, delay, unit);
87         mFutures.add(future);
88         return future;
89     }
90 
91     @Override
schedule(Callable<V> callable, long delay, TimeUnit unit)92     public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
93         throw new UnsupportedOperationException();
94     }
95 
96     @Override
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)97     public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period,
98             TimeUnit unit) {
99         return new MockScheduledFuture<>(command, period, unit);
100     }
101 
102     @Override
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)103     public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
104             long delay, TimeUnit unit) {
105         throw new UnsupportedOperationException();
106     }
107 
108     @Override
shutdown()109     public void shutdown() {
110         throw new UnsupportedOperationException();
111     }
112 
113     @Override
shutdownNow()114     public List<Runnable> shutdownNow() {
115         throw new UnsupportedOperationException();
116     }
117 
118     @Override
isShutdown()119     public boolean isShutdown() {
120         return false;
121     }
122 
123     @Override
isTerminated()124     public boolean isTerminated() {
125         throw new UnsupportedOperationException();
126     }
127 
128     @Override
awaitTermination(long timeout, TimeUnit unit)129     public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
130         throw new UnsupportedOperationException();
131     }
132 
133     @Override
submit(Callable<T> task)134     public <T> Future<T> submit(Callable<T> task) {
135         MockScheduledFuture<T> future = new MockScheduledFuture<>(task, 0, TimeUnit.MILLISECONDS);
136         try {
137             future.getCallable().call();
138         } catch (Exception e) {
139             e.printStackTrace();
140         }
141         return future;
142     }
143 
144     @Override
submit(Runnable task, T result)145     public <T> Future<T> submit(Runnable task, T result) {
146         throw new UnsupportedOperationException();
147     }
148 
149     @Override
submit(Runnable runnable)150     public Future<?> submit(Runnable runnable) {
151         mExecutes.add(runnable);
152         MockScheduledFuture<?> future = new MockScheduledFuture<>(runnable, 0,
153                 TimeUnit.MILLISECONDS);
154         future.getRunnable().run();
155         return future;
156     }
157 
158     @Override
invokeAll(Collection<? extends Callable<T>> tasks)159     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
160             throws InterruptedException {
161         throw new UnsupportedOperationException();
162     }
163 
164     @Override
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)165     public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
166             TimeUnit unit) throws InterruptedException {
167         throw new UnsupportedOperationException();
168     }
169 
170     @Override
invokeAny(Collection<? extends Callable<T>> tasks)171     public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
172             throws ExecutionException, InterruptedException {
173         throw new UnsupportedOperationException();
174     }
175 
176     @Override
invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)177     public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
178             throws ExecutionException, InterruptedException, TimeoutException {
179         throw new UnsupportedOperationException();
180     }
181 
182     @Override
execute(Runnable command)183     public void execute(Runnable command) {
184         mExecutes.add(command);
185         command.run();
186     }
187 
188     class MockScheduledFuture<V> implements ScheduledFuture<V> {
189 
190         private final Runnable mRunnable;
191         private final Callable<V> mCallable;
192         private final long mDelay;
193         private boolean mCancelled = false;
194 
MockScheduledFuture(Runnable runnable, long delay, TimeUnit timeUnit)195         MockScheduledFuture(Runnable runnable, long delay, TimeUnit timeUnit) {
196             this(runnable, null, delay);
197         }
198 
MockScheduledFuture(Callable<V> callable, long delay, TimeUnit timeUnit)199         MockScheduledFuture(Callable<V> callable, long delay, TimeUnit timeUnit) {
200             this(null, callable, delay);
201         }
202 
MockScheduledFuture(Runnable runnable, Callable<V> callable, long delay)203         private MockScheduledFuture(Runnable runnable, Callable<V> callable, long delay) {
204             mCallable = callable;
205             mRunnable = runnable;
206             mDelay = delay;
207         }
208 
getDelay()209         public long getDelay() {
210             return mDelay;
211         }
212 
getRunnable()213         public Runnable getRunnable() {
214             return mRunnable;
215         }
216 
getCallable()217         public Callable<V> getCallable() {
218             return mCallable;
219         }
220 
221         @Override
getDelay(TimeUnit unit)222         public long getDelay(TimeUnit unit) {
223             throw new UnsupportedOperationException();
224         }
225 
226         @Override
compareTo(Delayed o)227         public int compareTo(Delayed o) {
228             throw new UnsupportedOperationException();
229         }
230 
231         @Override
cancel(boolean mayInterruptIfRunning)232         public boolean cancel(boolean mayInterruptIfRunning) {
233             mCancelled = true;
234             return mFutures.remove(this);
235         }
236 
237         @Override
isCancelled()238         public boolean isCancelled() {
239             return mCancelled;
240         }
241 
242         @Override
isDone()243         public boolean isDone() {
244             return !mFutures.contains(this);
245         }
246 
247         @Override
get()248         public V get() throws ExecutionException, InterruptedException {
249             return null;
250         }
251 
252         @Override
get(long timeout, TimeUnit unit)253         public V get(long timeout, TimeUnit unit)
254                 throws ExecutionException, InterruptedException, TimeoutException {
255             return null;
256         }
257     }
258 }
259