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