xref: /aosp_15_r20/cts/tests/tests/media/common/src/android/media/cts/TestUtils.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright 2018 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.media.cts;
18 
19 import static android.content.pm.PackageManager.MATCH_APEX;
20 
21 import static org.junit.Assume.assumeTrue;
22 
23 import android.content.Context;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.PackageManager;
27 import android.os.Bundle;
28 import android.util.Log;
29 
30 import androidx.test.core.app.ApplicationProvider;
31 import androidx.test.platform.app.InstrumentationRegistry;
32 
33 import org.junit.Assert;
34 import org.junit.AssumptionViolatedException;
35 
36 import java.util.Locale;
37 import java.util.Objects;
38 
39 /**
40  * Utilities for tests.
41  */
42 public final class TestUtils {
43     private static String TAG = "TestUtils";
44     private static final int WAIT_TIME_MS = 1000;
45     private static final int WAIT_SERVICE_TIME_MS = 5000;
46 
47     /**
48      * Compares contents of two bundles.
49      *
50      * @param a a bundle
51      * @param b another bundle
52      * @return {@code true} if two bundles are the same. {@code false} otherwise. This may be
53      *     incorrect if any bundle contains a bundle.
54      */
equals(Bundle a, Bundle b)55     public static boolean equals(Bundle a, Bundle b) {
56         if (a == b) {
57             return true;
58         }
59         if (a == null || b == null) {
60             return false;
61         }
62         if (!a.keySet().containsAll(b.keySet())
63                 || !b.keySet().containsAll(a.keySet())) {
64             return false;
65         }
66         for (String key : a.keySet()) {
67             if (!Objects.equals(a.get(key), b.get(key))) {
68                 return false;
69             }
70         }
71         return true;
72     }
73 
74     /**
75      * Checks {@code module} is at least {@code minVersion}
76      *
77      * The tests are skipped by throwing a {@link AssumptionViolatedException}.  CTS test runners
78      * will report this as a {@code ASSUMPTION_FAILED}.
79      *
80      * @param module     the apex module name
81      * @param minVersion the minimum version
82      * @throws AssumptionViolatedException if module version < minVersion
83      */
assumeMainlineModuleAtLeast(String module, long minVersion)84     public static void assumeMainlineModuleAtLeast(String module, long minVersion) {
85         try {
86             long actualVersion = getModuleVersion(module);
87             assumeTrue("Assume  module  " + module + " version " + actualVersion + " < minVersion"
88                     + minVersion, actualVersion >= minVersion);
89         } catch (PackageManager.NameNotFoundException e) {
90             Assert.fail(e.getMessage());
91         }
92     }
93 
94     /**
95      * Checks if {@code module} is < {@code minVersion}
96      *
97      * <p>
98      * {@link AssumptionViolatedException} is not handled properly by {@code JUnit3} so just return
99      * the test
100      * early instead.
101      *
102      * @param module     the apex module name
103      * @param minVersion the minimum version
104      * @deprecated convert test to JUnit4 and use
105      * {@link #assumeMainlineModuleAtLeast(String, long)} instead.
106      */
107     @Deprecated
skipTestIfMainlineLessThan(String module, long minVersion)108     public static boolean skipTestIfMainlineLessThan(String module, long minVersion) {
109         try {
110             long actualVersion = getModuleVersion(module);
111             if (actualVersion < minVersion) {
112                 Log.i(TAG, "Skipping test because Module  " + module + " minVersion " + minVersion
113                         + " > "
114                         + minVersion
115                 );
116                 return true;
117             } else {
118                 return false;
119             }
120         } catch (PackageManager.NameNotFoundException e) {
121             Assert.fail(e.getMessage());
122             return false;
123         }
124     }
125 
getModuleVersion(String module)126     private static long getModuleVersion(String module)
127             throws PackageManager.NameNotFoundException {
128         Context context = ApplicationProvider.getApplicationContext();
129         PackageInfo info = context.getPackageManager().getPackageInfo(module,
130                 MATCH_APEX);
131         return info.getLongVersionCode();
132     }
133 
134 
135     /**
136      * Reports whether the APEX mainline module {@code module} has been updated from the
137      * version in the system image. The result is used to decide whether to relax some
138      * test criteria, like software codec performance being improved to run faster
139      * than performance data at initial release.
140      *
141      * @param module     the apex module name
142      * @return {@code true} {@code module} refers to an apex module which has been updated.
143      */
isUpdatedMainlineModule(String module)144     public static boolean isUpdatedMainlineModule(String module) {
145         try {
146             Context context = ApplicationProvider.getApplicationContext();
147             PackageInfo info = context.getPackageManager().getPackageInfo(module,
148                     MATCH_APEX);
149             if (info == null) {
150                 return false;
151             }
152             ApplicationInfo appInfo = info.applicationInfo;
153             if (appInfo == null) {
154                 return false;
155             }
156             // FLAG_SYSTEM changes during apex update on <= T; but stays set on >=U
157             // FLAG_UPDATED_SYSTEM_APP always provides desired signalling
158             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0) {
159                 return false;
160             }
161             return true;
162         } catch (PackageManager.NameNotFoundException e) {
163             // doesn't exist, so it can't be upgraded
164         }
165         // we don't have information telling us otherwise.
166         return false;
167     }
168 
169     /*
170      * decide whether we are in CTS, MCTS, or MTS mode.
171      * return the appropriate constant value
172      */
173     public static final int TESTMODE_CTS = 0;
174     public static final int TESTMODE_MCTS = 1;
175     public static final int TESTMODE_MTS = 2;
176 
177     /**
178      * Report the current testing mode, as an enumeration.
179      * Testing mode is determined by argument 'media-testing-mode'
180      * which specifies 'cts', 'mcts', or 'mts'
181      * If missing, we use the older boolean "mts-media" to generate either 'cts' or 'mts'
182      *
183      * This is most often specified in a CtsMedia* app's AndroidTest.xml, using
184      * a line like:
185      * <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
186      * ...
187      * <option name="instrumentation-arg" key="media-testing-mode" value="CTS" />
188      * </test>
189      *
190      * @return {@code} one of the values TESTMODE_CTS, TESTMODE_MCTS, or TESTMODE_MTS.
191      *
192      */
currentTestMode()193     public static int currentTestMode() {
194         Bundle bundle = InstrumentationRegistry.getArguments();
195         String value = bundle.getString("media-testing-mode");
196         if (value == null) {
197             value = bundle.getString("mts-media");
198             if (value == null || !value.equals("true")) {
199                 value = "CTS";
200             } else {
201                 value = "MTS";
202             }
203         }
204         int mode;
205         value = value.toUpperCase(Locale.ROOT);
206         if (value.equals("CTS")) {
207             mode = TESTMODE_CTS;
208         } else if (value.equals("MCTS")) {
209             mode = TESTMODE_MCTS;
210         } else if (value.equals("MTS")) {
211             mode = TESTMODE_MTS;
212         } else {
213             mode = TESTMODE_CTS;
214         }
215         return mode;
216     }
217 
218     /**
219      * Report the current testing mode, as a string.
220      * Testing mode is determined by argument 'media-testing-mode'
221      * which specifies 'cts', 'mcts', or 'mts'
222      * If missing, we use the older boolean "mts-media" to generate either 'cts' or 'mts'
223      *
224      * @return {@code} "CTS", "MCTS", or "MTS" corresponding to the mode.
225      */
currentTestModeName()226     public static String currentTestModeName() {
227         Bundle bundle = InstrumentationRegistry.getArguments();
228         String value = bundle.getString("media-testing-mode");
229         if (value == null) {
230             value = bundle.getString("mts-media");
231             if (value == null || !value.equals("true")) {
232                 value = "CTS";
233             } else {
234                 value = "MTS";
235             }
236         }
237         value = value.toUpperCase(Locale.ROOT);
238         if (value.equals("CTS")) {
239             return "CTS";
240         } else if (value.equals("MCTS")) {
241             return "MCTS";
242         } else if (value.equals("MTS")) {
243             return "MTS";
244         } else {
245             // same default as currentTestMode()
246             return "CTS";
247         }
248     }
249 
250     /**
251      * Report whether this test run should evaluate module functionality.
252      * Some tests (or parts of tests) are restricted to a particular mode.
253      *
254      * @return {@code} true is the current test mode is MCTS or MTS.
255      */
isTestingModules()256     public static boolean isTestingModules() {
257         int mode = currentTestMode();
258         switch (mode) {
259             case TESTMODE_MCTS:
260             case TESTMODE_MTS:
261                 return true;
262             default:
263                 break;
264         }
265         return false;
266     }
267 
268     /**
269      * Report whether we are in MTS mode (vs CTS or MCTS) mode.
270      * Some tests (or parts of tests) are restricted to a particular mode.
271      *
272      * @return {@code} true is the current test mode is MTS.
273      */
isMtsMode()274     public static boolean isMtsMode() {
275         int mode = currentTestMode();
276         return mode == TESTMODE_MTS;
277     }
278 
279     /*
280      * Report whether we want to test a particular code in the current test mode.
281      * CTS is pretty much "test them all".
282      * MTS should only be testing codecs that are part of the swcodec module; all of these
283      * begin with "c2.android."
284      *
285      * Used in spots throughout the test suite where we want to limit our testing to relevant
286      * codecs. This avoids false alarms that are sometimes triggered by non-compliant,
287      * non-mainline codecs.
288      *
289      * @param name    the name of a codec
290      * @return {@code} true is the codec should be tested in the current operating mode.
291      */
isTestableCodecInCurrentMode(String name)292     public static boolean isTestableCodecInCurrentMode(String name) {
293         if (name == null) {
294             return true;
295         }
296         int mode = currentTestMode();
297         boolean result = false;
298         switch (mode) {
299             case TESTMODE_CTS:
300                 result = !isMainlineCodec(name);
301                 break;
302             case TESTMODE_MCTS:
303             case TESTMODE_MTS:
304                 result = isMainlineCodec(name);
305                 break;
306         }
307         Log.d(TAG, "codec " + name + (result ? " is " : " is not ")
308                    + "tested in mode " + currentTestModeName());
309         return result;
310     }
311 
312     /*
313      * Report whether this codec is a google-supplied codec that lives within the
314      * mainline modules.
315      *
316      * @param name    the name of a codec
317      * @return {@code} true if the codec is one that lives within the mainline boundaries
318      */
isMainlineCodec(String name)319     public static boolean isMainlineCodec(String name) {
320         if (name.startsWith("c2.android.")) {
321             return true;
322         }
323         return false;
324     }
325 
TestUtils()326     private TestUtils() {
327     }
328 
329     public static class Monitor {
330         private int mNumSignal;
331 
reset()332         public synchronized void reset() {
333             mNumSignal = 0;
334         }
335 
signal()336         public synchronized void signal() {
337             mNumSignal++;
338             notifyAll();
339         }
340 
waitForSignal()341         public synchronized boolean waitForSignal() throws InterruptedException {
342             return waitForCountedSignals(1) > 0;
343         }
344 
waitForCountedSignals(int targetCount)345         public synchronized int waitForCountedSignals(int targetCount) throws InterruptedException {
346             while (mNumSignal < targetCount) {
347                 wait();
348             }
349             return mNumSignal;
350         }
351 
waitForSignal(long timeoutMs)352         public synchronized boolean waitForSignal(long timeoutMs) throws InterruptedException {
353             return waitForCountedSignals(1, timeoutMs) > 0;
354         }
355 
waitForCountedSignals(int targetCount, long timeoutMs)356         public synchronized int waitForCountedSignals(int targetCount, long timeoutMs)
357                 throws InterruptedException {
358             if (timeoutMs == 0) {
359                 return waitForCountedSignals(targetCount);
360             }
361             long deadline = System.currentTimeMillis() + timeoutMs;
362             while (mNumSignal < targetCount) {
363                 long delay = deadline - System.currentTimeMillis();
364                 if (delay <= 0) {
365                     break;
366                 }
367                 wait(delay);
368             }
369             return mNumSignal;
370         }
371 
isSignalled()372         public synchronized boolean isSignalled() {
373             return mNumSignal >= 1;
374         }
375 
getNumSignal()376         public synchronized int getNumSignal() {
377             return mNumSignal;
378         }
379     }
380 }
381