• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.telecom.cts.apps;
18 
19 import static android.os.SystemClock.sleep;
20 import static android.telecom.cts.apps.StackTraceUtil.appendStackTraceList;
21 
22 import static org.junit.Assert.assertEquals;
23 
24 import android.os.SystemClock;
25 import android.telecom.Connection;
26 import android.telecom.ConnectionRequest;
27 
28 import java.util.List;
29 import java.util.Objects;
30 import java.util.concurrent.CountDownLatch;
31 
32 public class WaitUntil {
33     public static final long DEFAULT_TIMEOUT_MS = 10000;
34     private static final String CLASS_NAME = WaitUntil.class.getCanonicalName();
35     private static final String TELECOM_ID_TOKEN = "_";
36 
37     // NOTE:
38     // - This method should NOT be called from a telecom test app. The assertEquals will cause
39     //     a DeadObjectException which will make any test failure log unreadable!
40     // - This can be used for classes like BindUtils, BaseAppVerifierImpl, etc. that are running
41     //    in the CTS test process
waitUntilConditionIsTrueOrTimeout( Condition condition, long timeout, String description)42     public static void waitUntilConditionIsTrueOrTimeout(
43             Condition condition,
44             long timeout,
45             String description) {
46 
47         long startTimeMillis = SystemClock.elapsedRealtime();
48         long remainingTimeMillis = timeout;
49         long elapsedTimeMillis;
50 
51         while (!Objects.equals(condition.expected(), condition.actual())
52                 && remainingTimeMillis > 0) {
53             sleep(50);
54             elapsedTimeMillis = SystemClock.elapsedRealtime() - startTimeMillis;
55             remainingTimeMillis = timeout - elapsedTimeMillis;
56         }
57         assertEquals(description, condition.expected(), condition.actual());
58     }
59 
60     // NOTE:
61     // - This method should NOT be called from a telecom test app. The assertEquals will cause
62     //     a DeadObjectException which will make any test failure log unreadable!
63     // - This can be used for classes like BindUtils, BaseAppVerifierImpl, etc. that are running
64     //    in the CTS test process
waitUntilConditionIsTrueOrTimeout( Condition condition)65     public static void waitUntilConditionIsTrueOrTimeout(
66             Condition condition) {
67         long startTimeMillis = SystemClock.elapsedRealtime();
68         long remainingTimeMillis = DEFAULT_TIMEOUT_MS;
69         long elapsedTimeMillis;
70 
71         while (!Objects.equals(condition.expected(), condition.actual())
72                 && remainingTimeMillis > 0) {
73             sleep(50);
74             elapsedTimeMillis = SystemClock.elapsedRealtime() - startTimeMillis;
75             remainingTimeMillis = DEFAULT_TIMEOUT_MS - elapsedTimeMillis;
76         }
77         assertEquals(condition.expected(), condition.actual());
78     }
79 
80     // This helper is intended for test apps!
waitUntilConditionIsTrueOrReturnFalse( Condition condition)81     private static boolean waitUntilConditionIsTrueOrReturnFalse(
82             Condition condition) {
83         long startTimeMillis = SystemClock.elapsedRealtime();
84         long remainingTimeMillis = DEFAULT_TIMEOUT_MS;
85         long elapsedTimeMillis;
86 
87         while (!Objects.equals(condition.expected(), condition.actual())
88                 && remainingTimeMillis > 0) {
89             sleep(50);
90             elapsedTimeMillis = SystemClock.elapsedRealtime() - startTimeMillis;
91             remainingTimeMillis = DEFAULT_TIMEOUT_MS - elapsedTimeMillis;
92         }
93         return (condition.expected().equals(condition.actual()));
94     }
95 
96 
97     public interface ConnectionServiceImpl {
getLastConnection()98         Connection getLastConnection();
99 
getLastFailedRequest()100         ConnectionRequest getLastFailedRequest();
101 
getCreateConnectionLatch(boolean isOutgoing)102         CountDownLatch getCreateConnectionLatch(boolean isOutgoing);
103     }
104 
waitUntilIdIsSet( String packageName, List<String> stackTrace, Connection connection)105     public static String waitUntilIdIsSet(
106             String packageName,
107             List<String> stackTrace,
108             Connection connection) {
109 
110         boolean success = waitUntilConditionIsTrueOrReturnFalse(
111                 new Condition() {
112                     @Override
113                     public Object expected() {
114                         return true;
115                     }
116 
117                     @Override
118                     public Object actual() {
119                         return connection.getTelecomCallId() != null
120                                 && !(connection.getTelecomCallId().equals(""));
121                     }
122                 }
123         );
124 
125         if (!success) {
126             throw new TestAppException(packageName,
127                     appendStackTraceList(stackTrace,
128                             CLASS_NAME + ".waitUntilIdIsSet"),
129                     "expected:<Connection#getCallId() to return an id within the time window>"
130                             + "actual:<hit timeout waiting for the Connection#getCallId() to be "
131                             + "set>");
132         }
133 
134         return extractTelecomId(connection);
135     }
136 
waitUntilCallAudioStateIsSet( String packageName, List<String> stackTrace, boolean isManaged, Connection connection)137     public static void waitUntilCallAudioStateIsSet(
138             String packageName,
139             List<String> stackTrace,
140             boolean isManaged,
141             Connection connection) {
142         boolean success = waitUntilConditionIsTrueOrReturnFalse(
143                 new Condition() {
144                     @Override
145                     public Object expected() {
146                         return true;
147                     }
148 
149                     @Override
150                     public Object actual() {
151                         if (isManaged) {
152                             return ((ManagedConnection) connection).getCurrentCallEndpointFromCallback()
153                                     != null;
154                         } else {
155                             return ((VoipConnection) connection).getCurrentCallEndpointFromCallback()
156                                     != null;
157                         }
158                     }
159                 }
160         );
161 
162         if (!success) {
163             throw new TestAppException(packageName,
164                     appendStackTraceList(stackTrace,
165                             CLASS_NAME + ".waitUntilCallAudioStateIsSet"),
166                     "expected:<Connection#onCallEndpointChanged() to set"
167                             + " Connection#mCallEndpoints within the time window> "
168                             + "actual:<hit timeout waiting for the CallEndpoint to be set>");
169         }
170     }
171 
waitUntilAvailableEndpointsIsSet( String packageName, List<String> stackTrace, boolean isManaged, Connection connection)172     public static void waitUntilAvailableEndpointsIsSet(
173             String packageName,
174             List<String> stackTrace,
175             boolean isManaged,
176             Connection connection) {
177         boolean success = waitUntilConditionIsTrueOrReturnFalse(
178                 new Condition() {
179                     @Override
180                     public Object expected() {
181                         return true;
182                     }
183 
184                     @Override
185                     public Object actual() {
186                         if (isManaged) {
187                             return ((ManagedConnection) connection).getCallEndpoints()
188                                     != null;
189                         } else {
190                             return ((VoipConnection) connection).getCallEndpoints()
191                                     != null;
192                         }
193                     }
194                 }
195         );
196 
197         if (!success) {
198             throw new TestAppException(packageName,
199                     appendStackTraceList(stackTrace,
200                             CLASS_NAME + ".waitUntilAvailableEndpointsIsSet"),
201                     "expected:<Connection#onAvailableCallEndpointsChanged() to set"
202                             + " ManagedConnection#mCallEndpoints within the time window> "
203                             + "actual:<hit timeout waiting for the CallEndpoints to be set>");
204         }
205     }
206 
waitUntilConnectionIsNonNull( String packageName, List<String> stackTrace, ConnectionServiceImpl s)207     public static Connection waitUntilConnectionIsNonNull(
208             String packageName,
209             List<String> stackTrace,
210             ConnectionServiceImpl s) {
211 
212         boolean success = waitUntilConditionIsTrueOrReturnFalse(
213                 new Condition() {
214                     @Override
215                     public Object expected() {
216                         return true;
217                     }
218 
219                     @Override
220                     public Object actual() {
221                         return getLastConnection(s) != null;
222                     }
223                 }
224         );
225 
226         if (!success) {
227             throw new TestAppException(packageName,
228                     appendStackTraceList(stackTrace,
229                             CLASS_NAME + ".waitUntilConnectionIsNonNull_Voip"),
230                     "expected:<Connection to be added to the ConnectionService> "
231                             + "actual:<hit timeout waiting for Connection>");
232         }
233 
234         return getLastConnection(s);
235     }
236 
waitUntilConnectionFails( String packageName, List<String> stackTrace, ConnectionServiceImpl s)237     public static ConnectionRequest waitUntilConnectionFails(
238             String packageName, List<String> stackTrace, ConnectionServiceImpl s) {
239 
240         boolean success =
241                 waitUntilConditionIsTrueOrReturnFalse(
242                         new Condition() {
243                             @Override
244                             public Object expected() {
245                                 return true;
246                             }
247 
248                             @Override
249                             public Object actual() {
250                                 return getLastFailedRequest(s) != null;
251                             }
252                         });
253 
254         if (!success) {
255             throw new TestAppException(
256                     packageName,
257                     appendStackTraceList(stackTrace, CLASS_NAME + ".waitUntilConnectionFails"),
258                     "expected:<Connection failed to be added to the ConnectionService> "
259                             + "actual:<no failed Connection detected>");
260         }
261 
262         return getLastFailedRequest(s);
263     }
264 
waitUntilManagedCreateConnectionInvoked( ConnectionServiceImpl s, boolean isOutgoing)265     public static boolean waitUntilManagedCreateConnectionInvoked(
266             ConnectionServiceImpl s, boolean isOutgoing) {
267 
268         return waitUntilConditionIsTrueOrReturnFalse(
269                 new Condition() {
270                     @Override
271                     public Object expected() {
272                         return true;
273                     }
274 
275                     @Override
276                     public Object actual() {
277                         return getCreateConnectionLatch(s, isOutgoing).getCount() == 0;
278                     }
279                 });
280     }
281 
282     private static String extractTelecomId(Connection connection) {
283         String str = connection.getTelecomCallId();
284         return str.substring(0, str.indexOf(TELECOM_ID_TOKEN));
285     }
286 
287     private static Connection getLastConnection(ConnectionServiceImpl s) {
288         return s.getLastConnection();
289     }
290 
291     private static ConnectionRequest getLastFailedRequest(ConnectionServiceImpl s) {
292         return s.getLastFailedRequest();
293     }
294 
295     private static CountDownLatch getCreateConnectionLatch(
296             ConnectionServiceImpl s, boolean isOutgoing) {
297         return s.getCreateConnectionLatch(isOutgoing);
298     }
299 
300     public static void waitUntilCurrentCallEndpointIsSet(
301             String packageName,
302             List<String> stackTrace,
303             TransactionalCallEvents events) throws TestAppException {
304         boolean success = WaitUntil.waitUntilConditionIsTrueOrReturnFalse(
305                 new Condition() {
306                     @Override
307                     public Object expected() {
308                         return true;
309                     }
310 
311                     @Override
312                     public Object actual() {
313                         return events.getCurrentCallEndpoint() != null;
314                     }
315                 }
316         );
317 
318         if (!success) {
319             throw new TestAppException(packageName,
320                     appendStackTraceList(stackTrace,
321                             CLASS_NAME + ".waitUntilCurrentCallEndpointIsSet"),
322                     "expected:<TransactionalCallEvents#onCallEndpointChanged() to set"
323                             + " TransactionalCallEvents#mCurrentCallEndpoint within time window>"
324                             + " actual:<hit timeout waiting for the CallEndpoint to be set>");
325         }
326     }
327 
328     public static void waitUntilAvailableEndpointAreSet(
329             String packageName,
330             List<String> stackTrace,
331             TransactionalCallEvents events) throws TestAppException {
332 
333         boolean success = WaitUntil.waitUntilConditionIsTrueOrReturnFalse(
334                 new Condition() {
335                     @Override
336                     public Object expected() {
337                         return true;
338                     }
339 
340                     @Override
341                     public Object actual() {
342                         return events.getCallEndpoints() != null;
343                     }
344                 }
345         );
346 
347         if (!success) {
348             throw new TestAppException(packageName,
349                     appendStackTraceList(stackTrace,
350                             CLASS_NAME + ".waitUntilAvailableEndpointAreSet"),
351                     "expected:<TransactionalCallEvents#onAvailableCallEndpointsChanged() to set"
352                             + " TransactionalCallEvents#mCallEndpoints within the time window> "
353                             + "actual:<hit timeout waiting for the CallEndpoints to be set>");
354         }
355     }
356 }
357