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 {@code module} is the version shipped with the original system image 137 * or if it has been updated via a mainline update. 138 * 139 * @param module the apex module name 140 * @return {@code true} if the apex module is the original version shipped with the device. 141 */ isMainlineModuleFactoryVersion(String module)142 public static boolean isMainlineModuleFactoryVersion(String module) { 143 try { 144 Context context = ApplicationProvider.getApplicationContext(); 145 PackageInfo info = context.getPackageManager().getPackageInfo(module, 146 MATCH_APEX); 147 if (info != null) { 148 return (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 149 } 150 } catch (PackageManager.NameNotFoundException e) { 151 // Ignore the exception on devices that do not have this module 152 } 153 return true; 154 } 155 156 /* 157 * decide whether we are in CTS, MCTS, or MTS mode. 158 * return the appropriate constant value 159 */ 160 public static final int TESTMODE_CTS = 0; 161 public static final int TESTMODE_MCTS = 1; 162 public static final int TESTMODE_MTS = 2; 163 164 /** 165 * Report the current testing mode, as an enumeration. 166 * Testing mode is determined by argument 'media-testing-mode' 167 * which specifies 'cts', 'mcts', or 'mts' 168 * If missing, we use the older boolean "mts-media" to generate either 'cts' or 'mts' 169 * 170 * This is most often specified in a CtsMedia* app's AndroidTest.xml, using 171 * a line like: 172 * <test class="com.android.tradefed.testtype.AndroidJUnitTest" > 173 * ... 174 * <option name="instrumentation-arg" key="media-testing-mode" value="CTS" /> 175 * </test> 176 * 177 * @return {@code} one of the values TESTMODE_CTS, TESTMODE_MCTS, or TESTMODE_MTS. 178 * 179 */ currentTestMode()180 public static int currentTestMode() { 181 Bundle bundle = InstrumentationRegistry.getArguments(); 182 String value = bundle.getString("media-testing-mode"); 183 if (value == null) { 184 value = bundle.getString("mts-media"); 185 if (value == null || !value.equals("true")) { 186 value = "CTS"; 187 } else { 188 value = "MTS"; 189 } 190 } 191 int mode; 192 value = value.toUpperCase(Locale.ROOT); 193 if (value.equals("CTS")) { 194 mode = TESTMODE_CTS; 195 } else if (value.equals("MCTS")) { 196 mode = TESTMODE_MCTS; 197 } else if (value.equals("MTS")) { 198 mode = TESTMODE_MTS; 199 } else { 200 mode = TESTMODE_CTS; 201 } 202 return mode; 203 } 204 205 /** 206 * Report the current testing mode, as a string. 207 * Testing mode is determined by argument 'media-testing-mode' 208 * which specifies 'cts', 'mcts', or 'mts' 209 * If missing, we use the older boolean "mts-media" to generate either 'cts' or 'mts' 210 * 211 * @return {@code} "CTS", "MCTS", or "MTS" corresponding to the mode. 212 */ currentTestModeName()213 public static String currentTestModeName() { 214 Bundle bundle = InstrumentationRegistry.getArguments(); 215 String value = bundle.getString("media-testing-mode"); 216 if (value == null) { 217 value = bundle.getString("mts-media"); 218 if (value == null || !value.equals("true")) { 219 value = "CTS"; 220 } else { 221 value = "MTS"; 222 } 223 } 224 value = value.toUpperCase(Locale.ROOT); 225 if (value.equals("CTS")) { 226 return "CTS"; 227 } else if (value.equals("MCTS")) { 228 return "MCTS"; 229 } else if (value.equals("MTS")) { 230 return "MTS"; 231 } else { 232 // same default as currentTestMode() 233 return "CTS"; 234 } 235 } 236 237 /** 238 * Report whether this test run should evaluate module functionality. 239 * Some tests (or parts of tests) are restricted to a particular mode. 240 * 241 * @return {@code} true is the current test mode is MCTS or MTS. 242 */ isTestingModules()243 public static boolean isTestingModules() { 244 int mode = currentTestMode(); 245 switch (mode) { 246 case TESTMODE_MCTS: 247 case TESTMODE_MTS: 248 return true; 249 default: 250 break; 251 } 252 return false; 253 } 254 255 /** 256 * Report whether we are in MTS mode (vs CTS or MCTS) mode. 257 * Some tests (or parts of tests) are restricted to a particular mode. 258 * 259 * @return {@code} true is the current test mode is MTS. 260 */ isMtsMode()261 public static boolean isMtsMode() { 262 int mode = currentTestMode(); 263 return mode == TESTMODE_MTS; 264 } 265 266 /* 267 * Report whether we want to test a particular code in the current test mode. 268 * CTS is pretty much "test them all". 269 * MTS should only be testing codecs that are part of the swcodec module; all of these 270 * begin with "c2.android." 271 * 272 * Used in spots throughout the test suite where we want to limit our testing to relevant 273 * codecs. This avoids false alarms that are sometimes triggered by non-compliant, 274 * non-mainline codecs. 275 * 276 * @param name the name of a codec 277 * @return {@code} true is the codec should be tested in the current operating mode. 278 */ isTestableCodecInCurrentMode(String name)279 public static boolean isTestableCodecInCurrentMode(String name) { 280 if (name == null) { 281 return true; 282 } 283 int mode = currentTestMode(); 284 boolean result = false; 285 switch (mode) { 286 case TESTMODE_CTS: 287 result = !isMainlineCodec(name); 288 break; 289 case TESTMODE_MCTS: 290 case TESTMODE_MTS: 291 result = isMainlineCodec(name); 292 break; 293 } 294 Log.d(TAG, "codec " + name + (result ? " is " : " is not ") 295 + "tested in mode " + currentTestModeName()); 296 return result; 297 } 298 299 /* 300 * Report whether this codec is a google-supplied codec that lives within the 301 * mainline modules. 302 * 303 * @param name the name of a codec 304 * @return {@code} true if the codec is one that lives within the mainline boundaries 305 */ isMainlineCodec(String name)306 public static boolean isMainlineCodec(String name) { 307 if (name.startsWith("c2.android.")) { 308 return true; 309 } 310 return false; 311 } 312 TestUtils()313 private TestUtils() { 314 } 315 316 public static class Monitor { 317 private int mNumSignal; 318 reset()319 public synchronized void reset() { 320 mNumSignal = 0; 321 } 322 signal()323 public synchronized void signal() { 324 mNumSignal++; 325 notifyAll(); 326 } 327 waitForSignal()328 public synchronized boolean waitForSignal() throws InterruptedException { 329 return waitForCountedSignals(1) > 0; 330 } 331 waitForCountedSignals(int targetCount)332 public synchronized int waitForCountedSignals(int targetCount) throws InterruptedException { 333 while (mNumSignal < targetCount) { 334 wait(); 335 } 336 return mNumSignal; 337 } 338 waitForSignal(long timeoutMs)339 public synchronized boolean waitForSignal(long timeoutMs) throws InterruptedException { 340 return waitForCountedSignals(1, timeoutMs) > 0; 341 } 342 waitForCountedSignals(int targetCount, long timeoutMs)343 public synchronized int waitForCountedSignals(int targetCount, long timeoutMs) 344 throws InterruptedException { 345 if (timeoutMs == 0) { 346 return waitForCountedSignals(targetCount); 347 } 348 long deadline = System.currentTimeMillis() + timeoutMs; 349 while (mNumSignal < targetCount) { 350 long delay = deadline - System.currentTimeMillis(); 351 if (delay <= 0) { 352 break; 353 } 354 wait(delay); 355 } 356 return mNumSignal; 357 } 358 isSignalled()359 public synchronized boolean isSignalled() { 360 return mNumSignal >= 1; 361 } 362 getNumSignal()363 public synchronized int getNumSignal() { 364 return mNumSignal; 365 } 366 } 367 } 368