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 package com.android.adservices.shared.testing; 17 18 import static com.android.adservices.shared.testing.concurrency.SyncCallback.LOG_TAG; 19 20 import com.android.adservices.shared.testing.DeviceConfigHelper.SyncDisabledModeForTest; 21 import com.android.adservices.shared.testing.Logger.LogLevel; 22 import com.android.adservices.shared.testing.Logger.RealLogger; 23 import com.android.adservices.shared.testing.NameValuePair.Matcher; 24 import com.android.adservices.shared.testing.annotations.DisableDebugFlag; 25 import com.android.adservices.shared.testing.annotations.DisableDebugFlags; 26 import com.android.adservices.shared.testing.annotations.EnableDebugFlag; 27 import com.android.adservices.shared.testing.annotations.EnableDebugFlags; 28 import com.android.adservices.shared.testing.annotations.SetDoubleFlag; 29 import com.android.adservices.shared.testing.annotations.SetDoubleFlags; 30 import com.android.adservices.shared.testing.annotations.SetFlagDisabled; 31 import com.android.adservices.shared.testing.annotations.SetFlagEnabled; 32 import com.android.adservices.shared.testing.annotations.SetFlagFalse; 33 import com.android.adservices.shared.testing.annotations.SetFlagTrue; 34 import com.android.adservices.shared.testing.annotations.SetFlagsDisabled; 35 import com.android.adservices.shared.testing.annotations.SetFlagsEnabled; 36 import com.android.adservices.shared.testing.annotations.SetFlagsFalse; 37 import com.android.adservices.shared.testing.annotations.SetFlagsTrue; 38 import com.android.adservices.shared.testing.annotations.SetFloatFlag; 39 import com.android.adservices.shared.testing.annotations.SetFloatFlags; 40 import com.android.adservices.shared.testing.annotations.SetIntegerFlag; 41 import com.android.adservices.shared.testing.annotations.SetIntegerFlags; 42 import com.android.adservices.shared.testing.annotations.SetLogcatTag; 43 import com.android.adservices.shared.testing.annotations.SetLogcatTags; 44 import com.android.adservices.shared.testing.annotations.SetLongDebugFlag; 45 import com.android.adservices.shared.testing.annotations.SetLongDebugFlags; 46 import com.android.adservices.shared.testing.annotations.SetLongFlag; 47 import com.android.adservices.shared.testing.annotations.SetLongFlags; 48 import com.android.adservices.shared.testing.annotations.SetStringArrayFlag; 49 import com.android.adservices.shared.testing.annotations.SetStringArrayFlags; 50 import com.android.adservices.shared.testing.annotations.SetStringFlag; 51 import com.android.adservices.shared.testing.annotations.SetStringFlags; 52 53 import com.google.errorprone.annotations.FormatMethod; 54 import com.google.errorprone.annotations.FormatString; 55 56 import org.junit.runner.Description; 57 import org.junit.runners.model.Statement; 58 59 import java.lang.annotation.Annotation; 60 import java.util.ArrayList; 61 import java.util.LinkedHashSet; 62 import java.util.List; 63 import java.util.Objects; 64 import java.util.Set; 65 66 // TODO(b/294423183): add unit tests for the most relevant / less repetitive stuff (don't need to 67 // test all setters / getters, for example) 68 /** 69 * Rule used to properly set "Android flags"- it will take care of permissions, restoring values at 70 * the end, setting {@link android.provider.DeviceConfig} or {@link android.os.SystemProperties}, 71 * etc... 72 */ 73 public abstract class AbstractFlagsSetterRule<T extends AbstractFlagsSetterRule<T>> 74 extends AbstractRethrowerRule { 75 76 protected static final String SYSTEM_PROPERTY_FOR_LOGCAT_TAGS_PREFIX = "log.tag."; 77 78 private final String mDeviceConfigNamespace; 79 private final DeviceConfigHelper mDeviceConfig; 80 // TODO(b/338067482): move system properties to its own rule? 81 // Prefix used on SystemProperties used for DebugFlags 82 private final String mDebugFlagPrefix; 83 private final SystemPropertiesHelper mSystemProperties; 84 85 // Cache methods that were called before the test started, so the rule can be 86 // instantiated using a builder-like approach. 87 private final List<Command> mInitialCommands = new ArrayList<>(); 88 89 // Name of flags that were changed by the test 90 private final Set<String> mChangedFlags = new LinkedHashSet<>(); 91 // Name of system properties that were changed by the test 92 private final Set<String> mChangedSystemProperties = new LinkedHashSet<>(); 93 private final Matcher mSystemPropertiesMatcher; 94 95 private final List<NameValuePair> mPreTestFlags = new ArrayList<>(); 96 private final List<NameValuePair> mPreTestSystemProperties = new ArrayList<>(); 97 private final List<NameValuePair> mOnTestFailureFlags = new ArrayList<>(); 98 private final List<NameValuePair> mOnTestFailureSystemProperties = new ArrayList<>(); 99 100 private final SyncDisabledModeForTest mPreviousSyncDisabledModeForTest; 101 102 private boolean mIsRunning; 103 private boolean mFlagsClearedByTest; 104 AbstractFlagsSetterRule( RealLogger logger, String deviceConfigNamespace, String debugFlagPrefix, DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, SystemPropertiesHelper.Interface systemPropertiesInterface)105 protected AbstractFlagsSetterRule( 106 RealLogger logger, 107 String deviceConfigNamespace, 108 String debugFlagPrefix, 109 DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, 110 SystemPropertiesHelper.Interface systemPropertiesInterface) { 111 this( 112 logger, 113 deviceConfigNamespace, 114 debugFlagPrefix, 115 // TODO(b/294423183, 328682831): should not be necessary, but integrated with 116 // setLogcatTag() 117 (prop) -> 118 prop.name.startsWith(debugFlagPrefix) 119 || prop.name.startsWith(SYSTEM_PROPERTY_FOR_LOGCAT_TAGS_PREFIX), 120 deviceConfigInterfaceFactory, 121 systemPropertiesInterface); 122 } 123 AbstractFlagsSetterRule( RealLogger logger, String deviceConfigNamespace, String debugFlagPrefix, Matcher systemPropertiesMatcher, DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, SystemPropertiesHelper.Interface systemPropertiesInterface)124 protected AbstractFlagsSetterRule( 125 RealLogger logger, 126 String deviceConfigNamespace, 127 String debugFlagPrefix, 128 Matcher systemPropertiesMatcher, 129 DeviceConfigHelper.InterfaceFactory deviceConfigInterfaceFactory, 130 SystemPropertiesHelper.Interface systemPropertiesInterface) { 131 132 super(logger); 133 134 mDeviceConfigNamespace = Objects.requireNonNull(deviceConfigNamespace); 135 mDebugFlagPrefix = Objects.requireNonNull(debugFlagPrefix); 136 mSystemPropertiesMatcher = Objects.requireNonNull(systemPropertiesMatcher); 137 mDeviceConfig = 138 new DeviceConfigHelper(deviceConfigInterfaceFactory, deviceConfigNamespace, logger); 139 mSystemProperties = new SystemPropertiesHelper(systemPropertiesInterface, logger); 140 // TODO(b/294423183): ideally the current mode should be returned by 141 // setSyncDisabledMode(), 142 // but unfortunately getting the current mode is not straightforward due to 143 // different 144 // behaviors: 145 // - T+ provides get_sync_disabled_for_tests 146 // - S provides is_sync_disabled_for_tests 147 // - R doesn't provide anything 148 mPreviousSyncDisabledModeForTest = SyncDisabledModeForTest.NONE; 149 // Must set right away to avoid race conditions (for example, backend setting flags before 150 // apply() is called) 151 setSyncDisabledMode(SyncDisabledModeForTest.PERSISTENT); 152 153 mLog.v( 154 "Constructor: mDeviceConfigNamespace=%s," 155 + " mDebugFlagPrefix=%s,mDeviceConfig=%s, mSystemProperties=%s," 156 + " mPreviousSyncDisabledModeForTest=%s", 157 mDeviceConfigNamespace, 158 mDebugFlagPrefix, 159 mDeviceConfig, 160 mSystemProperties, 161 mPreviousSyncDisabledModeForTest); 162 } 163 164 @Override preTest(Statement base, Description description, List<Throwable> cleanUpErrors)165 protected void preTest(Statement base, Description description, List<Throwable> cleanUpErrors) { 166 String testName = TestHelper.getTestName(description); 167 mIsRunning = true; 168 169 // TODO(b/294423183): ideally should be "setupErrors", but it's not used yet (other 170 // than logging), so it doesn't matter 171 runSafely(cleanUpErrors, () -> mPreTestFlags.addAll(mDeviceConfig.getAll())); 172 runSafely( 173 cleanUpErrors, 174 () -> 175 mPreTestSystemProperties.addAll( 176 mSystemProperties.getAll(mSystemPropertiesMatcher))); 177 178 setAnnotatedFlags(description); 179 runInitialCommands(testName); 180 } 181 182 @Override onTestFailure( Statement base, Description description, List<Throwable> cleanUpErrors, Throwable testFailure)183 protected void onTestFailure( 184 Statement base, 185 Description description, 186 List<Throwable> cleanUpErrors, 187 Throwable testFailure) { 188 runSafely(cleanUpErrors, () -> mOnTestFailureFlags.addAll(mDeviceConfig.getAll())); 189 runSafely( 190 cleanUpErrors, 191 () -> 192 mOnTestFailureSystemProperties.addAll( 193 mSystemProperties.getAll(mSystemPropertiesMatcher))); 194 } 195 196 @Override postTest( Statement base, Description description, List<Throwable> cleanUpErrors)197 protected void postTest( 198 Statement base, Description description, List<Throwable> cleanUpErrors) { 199 String testName = TestHelper.getTestName(description); 200 runSafely(cleanUpErrors, () -> resetFlags(testName)); 201 runSafely(cleanUpErrors, () -> resetSystemProperties(testName)); 202 runSafely(cleanUpErrors, () -> setSyncDisabledMode(mPreviousSyncDisabledModeForTest)); 203 mIsRunning = false; 204 } 205 setSyncDisabledMode(SyncDisabledModeForTest mode)206 private void setSyncDisabledMode(SyncDisabledModeForTest mode) { 207 runOrCache( 208 "setSyncDisabledMode(" + mode + ")", () -> mDeviceConfig.setSyncDisabledMode(mode)); 209 } 210 211 @Override decorateTestFailureMessage(StringBuilder dump, List<Throwable> cleanUpErrors)212 protected String decorateTestFailureMessage(StringBuilder dump, List<Throwable> cleanUpErrors) { 213 if (mFlagsClearedByTest) { 214 dump.append("NOTE: test explicitly cleared all flags.\n"); 215 } 216 217 logAllAndDumpDiff( 218 "flags", dump, mChangedFlags, mPreTestFlags, mOnTestFailureSystemProperties); 219 logAllAndDumpDiff( 220 "system properties", 221 dump, 222 mChangedSystemProperties, 223 mPreTestSystemProperties, 224 mOnTestFailureSystemProperties); 225 return "flags / system properties state"; 226 } 227 logAllAndDumpDiff( String what, StringBuilder dump, Set<String> changedNames, List<NameValuePair> preTest, List<NameValuePair> postTest)228 private void logAllAndDumpDiff( 229 String what, 230 StringBuilder dump, 231 Set<String> changedNames, 232 List<NameValuePair> preTest, 233 List<NameValuePair> postTest) { 234 // Log all values 235 log(preTest, "%s before the test", what); 236 log(postTest, "%s after the test", what); 237 238 // Dump only what was change 239 appendChanges(dump, what, changedNames, preTest, postTest); 240 } 241 appendChanges( StringBuilder dump, String what, Set<String> changedNames, List<NameValuePair> preTest, List<NameValuePair> postTest)242 private void appendChanges( 243 StringBuilder dump, 244 String what, 245 Set<String> changedNames, 246 List<NameValuePair> preTest, 247 List<NameValuePair> postTest) { 248 if (changedNames.isEmpty()) { 249 dump.append("Tested didn't change any ").append(what).append('\n'); 250 return; 251 } 252 dump.append("Test changed ") 253 .append(changedNames.size()) 254 .append(' ') 255 .append(what) 256 .append(" (see log for all changes): \n"); 257 258 for (String name : changedNames) { 259 String before = getValue("before", preTest, name); 260 String after = getValue("after", postTest, name); 261 dump.append('\t') 262 .append(name) 263 .append(": ") 264 .append(before) 265 .append(", ") 266 .append(after) 267 .append('\n'); 268 } 269 } 270 getValue(String when, List<NameValuePair> list, String name)271 private String getValue(String when, List<NameValuePair> list, String name) { 272 for (NameValuePair candidate : list) { 273 if (candidate.name.equals(name)) { 274 return when + "=" + candidate.value; 275 } 276 } 277 return "(not set " + when + ")"; 278 } 279 280 /** 281 * Dumps all flags using the {@value #TAG} tag. 282 * 283 * <p>Typically use for temporary debugging purposes like {@code dumpFlags("getFoo(%s)", bar)}. 284 */ 285 @FormatMethod dumpFlags(@ormatString String reasonFmt, @Nullable Object... reasonArgs)286 public final void dumpFlags(@FormatString String reasonFmt, @Nullable Object... reasonArgs) { 287 log(mDeviceConfig.getAll(), "flags (Reason: %s)", String.format(reasonFmt, reasonArgs)); 288 } 289 290 /** 291 * Dumps all system properties using the {@value #TAG} tag. 292 * 293 * <p>Typically use for temporary debugging purposes like {@code 294 * dumpSystemProperties("getFoo(%s)", bar)}. 295 */ 296 @FormatMethod dumpSystemProperties( @ormatString String reasonFmt, @Nullable Object... reasonArgs)297 public final void dumpSystemProperties( 298 @FormatString String reasonFmt, @Nullable Object... reasonArgs) { 299 log( 300 mSystemProperties.getAll(mSystemPropertiesMatcher), 301 "system properties (Reason: %s)", 302 String.format(reasonFmt, reasonArgs)); 303 } 304 305 @FormatMethod log( List<NameValuePair> values, @FormatString String whatFmt, @Nullable Object... whatArgs)306 private void log( 307 List<NameValuePair> values, 308 @FormatString String whatFmt, 309 @Nullable Object... whatArgs) { 310 String what = String.format(whatFmt, whatArgs); 311 if (values.isEmpty()) { 312 mLog.e("%s: empty", what); 313 return; 314 } 315 mLog.i("Logging name/value of %d %s:", values.size(), what); 316 values.forEach(value -> mLog.i("\t%s", value)); 317 } 318 319 /** Clears all flags from the namespace */ clearFlags()320 public final T clearFlags() { 321 return runOrCache( 322 "clearFlags()", 323 () -> { 324 mLog.i("Clearing all flags. mIsRunning=%b", mIsRunning); 325 mDeviceConfig.clearFlags(); 326 // TODO(b/294423183): ideally we should save the flags and restore - possibly 327 // using DeviceConfig properties - but for now let's just clear it. 328 mFlagsClearedByTest = true; 329 }); 330 } 331 332 /** Sets the flag with the given value. */ setFlag(String name, boolean value)333 public final T setFlag(String name, boolean value) { 334 return setOrCacheFlag(name, Boolean.toString(value)); 335 } 336 337 /** Sets the flag with the given value. */ setFlag(String name, int value)338 public final T setFlag(String name, int value) { 339 return setOrCacheFlag(name, Integer.toString(value)); 340 } 341 342 /** Sets the flag with the given value. */ setFlag(String name, long value)343 public final T setFlag(String name, long value) { 344 return setOrCacheFlag(name, Long.toString(value)); 345 } 346 347 /** Sets the flag with the given value. */ setFlag(String name, float value)348 public final T setFlag(String name, float value) { 349 return setOrCacheFlag(name, Float.toString(value)); 350 } 351 352 /** Sets the flag with the given value. */ setFlag(String name, double value)353 public final T setFlag(String name, double value) { 354 return setOrCacheFlag(name, Double.toString(value)); 355 } 356 357 /** Sets the flag with the given value. */ setFlag(String name, String value)358 public final T setFlag(String name, String value) { 359 return setOrCacheFlag(name, value); 360 } 361 362 // TODO(b/303901926): add unit test 363 /** 364 * Sets the string array flag with the given value , using the {@code separator} to flatten it. 365 * 366 * <p><b>Note:</b> in most cases, it's clearer to use the {@link SetLogcatTag} annotation 367 * instead. 368 */ setFlag(String name, String[] value, String separator)369 public final T setFlag(String name, String[] value, String separator) { 370 if (value == null || value.length == 0) { 371 throw new IllegalArgumentException("no values (name=" + name + ")"); 372 } 373 if (value.length == 1) { 374 return setFlag(name, value[0]); 375 } 376 377 // TODO(b/303901926): use some existing helper / utility to flatten it - or a stream like 378 // list.stream().map(Object::toString).collect(Collectors.joining(delimiter) - once it's 379 // unit tested 380 StringBuilder flattenedValue = new StringBuilder().append(value[0]); 381 for (int i = 1; i < value.length; i++) { 382 String nextValue = value[i]; 383 if (i < value.length) { 384 flattenedValue.append(separator); 385 } 386 flattenedValue.append(nextValue); 387 } 388 return setFlag(new NameValuePair(name, flattenedValue.toString(), separator)); 389 } 390 391 /** 392 * Sets a {@code logcat} tag. 393 * 394 * <p><b>Note: </b> it's clearer to use the {@link SetLogcatTag} annotation instead. 395 */ setLogcatTag(String tag, LogLevel level)396 public final T setLogcatTag(String tag, LogLevel level) { 397 setOrCacheLogtagSystemProperty(tag, level.name()); 398 return getThis(); 399 } 400 401 // TODO(b/331781012): add all of them 402 // TODO(b/331781012): create @SetInfraLogcatTags as well 403 /** Sets the {@code logcat} tags for the (shared) infra classes. */ setInfraLogcatTags()404 public final T setInfraLogcatTags() { 405 // TODO(b/331781012): create a String[] constants somewhere and iterate over it 406 setLogcatTag(LOG_TAG, LogLevel.VERBOSE); 407 return getThis(); 408 } 409 410 /** Gets the value of the given flag. */ 411 @Nullable getFlag(String flag)412 public final String getFlag(String flag) { 413 return mDeviceConfig.get(flag); 414 } 415 416 // TODO(295007931): abstract SDK-related methods in a new SdkLevelHelper and reuse them on 417 // SdkLevelSupportRule 418 /** Gets the device's SDK level. */ getDeviceSdk()419 protected abstract int getDeviceSdk(); 420 isAtLeastR()421 protected boolean isAtLeastR() { 422 return getDeviceSdk() >= 30; 423 } 424 isAtLeastS()425 protected boolean isAtLeastS() { 426 return getDeviceSdk() >= 31; 427 } 428 isAtLeastT()429 protected boolean isAtLeastT() { 430 return getDeviceSdk() > 32; 431 } 432 433 // Helper to get a reference to this object, taking care of the generic casting. 434 @SuppressWarnings("unchecked") getThis()435 protected final T getThis() { 436 return (T) this; 437 } 438 439 // Set the annotated flags with the specified value for a particular test method. 440 // NOTE: when adding an annotation here, you also need to add it on isFlagAnnotationPresent() setAnnotatedFlags(Description description)441 private void setAnnotatedFlags(Description description) { 442 List<Annotation> annotations = getAllFlagAnnotations(description); 443 444 // Apply the annotations in the reverse order. First apply from the super classes, test 445 // class and then test method. If same annotated flag is present in class and test 446 // method, test method takes higher priority. 447 // NOTE: add annotations sorted by "most likely usage" and "groups" 448 for (int i = annotations.size() - 1; i >= 0; i--) { 449 Annotation annotation = annotations.get(i); 450 451 // Boolean 452 if (annotation instanceof SetFlagEnabled) { 453 setAnnotatedFlag((SetFlagEnabled) annotation); 454 } else if (annotation instanceof SetFlagsEnabled) { 455 setAnnotatedFlag((SetFlagsEnabled) annotation); 456 } else if (annotation instanceof SetFlagDisabled) { 457 setAnnotatedFlag((SetFlagDisabled) annotation); 458 } else if (annotation instanceof SetFlagsDisabled) { 459 setAnnotatedFlag((SetFlagsDisabled) annotation); 460 } else if (annotation instanceof SetFlagTrue) { 461 setAnnotatedFlag((SetFlagTrue) annotation); 462 } else if (annotation instanceof SetFlagsTrue) { 463 setAnnotatedFlag((SetFlagsTrue) annotation); 464 } else if (annotation instanceof SetFlagFalse) { 465 setAnnotatedFlag((SetFlagFalse) annotation); 466 } else if (annotation instanceof SetFlagsFalse) { 467 setAnnotatedFlag((SetFlagsFalse) annotation); 468 469 // Numbers 470 } else if (annotation instanceof SetIntegerFlag) { 471 setAnnotatedFlag((SetIntegerFlag) annotation); 472 } else if (annotation instanceof SetIntegerFlags) { 473 setAnnotatedFlag((SetIntegerFlags) annotation); 474 } else if (annotation instanceof SetLongFlag) { 475 setAnnotatedFlag((SetLongFlag) annotation); 476 } else if (annotation instanceof SetLongFlags) { 477 setAnnotatedFlag((SetLongFlags) annotation); 478 } else if (annotation instanceof SetFloatFlag) { 479 setAnnotatedFlag((SetFloatFlag) annotation); 480 } else if (annotation instanceof SetFloatFlags) { 481 setAnnotatedFlag((SetFloatFlags) annotation); 482 } else if (annotation instanceof SetDoubleFlag) { 483 setAnnotatedFlag((SetDoubleFlag) annotation); 484 } else if (annotation instanceof SetDoubleFlags) { 485 setAnnotatedFlag((SetDoubleFlags) annotation); 486 487 // String 488 } else if (annotation instanceof SetStringFlag) { 489 setAnnotatedFlag((SetStringFlag) annotation); 490 } else if (annotation instanceof SetStringFlags) { 491 setAnnotatedFlag((SetStringFlags) annotation); 492 } else if (annotation instanceof SetStringArrayFlag) { 493 setAnnotatedFlag((SetStringArrayFlag) annotation); 494 } else if (annotation instanceof SetStringArrayFlags) { 495 setAnnotatedFlag((SetStringArrayFlags) annotation); 496 497 // Debug flags 498 } else if (annotation instanceof EnableDebugFlag) { 499 setAnnotatedFlag((EnableDebugFlag) annotation); 500 } else if (annotation instanceof EnableDebugFlags) { 501 setAnnotatedFlag((EnableDebugFlags) annotation); 502 } else if (annotation instanceof DisableDebugFlag) { 503 setAnnotatedFlag((DisableDebugFlag) annotation); 504 } else if (annotation instanceof DisableDebugFlags) { 505 setAnnotatedFlag((DisableDebugFlags) annotation); 506 } else if (annotation instanceof SetLongDebugFlag) { 507 setAnnotatedFlag((SetLongDebugFlag) annotation); 508 } else if (annotation instanceof SetLongDebugFlags) { 509 setAnnotatedFlag((SetLongDebugFlags) annotation); 510 511 // Logcat flags 512 } else if (annotation instanceof SetLogcatTag) { 513 setAnnotatedFlag((SetLogcatTag) annotation); 514 } else if (annotation instanceof SetLogcatTags) { 515 setAnnotatedFlag((SetLogcatTags) annotation); 516 } else { 517 processAnnotation(description, annotation); 518 } 519 } 520 } 521 setOrCacheFlag(String name, String value)522 private T setOrCacheFlag(String name, String value) { 523 return setOrCacheFlag(name, value, /* separator= */ null); 524 } 525 526 // TODO(b/294423183): need to add unit test for setters that call this setOrCacheFlag(String name, String value, @Nullable String separator)527 protected final T setOrCacheFlag(String name, String value, @Nullable String separator) { 528 NameValuePair flag = new NameValuePair(name, value, separator); 529 if (!mIsRunning) { 530 if (isFlagManagedByRunner(name)) { 531 return getThis(); 532 } 533 cacheCommand(new SetFlagCommand(flag)); 534 return getThis(); 535 } 536 return setFlag(flag); 537 } 538 539 // TODO(b/295321663): need to provide a more elegant way to integrate it with the custom runners isFlagManagedByRunner(String flag)540 protected boolean isFlagManagedByRunner(String flag) { 541 return false; 542 } 543 setFlag(NameValuePair flag)544 private T setFlag(NameValuePair flag) { 545 mLog.d("Setting flag: %s", flag); 546 if (flag.separator == null) { 547 mDeviceConfig.set(flag.name, flag.value); 548 } else { 549 mDeviceConfig.setWithSeparator(flag.name, flag.value, flag.separator); 550 } 551 mChangedFlags.add(flag.name); 552 return getThis(); 553 } 554 resetFlags(String testName)555 private void resetFlags(String testName) { 556 mLog.d("Resetting flags after %s", testName); 557 mDeviceConfig.reset(); 558 } 559 560 /** Sets the value of the given {@link com.android.adservices.service.DebugFlag}. */ setDebugFlag(String name, boolean value)561 public final T setDebugFlag(String name, boolean value) { 562 return setDebugFlag(name, Boolean.toString(value)); 563 } 564 setOrCacheLogtagSystemProperty(String name, String value)565 private T setOrCacheLogtagSystemProperty(String name, String value) { 566 return setOrCacheSystemProperty(SYSTEM_PROPERTY_FOR_LOGCAT_TAGS_PREFIX + name, value); 567 } 568 setDebugFlag(String name, String value)569 private T setDebugFlag(String name, String value) { 570 return setOrCacheSystemProperty(mDebugFlagPrefix + name, value); 571 } 572 setOrCacheSystemProperty(String name, String value)573 private T setOrCacheSystemProperty(String name, String value) { 574 NameValuePair systemProperty = new NameValuePair(name, value); 575 if (!mIsRunning) { 576 cacheCommand(new SetSystemPropertyCommand(systemProperty)); 577 return getThis(); 578 } 579 return setSystemProperty(systemProperty); 580 } 581 setSystemProperty(NameValuePair systemProperty)582 private T setSystemProperty(NameValuePair systemProperty) { 583 mLog.d("Setting system property: %s", systemProperty); 584 mSystemProperties.set(systemProperty.name, systemProperty.value); 585 mChangedSystemProperties.add(systemProperty.name); 586 return getThis(); 587 } 588 resetSystemProperties(String testName)589 private void resetSystemProperties(String testName) { 590 mLog.d("Resetting SystemProperties after %s", testName); 591 mSystemProperties.reset(); 592 } 593 runOrCache(String description, Runnable r)594 protected T runOrCache(String description, Runnable r) { 595 RunnableCommand command = new RunnableCommand(description, r); 596 if (!mIsRunning) { 597 cacheCommand(command); 598 return getThis(); 599 } 600 command.execute(); 601 return getThis(); 602 } 603 cacheCommand(Command command)604 private void cacheCommand(Command command) { 605 if (mIsRunning) { 606 throw new IllegalStateException( 607 "Cannot cache " + command + " as test is already running"); 608 } 609 mLog.v("Caching %s as test is not running yet", command); 610 mInitialCommands.add(command); 611 } 612 runCommand(String description, Runnable runnable)613 private void runCommand(String description, Runnable runnable) { 614 mLog.v("Running runnable for %s", description); 615 runnable.run(); 616 } 617 618 // TODO(b/294423183): make private once not used by subclass for legacy methods runInitialCommands(String testName)619 protected final void runInitialCommands(String testName) { 620 if (mInitialCommands.isEmpty()) { 621 mLog.d("Not executing any command before %s", testName); 622 } else { 623 int size = mInitialCommands.size(); 624 mLog.d("Executing %d commands before %s", size, testName); 625 for (int i = 0; i < mInitialCommands.size(); i++) { 626 Command command = mInitialCommands.get(i); 627 mLog.v("\t%d: %s", i, command); 628 command.execute(); 629 } 630 } 631 } 632 633 // TODO(b/294423183): improve logic used here and on setAnnotatedFlags() 634 // NOTE: when adding an annotation here, you also need to add it on setAnnotatedFlags() isFlagAnnotationPresent(Annotation annotation)635 private boolean isFlagAnnotationPresent(Annotation annotation) { 636 // NOTE: add annotations sorted by "most likely usage" and "groups" 637 boolean processedHere = 638 // Boolean 639 (annotation instanceof SetFlagEnabled) 640 || (annotation instanceof SetFlagsEnabled) 641 || (annotation instanceof SetFlagDisabled) 642 || (annotation instanceof SetFlagsDisabled) 643 || (annotation instanceof SetFlagTrue) 644 || (annotation instanceof SetFlagsTrue) 645 || (annotation instanceof SetFlagFalse) 646 || (annotation instanceof SetFlagsFalse) 647 // Numbers 648 || (annotation instanceof SetIntegerFlag) 649 || (annotation instanceof SetIntegerFlags) 650 || (annotation instanceof SetLongFlag) 651 || (annotation instanceof SetLongFlags) 652 || (annotation instanceof SetFloatFlag) 653 || (annotation instanceof SetFloatFlags) 654 || (annotation instanceof SetDoubleFlag) 655 || (annotation instanceof SetDoubleFlags) 656 // Strings 657 || (annotation instanceof SetStringFlag) 658 || (annotation instanceof SetStringFlags) 659 || (annotation instanceof SetStringArrayFlag) 660 || (annotation instanceof SetStringArrayFlags) 661 // Debug flags 662 || (annotation instanceof DisableDebugFlag) 663 || (annotation instanceof DisableDebugFlags) 664 || (annotation instanceof EnableDebugFlag) 665 || (annotation instanceof EnableDebugFlags) 666 || (annotation instanceof SetLongDebugFlag) 667 || (annotation instanceof SetLongDebugFlags) 668 // Logcat flags 669 || (annotation instanceof SetLogcatTag) 670 || (annotation instanceof SetLogcatTags); 671 return processedHere || isAnnotationSupported(annotation); 672 } 673 674 /** 675 * By default returns {@code false}, but subclasses can override to support custom annotations. 676 * 677 * <p>Note: when overridden, {@link #processAnnotation(Description, Annotation)} should be 678 * overridden as well. 679 */ isAnnotationSupported(Annotation annotation)680 protected boolean isAnnotationSupported(Annotation annotation) { 681 return false; 682 } 683 684 /** 685 * Called to process custom annotations present in the test (when {@link 686 * #isAnnotationSupported(Annotation)} returns {@code true} for that annotation type). 687 */ processAnnotation(Description description, Annotation annotation)688 protected void processAnnotation(Description description, Annotation annotation) { 689 throw new IllegalStateException( 690 "Rule subclass (" 691 + this.getClass().getName() 692 + ") supports annotation " 693 + annotation.annotationType().getName() 694 + ", but doesn't override processAnnotation(), which was called with " 695 + annotation); 696 } 697 getAllFlagAnnotations(Description description)698 private List<Annotation> getAllFlagAnnotations(Description description) { 699 // TODO(b/318893752): Move this to a helper function to scan test method, class and 700 // superclasses for annotations. 701 List<Annotation> result = new ArrayList<>(); 702 for (Annotation testMethodAnnotation : description.getAnnotations()) { 703 if (isFlagAnnotationPresent(testMethodAnnotation)) { 704 result.add(testMethodAnnotation); 705 } else { 706 mLog.v("Ignoring annotation %s", testMethodAnnotation); 707 } 708 } 709 710 // Get all the flag based annotations from test class and super classes 711 Class<?> clazz = description.getTestClass(); 712 do { 713 Annotation[] classAnnotations = clazz.getAnnotations(); 714 if (classAnnotations != null) { 715 for (Annotation annotation : classAnnotations) { 716 if (isFlagAnnotationPresent(annotation)) { 717 result.add(annotation); 718 } 719 } 720 } 721 clazz = clazz.getSuperclass(); 722 } while (clazz != null); 723 724 return result; 725 } 726 727 // Single SetFlagEnabled annotations present setAnnotatedFlag(SetFlagEnabled annotation)728 private void setAnnotatedFlag(SetFlagEnabled annotation) { 729 setFlag(annotation.value(), true); 730 } 731 732 // Multiple SetFlagEnabled annotations present setAnnotatedFlag(SetFlagsEnabled repeatedAnnotation)733 private void setAnnotatedFlag(SetFlagsEnabled repeatedAnnotation) { 734 for (SetFlagEnabled annotation : repeatedAnnotation.value()) { 735 setAnnotatedFlag(annotation); 736 } 737 } 738 739 // Single SetFlagDisabled annotations present setAnnotatedFlag(SetFlagDisabled annotation)740 private void setAnnotatedFlag(SetFlagDisabled annotation) { 741 setFlag(annotation.value(), false); 742 } 743 744 // Multiple SetFlagDisabled annotations present setAnnotatedFlag(SetFlagsDisabled repeatedAnnotation)745 private void setAnnotatedFlag(SetFlagsDisabled repeatedAnnotation) { 746 for (SetFlagDisabled annotation : repeatedAnnotation.value()) { 747 setAnnotatedFlag(annotation); 748 } 749 } 750 751 // Single SetFlagTrue annotations present setAnnotatedFlag(SetFlagTrue annotation)752 private void setAnnotatedFlag(SetFlagTrue annotation) { 753 setFlag(annotation.value(), true); 754 } 755 756 // Multiple SetFlagTrue annotations present setAnnotatedFlag(SetFlagsTrue repeatedAnnotation)757 private void setAnnotatedFlag(SetFlagsTrue repeatedAnnotation) { 758 for (SetFlagTrue annotation : repeatedAnnotation.value()) { 759 setAnnotatedFlag(annotation); 760 } 761 } 762 763 // Single SetFlagFalse annotations present setAnnotatedFlag(SetFlagFalse annotation)764 private void setAnnotatedFlag(SetFlagFalse annotation) { 765 setFlag(annotation.value(), false); 766 } 767 768 // Multiple SetFlagFalse annotations present setAnnotatedFlag(SetFlagsFalse repeatedAnnotation)769 private void setAnnotatedFlag(SetFlagsFalse repeatedAnnotation) { 770 for (SetFlagFalse annotation : repeatedAnnotation.value()) { 771 setAnnotatedFlag(annotation); 772 } 773 } 774 775 // Single SetIntegerFlag annotations present setAnnotatedFlag(SetIntegerFlag annotation)776 private void setAnnotatedFlag(SetIntegerFlag annotation) { 777 setFlag(annotation.name(), annotation.value()); 778 } 779 780 // Multiple SetIntegerFlag annotations present setAnnotatedFlag(SetIntegerFlags repeatedAnnotation)781 private void setAnnotatedFlag(SetIntegerFlags repeatedAnnotation) { 782 for (SetIntegerFlag annotation : repeatedAnnotation.value()) { 783 setAnnotatedFlag(annotation); 784 } 785 } 786 787 // Single SetLongFlag annotations present setAnnotatedFlag(SetLongFlag annotation)788 private void setAnnotatedFlag(SetLongFlag annotation) { 789 setFlag(annotation.name(), annotation.value()); 790 } 791 792 // Multiple SetLongFlag annotations present setAnnotatedFlag(SetLongFlags repeatedAnnotation)793 private void setAnnotatedFlag(SetLongFlags repeatedAnnotation) { 794 for (SetLongFlag annotation : repeatedAnnotation.value()) { 795 setAnnotatedFlag(annotation); 796 } 797 } 798 799 // Single SetLongFlag annotations present setAnnotatedFlag(SetFloatFlag annotation)800 private void setAnnotatedFlag(SetFloatFlag annotation) { 801 setFlag(annotation.name(), annotation.value()); 802 } 803 804 // Multiple SetLongFlag annotations present setAnnotatedFlag(SetFloatFlags repeatedAnnotation)805 private void setAnnotatedFlag(SetFloatFlags repeatedAnnotation) { 806 for (SetFloatFlag annotation : repeatedAnnotation.value()) { 807 setAnnotatedFlag(annotation); 808 } 809 } 810 811 // Single SetDoubleFlag annotations present setAnnotatedFlag(SetDoubleFlag annotation)812 private void setAnnotatedFlag(SetDoubleFlag annotation) { 813 setFlag(annotation.name(), annotation.value()); 814 } 815 816 // Multiple SetDoubleFlag annotations present setAnnotatedFlag(SetDoubleFlags repeatedAnnotation)817 private void setAnnotatedFlag(SetDoubleFlags repeatedAnnotation) { 818 for (SetDoubleFlag annotation : repeatedAnnotation.value()) { 819 setAnnotatedFlag(annotation); 820 } 821 } 822 823 // Single SetStringFlag annotations present setAnnotatedFlag(SetStringFlag annotation)824 private void setAnnotatedFlag(SetStringFlag annotation) { 825 setFlag(annotation.name(), annotation.value()); 826 } 827 828 // Multiple SetStringFlag annotations present setAnnotatedFlag(SetStringFlags repeatedAnnotation)829 private void setAnnotatedFlag(SetStringFlags repeatedAnnotation) { 830 for (SetStringFlag annotation : repeatedAnnotation.value()) { 831 setAnnotatedFlag(annotation); 832 } 833 } 834 835 // Single SetStringArrayFlag annotations present setAnnotatedFlag(SetStringArrayFlag annotation)836 private void setAnnotatedFlag(SetStringArrayFlag annotation) { 837 setFlag(annotation.name(), annotation.value(), annotation.separator()); 838 } 839 840 // Multiple SetStringArrayFlag annotations present setAnnotatedFlag(SetStringArrayFlags repeatedAnnotation)841 private void setAnnotatedFlag(SetStringArrayFlags repeatedAnnotation) { 842 for (SetStringArrayFlag annotation : repeatedAnnotation.value()) { 843 setAnnotatedFlag(annotation); 844 } 845 } 846 847 // Single EnableDebugFlag annotations present setAnnotatedFlag(EnableDebugFlag annotation)848 private void setAnnotatedFlag(EnableDebugFlag annotation) { 849 setDebugFlag(annotation.value(), true); 850 } 851 852 // Multiple EnableDebugFlag annotations present setAnnotatedFlag(EnableDebugFlags repeatedAnnotation)853 private void setAnnotatedFlag(EnableDebugFlags repeatedAnnotation) { 854 for (EnableDebugFlag annotation : repeatedAnnotation.value()) { 855 setAnnotatedFlag(annotation); 856 } 857 } 858 859 // Single DisableDebugFlag annotations present setAnnotatedFlag(DisableDebugFlag annotation)860 private void setAnnotatedFlag(DisableDebugFlag annotation) { 861 setDebugFlag(annotation.value(), false); 862 } 863 864 // Multiple DisableDebugFlag annotations present setAnnotatedFlag(DisableDebugFlags repeatedAnnotation)865 private void setAnnotatedFlag(DisableDebugFlags repeatedAnnotation) { 866 for (DisableDebugFlag annotation : repeatedAnnotation.value()) { 867 setAnnotatedFlag(annotation); 868 } 869 } 870 871 // Single SetLongDebugFlag annotations present setAnnotatedFlag(SetLongDebugFlag annotation)872 private void setAnnotatedFlag(SetLongDebugFlag annotation) { 873 setDebugFlag(annotation.name(), Long.toString(annotation.value())); 874 } 875 876 // Multiple SetLongDebugFlag annotations present setAnnotatedFlag(SetLongDebugFlags repeatedAnnotation)877 private void setAnnotatedFlag(SetLongDebugFlags repeatedAnnotation) { 878 for (SetLongDebugFlag annotation : repeatedAnnotation.value()) { 879 setAnnotatedFlag(annotation); 880 } 881 } 882 883 // Single SetLogcatTag annotations present setAnnotatedFlag(SetLogcatTag annotation)884 private void setAnnotatedFlag(SetLogcatTag annotation) { 885 setLogcatTag(annotation.tag(), annotation.level()); 886 } 887 888 // Multiple SetLogcatTag annotations present setAnnotatedFlag(SetLogcatTags repeatedAnnotation)889 private void setAnnotatedFlag(SetLogcatTags repeatedAnnotation) { 890 for (SetLogcatTag annotation : repeatedAnnotation.value()) { 891 setAnnotatedFlag(annotation); 892 } 893 } 894 895 @SuppressWarnings("ClassCanBeStatic") // Subclasses reference enclosing class 896 private abstract class Command { 897 protected final String mDescription; 898 Command(String description)899 Command(String description) { 900 mDescription = description; 901 } 902 execute()903 abstract void execute(); 904 905 @Override toString()906 public final String toString() { 907 return mDescription; 908 } 909 } 910 911 private final class RunnableCommand extends Command { 912 private final Runnable mRunnable; 913 RunnableCommand(String description, Runnable runnable)914 RunnableCommand(String description, Runnable runnable) { 915 super(description); 916 mRunnable = runnable; 917 } 918 919 @Override execute()920 void execute() { 921 runCommand(mDescription, mRunnable); 922 } 923 } 924 925 private abstract class SetFlagOrSystemPropertyCommand extends Command { 926 protected final NameValuePair mFlagOrSystemProperty; 927 SetFlagOrSystemPropertyCommand(String description, NameValuePair flagOrSystemProperty)928 SetFlagOrSystemPropertyCommand(String description, NameValuePair flagOrSystemProperty) { 929 super(description + "(" + flagOrSystemProperty + ")"); 930 mFlagOrSystemProperty = flagOrSystemProperty; 931 } 932 } 933 934 private final class SetFlagCommand extends SetFlagOrSystemPropertyCommand { SetFlagCommand(NameValuePair flag)935 SetFlagCommand(NameValuePair flag) { 936 super("SetFlag", flag); 937 } 938 939 @Override execute()940 void execute() { 941 setFlag(mFlagOrSystemProperty); 942 } 943 } 944 945 private final class SetSystemPropertyCommand extends SetFlagOrSystemPropertyCommand { SetSystemPropertyCommand(NameValuePair flag)946 SetSystemPropertyCommand(NameValuePair flag) { 947 super("SetSystemProperty", flag); 948 } 949 950 @Override execute()951 void execute() { 952 setSystemProperty(mFlagOrSystemProperty); 953 } 954 } 955 } 956