1 /* 2 * Copyright (C) 2019 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.deviceconfig.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNull; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.fail; 23 import static org.junit.Assume.assumeTrue; 24 25 import android.content.Context; 26 import android.os.SystemClock; 27 import android.os.UserHandle; 28 import android.provider.DeviceConfig; 29 import android.provider.DeviceConfig.OnPropertiesChangedListener; 30 import android.provider.DeviceConfig.Properties; 31 32 import androidx.test.InstrumentationRegistry; 33 import androidx.test.runner.AndroidJUnit4; 34 35 import com.android.modules.utils.build.SdkLevel; 36 37 import org.junit.After; 38 import org.junit.AfterClass; 39 import org.junit.Before; 40 import org.junit.BeforeClass; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.HashMap; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.concurrent.CountDownLatch; 50 import java.util.concurrent.Executor; 51 import java.util.concurrent.Executors; 52 import java.util.concurrent.TimeUnit; 53 54 @RunWith(AndroidJUnit4.class) 55 public final class DeviceConfigApiTests { 56 private static final String NAMESPACE1 = "namespace1"; 57 private static final String NAMESPACE2 = "namespace2"; 58 private static final String NAMESPACE3 = "namespace3"; 59 private static final String NAMESPACE4 = "namespace4"; 60 private static final String EMPTY_NAMESPACE = "empty_namespace"; 61 private static final String KEY1 = "key1"; 62 private static final String KEY2 = "key2"; 63 private static final String KEY3 = "key3"; 64 private static final String KEY4 = "key4"; 65 private static final String VALUE1 = "value1"; 66 private static final String VALUE2 = "value2"; 67 private static final String VALUE3 = "value3"; 68 private static final String VALUE4 = "value4"; 69 private static final String DEFAULT_VALUE = "default_value"; 70 71 private static final String KEY_NON_EXISTING = "key_non_existing"; 72 73 private static final boolean DEFAULT_BOOLEAN_TRUE = true; 74 private static final boolean DEFAULT_BOOLEAN_FALSE = false; 75 private static final boolean BOOLEAN_TRUE = true; 76 private static final boolean BOOLEAN_FALSE = false; 77 private static final String INVALID_BOOLEAN = "TR_UE"; 78 79 private static final int DEFAULT_INT = 999; 80 private static final int VALID_INT = 123; 81 private static final String INVALID_INT = "12E"; 82 83 private static final long DEFAULT_LONG = 123456; 84 private static final long VALID_LONG = 278724287; 85 private static final String INVALID_LONG = "23232R42"; 86 87 private static final float DEFAULT_FLOAT = 123.456f; 88 private static final float VALID_FLOAT = 456.789f; 89 private static final String INVALID_FLOAT = "34343et"; 90 91 private static final int RESET_MODE_PACKAGE_DEFAULTS = 1; 92 private static final int SYNC_DISABLED_MODE_NONE = 0; 93 94 private static final long OPERATION_TIMEOUT_MS = 5000; 95 96 private static final Context CONTEXT = InstrumentationRegistry.getContext(); 97 98 private static final Executor EXECUTOR = CONTEXT.getMainExecutor(); 99 100 101 private static final long WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS = 2000; // 2 sec 102 private final Object mLock = new Object(); 103 104 105 private static final String WRITE_DEVICE_CONFIG_PERMISSION = 106 "android.permission.WRITE_DEVICE_CONFIG"; 107 108 private static final String READ_DEVICE_CONFIG_PERMISSION = 109 "android.permission.READ_DEVICE_CONFIG"; 110 111 private static final String MONITOR_DEVICE_CONFIG_ACCESS = 112 "android.permission.MONITOR_DEVICE_CONFIG_ACCESS"; 113 114 // String used to skip tests if not support. 115 // TODO: ideally it would be simpler to just use assumeTrue() in the @BeforeClass method, but 116 // then the test would crash - it might be an issue on atest / AndroidJUnit4 117 private static String sUnsupportedReason; 118 119 private int mInitialSyncDisabledMode; 120 121 /** 122 * Get necessary permissions to access and modify properties through DeviceConfig API. 123 */ 124 @BeforeClass setUp()125 public static void setUp() throws Exception { 126 assumeTrue(SdkLevel.isAtLeastU()); 127 if (CONTEXT.getUserId() != UserHandle.USER_SYSTEM 128 && CONTEXT.getPackageManager().isInstantApp()) { 129 sUnsupportedReason = "cannot run test as instant app on secondary user " 130 + CONTEXT.getUserId(); 131 return; 132 } 133 134 InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 135 WRITE_DEVICE_CONFIG_PERMISSION, READ_DEVICE_CONFIG_PERMISSION, 136 MONITOR_DEVICE_CONFIG_ACCESS); 137 } 138 139 @Before assumeSupported()140 public void assumeSupported() { 141 assumeTrue(sUnsupportedReason, isSupported()); 142 } 143 144 @Before setUpSyncDisabledMode()145 public void setUpSyncDisabledMode() { 146 mInitialSyncDisabledMode = DeviceConfig.getSyncDisabledMode(); 147 DeviceConfig.setSyncDisabledMode(SYNC_DISABLED_MODE_NONE); 148 } 149 150 /** 151 * Nullify properties in DeviceConfig API after completion of every test. 152 */ 153 @After cleanUp()154 public void cleanUp() throws Exception { 155 if (!isSupported()) return; 156 157 // first wait to make sure callbacks for SetProperties/SetProperty 158 // invoked in the test methods got emitted. So that the callbacks 159 // won't interfere with setPropertiesAndAssertSuccessfulChange invoked 160 // in nullifyProperty. 161 if (SdkLevel.isAtLeastV()) { 162 DeviceConfig.clearAllLocalOverrides(); 163 } 164 TimeUnit.MILLISECONDS.sleep(WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS); 165 nullifyProperty(NAMESPACE1, KEY1); 166 nullifyProperty(NAMESPACE2, KEY1); 167 nullifyProperty(NAMESPACE1, KEY2); 168 nullifyProperty(NAMESPACE2, KEY2); 169 nullifyProperty(NAMESPACE3, KEY3); 170 nullifyProperty(NAMESPACE4, KEY3); 171 nullifyProperty(NAMESPACE3, KEY4); 172 nullifyProperty(NAMESPACE4, KEY4); 173 DeviceConfig.setSyncDisabledMode(mInitialSyncDisabledMode); 174 } 175 176 /** 177 * Delete properties in DeviceConfig API after completion of all tests and drop shell 178 * permissions. 179 */ 180 @AfterClass cleanUpAfterAllTests()181 public static void cleanUpAfterAllTests() { 182 if (!isSupported()) return; 183 184 deletePropertyThrowShell(NAMESPACE1, KEY1); 185 deletePropertyThrowShell(NAMESPACE2, KEY1); 186 deletePropertyThrowShell(NAMESPACE1, KEY2); 187 deletePropertyThrowShell(NAMESPACE2, KEY2); 188 InstrumentationRegistry.getInstrumentation().getUiAutomation() 189 .dropShellPermissionIdentity(); 190 } 191 192 @Test testPropertiesIncludedInGetAllProperties()193 public void testPropertiesIncludedInGetAllProperties() { 194 if (!SdkLevel.isAtLeastV()) { 195 return; 196 } 197 198 DeviceConfig.setProperty(NAMESPACE3, KEY3, VALUE3, false); 199 DeviceConfig.setProperty(NAMESPACE4, KEY4, VALUE4, false); 200 201 boolean containsNamespace3 = false; 202 boolean containsNamespace4 = false; 203 for (Properties properties : DeviceConfig.getAllProperties()) { 204 System.out.println(properties); 205 boolean hasNamespace3 = properties.getNamespace().equals(NAMESPACE3); 206 boolean hasValue3 = VALUE3.equals(properties.getString(KEY3, null)); 207 if (hasNamespace3 && hasValue3) { 208 containsNamespace3 = true; 209 assertEquals(VALUE3, properties.getString(KEY3, null)); 210 } 211 212 boolean hasNamespace4 = properties.getNamespace().equals(NAMESPACE4); 213 boolean hasValue4 = VALUE4.equals(properties.getString(KEY4, null)); 214 if (hasNamespace4 && hasValue4) { 215 containsNamespace4 = true; 216 } 217 } 218 219 assertTrue(containsNamespace3); 220 assertTrue(containsNamespace4); 221 } 222 223 /** 224 * Test that creating a sticky local override for a flag prevents further writes to that flag. 225 */ 226 @Test testAddStickyLocalOverridePreventsWrites()227 public void testAddStickyLocalOverridePreventsWrites() { 228 if (!SdkLevel.isAtLeastV()) { 229 return; 230 } 231 232 DeviceConfig.setLocalOverride(NAMESPACE3, KEY3, VALUE3); 233 234 String key3Value = DeviceConfig.getProperty(NAMESPACE3, KEY3); 235 assertEquals(VALUE3, key3Value); 236 237 DeviceConfig.setProperty(NAMESPACE3, KEY3, VALUE4, /* makeDefault= */ false); 238 key3Value = DeviceConfig.getProperty(NAMESPACE3, KEY3); 239 assertEquals(VALUE3, key3Value); 240 } 241 242 /** 243 * Test that when we locally override a flag, we can still write other flags. 244 */ 245 @Test testAddStickyLocalOverrideDoesNotAffectOtherFlags()246 public void testAddStickyLocalOverrideDoesNotAffectOtherFlags() { 247 if (!SdkLevel.isAtLeastV()) { 248 return; 249 } 250 251 DeviceConfig.setLocalOverride(NAMESPACE3, KEY3, VALUE3); 252 DeviceConfig.setProperty(NAMESPACE3, KEY4, VALUE4, /* makeDefault= */ false); 253 String key4Value = DeviceConfig.getProperty(NAMESPACE3, KEY4); 254 assertEquals(VALUE4, key4Value); 255 } 256 257 /** 258 * Test that when we apply some overrides, they show up in the override list. 259 */ 260 @Test testGetStickyLocalOverrides()261 public void testGetStickyLocalOverrides() { 262 if (!SdkLevel.isAtLeastV()) { 263 return; 264 } 265 266 DeviceConfig.setProperty(NAMESPACE3, KEY3, VALUE4, false); 267 DeviceConfig.setProperty(NAMESPACE3, KEY4, VALUE3, false); 268 DeviceConfig.setLocalOverride(NAMESPACE3, KEY3, VALUE3); 269 DeviceConfig.setLocalOverride(NAMESPACE3, KEY4, VALUE4); 270 271 Map<String, Map<String, String>> expectedOverrides = new HashMap<>(); 272 Map<String, String> expectedInnerMap = new HashMap<>(); 273 expectedInnerMap.put(KEY3, VALUE4); 274 expectedInnerMap.put(KEY4, VALUE3); 275 expectedOverrides.put(NAMESPACE3, expectedInnerMap); 276 277 assertEquals(expectedOverrides, DeviceConfig.getUnderlyingValuesForOverriddenFlags()); 278 } 279 280 /** 281 * Test that when we clear all overrides, the override list is empty. 282 */ 283 @Test testClearStickyLocalOverrides()284 public void testClearStickyLocalOverrides() { 285 if (!SdkLevel.isAtLeastV()) { 286 return; 287 } 288 289 DeviceConfig.setLocalOverride(NAMESPACE4, KEY3, VALUE3); 290 DeviceConfig.setLocalOverride(NAMESPACE4, KEY4, VALUE4); 291 292 DeviceConfig.clearAllLocalOverrides(); 293 294 Map<String, Map<String, String>> overrides = 295 DeviceConfig.getUnderlyingValuesForOverriddenFlags(); 296 assertTrue(overrides.isEmpty()); 297 } 298 299 /** 300 * Test that when we clear a single override, it doesn't appear in the list. 301 */ 302 @Test testClearStickyLocalOverride()303 public void testClearStickyLocalOverride() { 304 if (!SdkLevel.isAtLeastV()) { 305 return; 306 } 307 308 DeviceConfig.setProperty(NAMESPACE3, KEY3, VALUE4, false); 309 DeviceConfig.setProperty(NAMESPACE4, KEY4, VALUE3, false); 310 DeviceConfig.setLocalOverride(NAMESPACE3, KEY3, VALUE3); 311 DeviceConfig.setLocalOverride(NAMESPACE4, KEY4, VALUE4); 312 313 DeviceConfig.clearLocalOverride(NAMESPACE3, KEY3); 314 315 Map<String, Map<String, String>> expectedOverrides = new HashMap<>(); 316 Map<String, String> expectedInnerMap = new HashMap<>(); 317 expectedInnerMap.put(KEY4, VALUE3); 318 expectedOverrides.put(NAMESPACE4, expectedInnerMap); 319 320 assertEquals(expectedOverrides, DeviceConfig.getUnderlyingValuesForOverriddenFlags()); 321 } 322 323 /** 324 * Checks that getting property which does not exist returns null. 325 */ 326 @Test testGetProperty_empty()327 public void testGetProperty_empty() { 328 String result = DeviceConfig.getProperty(EMPTY_NAMESPACE, KEY1); 329 assertNull("Request for non existant flag name in DeviceConfig API should return null " 330 + "while " + result + " was returned", result); 331 } 332 333 /** 334 * Checks that setting and getting property from the same namespace return correct value. 335 */ 336 @Test testSetAndGetProperty_sameNamespace()337 public void testSetAndGetProperty_sameNamespace() { 338 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 339 String result = DeviceConfig.getProperty(NAMESPACE1, KEY1); 340 assertEquals("Value read from DeviceConfig API does not match written value.", VALUE1, 341 result); 342 } 343 344 /** 345 * Checks that setting and getting properties from the same namespace return correct values. 346 */ 347 @Test testSetAndGetProperties_sameNamespace()348 public void testSetAndGetProperties_sameNamespace() throws Exception { 349 Properties properties = new Properties.Builder(NAMESPACE1) 350 .setString(KEY1, VALUE1).setInt(KEY2, VALID_INT).build(); 351 assertEquals(DEFAULT_VALUE, DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE)); 352 assertEquals(DEFAULT_INT, DeviceConfig.getInt(NAMESPACE1, KEY2, DEFAULT_INT)); 353 DeviceConfig.setProperties(properties); 354 355 assertEquals(VALUE1, DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE)); 356 assertEquals(VALID_INT, DeviceConfig.getInt(NAMESPACE1, KEY2, DEFAULT_INT)); 357 } 358 359 /** 360 * Checks that setting a property in one namespace does not set the same property in a different 361 * namespace. 362 */ 363 @Test testSetAndGetProperty_differentNamespace()364 public void testSetAndGetProperty_differentNamespace() { 365 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 366 String result = DeviceConfig.getProperty(NAMESPACE2, KEY1); 367 assertNull("Value for same keys written to different namespaces must not clash", result); 368 } 369 370 /** 371 * Checks that setting properties in one namespace does not set the same properties in a 372 * different namespace. 373 */ 374 @Test testSetAndGetProperties_differentNamespace()375 public void testSetAndGetProperties_differentNamespace() throws Exception { 376 Properties properties = new Properties.Builder(NAMESPACE1) 377 .setString(KEY1, VALUE1).setInt(KEY2, VALID_INT).build(); 378 DeviceConfig.setProperties(properties); 379 380 assertEquals(DEFAULT_VALUE, DeviceConfig.getString(NAMESPACE2, KEY1, DEFAULT_VALUE)); 381 assertEquals(DEFAULT_INT, DeviceConfig.getInt(NAMESPACE2, KEY2, DEFAULT_INT)); 382 } 383 384 /** 385 * Checks that different namespaces can keep different values for the same key. 386 */ 387 @Test testSetAndGetProperty_multipleNamespaces()388 public void testSetAndGetProperty_multipleNamespaces() { 389 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 390 DeviceConfig.setProperty(NAMESPACE2, KEY1, VALUE2, /*makeDefault=*/false); 391 String result = DeviceConfig.getProperty(NAMESPACE1, KEY1); 392 assertEquals("Value read from DeviceConfig API does not match written value.", VALUE1, 393 result); 394 result = DeviceConfig.getProperty(NAMESPACE2, KEY1); 395 assertEquals("Value read from DeviceConfig API does not match written value.", VALUE2, 396 result); 397 } 398 399 /** 400 * Checks that different namespaces can keep different values for the same keys. 401 */ 402 @Test testSetAndGetProperties_multipleNamespaces()403 public void testSetAndGetProperties_multipleNamespaces() throws Exception { 404 int VALID_INT2 = VALID_INT + 2; 405 Properties properties1 = new Properties.Builder(NAMESPACE1) 406 .setString(KEY1, VALUE1).setInt(KEY2, VALID_INT).build(); 407 Properties properties2 = new Properties.Builder(NAMESPACE2) 408 .setString(KEY1, VALUE2).setInt(KEY2, VALID_INT2).build(); 409 DeviceConfig.setProperties(properties1); 410 DeviceConfig.setProperties(properties2); 411 412 assertEquals(VALUE1, DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE)); 413 assertEquals(VALID_INT, DeviceConfig.getInt(NAMESPACE1, KEY2, DEFAULT_INT)); 414 assertEquals(VALUE2, DeviceConfig.getString(NAMESPACE2, KEY1, DEFAULT_VALUE)); 415 assertEquals(VALID_INT2, DeviceConfig.getInt(NAMESPACE2, KEY2, DEFAULT_INT)); 416 } 417 418 /** 419 * Checks that saving value twice keeps the last value. 420 */ 421 @Test testSetAndGetProperty_overrideValue()422 public void testSetAndGetProperty_overrideValue() { 423 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 424 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE2, /*makeDefault=*/false); 425 String result = DeviceConfig.getProperty(NAMESPACE1, KEY1); 426 assertEquals("New value written to the same namespace/key did not override previous" 427 + " value.", VALUE2, result); 428 } 429 430 /** 431 * Checks that saving values twice keeps the last values. 432 */ 433 @Test testSetAndGetProperties_overrideValue()434 public void testSetAndGetProperties_overrideValue() throws Exception { 435 int VALID_INT2 = VALID_INT + 2; 436 Properties properties1 = new Properties.Builder(NAMESPACE1) 437 .setString(KEY1, VALUE1).setInt(KEY2, VALID_INT).build(); 438 Properties properties2 = new Properties.Builder(NAMESPACE1) 439 .setString(KEY1, VALUE2).setInt(KEY2, VALID_INT2).build(); 440 DeviceConfig.setProperties(properties1); 441 DeviceConfig.setProperties(properties2); 442 443 assertEquals(VALUE2, DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE)); 444 assertEquals(VALID_INT2, DeviceConfig.getInt(NAMESPACE1, KEY2, DEFAULT_INT)); 445 } 446 447 /** 448 * Checks that getString() for null property returns default value. 449 */ 450 @Test testGetString_empty()451 public void testGetString_empty() { 452 final String result = DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE); 453 assertEquals("DeviceConfig.getString() must return default value if property is null", 454 DEFAULT_VALUE, result); 455 } 456 457 /** 458 * Checks that getString() for null property returns default value even if it is null. 459 */ 460 @Test testGetString_nullDefault()461 public void testGetString_nullDefault() { 462 final String result = DeviceConfig.getString(NAMESPACE1, KEY1, null); 463 assertEquals("DeviceConfig.getString() must return default value if property is null", 464 null, result); 465 } 466 467 /** 468 * Checks that getString() returns string saved in property. 469 */ 470 @Test testGetString_nonEmpty()471 public void testGetString_nonEmpty() { 472 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 473 474 final String result = DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE); 475 assertEquals("DeviceConfig.getString() must return same value as getProperty() when " + 476 "property is not null", VALUE1, result); 477 } 478 479 /** 480 * Checks that getString() fails with NullPointerException when called with null namespace. 481 */ 482 @Test testGetString_nullNamespace()483 public void testGetString_nullNamespace() { 484 try { 485 DeviceConfig.getString(null, KEY1, DEFAULT_VALUE); 486 fail("DeviceConfig.getString() with null namespace must result in " 487 + "NullPointerException"); 488 } catch (NullPointerException e) { 489 // expected 490 } 491 } 492 493 /** 494 * Checks that getString() fails with NullPointerException when called with null key. 495 */ 496 @Test testGetString_nullName()497 public void testGetString_nullName() { 498 try { 499 DeviceConfig.getString(NAMESPACE1, null, DEFAULT_VALUE); 500 fail("DeviceConfig.getString() with null name must result in NullPointerException"); 501 } catch (NullPointerException e) { 502 // expected 503 } 504 } 505 506 /** 507 * Checks that getBoolean() for null property returns default value. 508 */ 509 @Test testGetBoolean_empty()510 public void testGetBoolean_empty() { 511 final boolean result = DeviceConfig.getBoolean(NAMESPACE1, KEY1, DEFAULT_BOOLEAN_TRUE); 512 assertEquals("DeviceConfig.getBoolean() must return default value if property is null", 513 DEFAULT_BOOLEAN_TRUE, result); 514 } 515 516 /** 517 * Checks that getBoolean() returns boolean representation of string saved in property. 518 */ 519 @Test testGetBoolean_valid()520 public void testGetBoolean_valid() { 521 DeviceConfig.setProperty(NAMESPACE1, KEY1, String.valueOf(BOOLEAN_TRUE), 522 /*makeDefault=*/false); 523 524 final boolean result = DeviceConfig.getBoolean(NAMESPACE1, KEY1, DEFAULT_BOOLEAN_FALSE); 525 assertEquals("DeviceConfig.getString() must return boolean equivalent value of" 526 + " getProperty() when property is not null", BOOLEAN_TRUE, result); 527 } 528 529 /** 530 * Checks that getBoolean() returns false for any invalid property value. 531 */ 532 @Test testGetBoolean_invalid()533 public void testGetBoolean_invalid() { 534 DeviceConfig.setProperty(NAMESPACE1, KEY1, INVALID_BOOLEAN, /*makeDefault=*/false); 535 536 final boolean result = DeviceConfig.getBoolean(NAMESPACE1, KEY1, DEFAULT_BOOLEAN_TRUE); 537 // Anything non-null other than case insensitive "true" parses to false. 538 assertEquals("DeviceConfig.getBoolean() must return boolean equivalent value of" 539 + " getProperty() when property is not null", BOOLEAN_FALSE, result); 540 } 541 542 /** 543 * Checks that getBoolean() fails with NullPointerException when called with null namespace. 544 */ 545 @Test testGetBoolean_nullNamespace()546 public void testGetBoolean_nullNamespace() { 547 try { 548 DeviceConfig.getBoolean(null, KEY1, DEFAULT_BOOLEAN_TRUE); 549 fail("DeviceConfig.getBoolean() with null namespace must result in " 550 + "NullPointerException"); 551 } catch (NullPointerException e) { 552 // expected 553 } 554 } 555 556 /** 557 * Checks that getBoolean() fails with NullPointerException when called with null name. 558 */ 559 @Test testGetBoolean_nullName()560 public void testGetBoolean_nullName() { 561 try { 562 DeviceConfig.getBoolean(NAMESPACE1, null, DEFAULT_BOOLEAN_TRUE); 563 fail("DeviceConfig.getBoolean() with null name must result in NullPointerException"); 564 } catch (NullPointerException e) { 565 // expected 566 } 567 } 568 569 /** 570 * Checks that getInt() for null property returns default value. 571 */ 572 @Test testGetInt_empty()573 public void testGetInt_empty() { 574 final int result = DeviceConfig.getInt(NAMESPACE1, KEY1, DEFAULT_INT); 575 assertEquals("DeviceConfig.getInt() must return default value if property is null", 576 DEFAULT_INT, result); 577 } 578 579 /** 580 * Checks that getInt() returns integer representation of string saved in property. 581 */ 582 @Test testGetInt_valid()583 public void testGetInt_valid() { 584 DeviceConfig.setProperty(NAMESPACE1, KEY1, String.valueOf(VALID_INT), 585 /*makeDefault=*/false); 586 587 final int result = DeviceConfig.getInt(NAMESPACE1, KEY1, DEFAULT_INT); 588 assertEquals("DeviceConfig.getInt() must return integer equivalent value of" 589 + " getProperty() when property is not null", VALID_INT, result); 590 } 591 592 /** 593 * Checks that getInt() returns default value if property is not well-formed integer value. 594 */ 595 @Test testGetInt_invalid()596 public void testGetInt_invalid() { 597 DeviceConfig.setProperty(NAMESPACE1, KEY1, INVALID_INT, /*makeDefault=*/false); 598 599 final int result = DeviceConfig.getInt(NAMESPACE1, KEY1, DEFAULT_INT); 600 // Failure to parse results in using the default value 601 assertEquals("DeviceConfig.getInt() must return integer equivalent value of" 602 + " getProperty() when property is not null", DEFAULT_INT, result); 603 } 604 605 /** 606 * Checks that getInt() fails with NullPointerException when called with null namespace. 607 */ 608 @Test testGetInt_nullNamespace()609 public void testGetInt_nullNamespace() { 610 try { 611 DeviceConfig.getInt(null, KEY1, VALID_INT); 612 fail("DeviceConfig.getInt() with null namespace must result in NullPointerException"); 613 } catch (NullPointerException e) { 614 // expected 615 } 616 } 617 618 /** 619 * Checks that getInt() fails with NullPointerException when called with null name. 620 */ 621 @Test testGetInt_nullName()622 public void testGetInt_nullName() { 623 try { 624 DeviceConfig.getInt(NAMESPACE1, null, VALID_INT); 625 fail("DeviceConfig.getInt() with null name must result in NullPointerException"); 626 } catch (NullPointerException e) { 627 // expected 628 } 629 } 630 631 /** 632 * Checks that getLong() for null property returns default value. 633 */ 634 @Test testGetLong_empty()635 public void testGetLong_empty() { 636 final long result = DeviceConfig.getLong(NAMESPACE1, KEY1, DEFAULT_LONG); 637 assertEquals("DeviceConfig.getLong() must return default value if property is null", 638 DEFAULT_LONG, result); 639 } 640 641 /** 642 * Checks that getLong() returns long representation of string saved in property. 643 */ 644 @Test testGetLong_valid()645 public void testGetLong_valid() { 646 DeviceConfig.setProperty(NAMESPACE1, KEY1, String.valueOf(VALID_LONG), 647 /*makeDefault=*/false); 648 649 final long result = DeviceConfig.getLong(NAMESPACE1, KEY1, DEFAULT_LONG); 650 assertEquals("DeviceConfig.getLong() must return long equivalent value of" 651 + " getProperty() when property is not null", VALID_LONG, result); 652 } 653 654 /** 655 * Checks that getLong() returns default value if property is not well-formed long value. 656 */ 657 @Test testGetLong_invalid()658 public void testGetLong_invalid() { 659 DeviceConfig.setProperty(NAMESPACE1, KEY1, INVALID_LONG, /*makeDefault=*/false); 660 661 final long result = DeviceConfig.getLong(NAMESPACE1, KEY1, DEFAULT_LONG); 662 // Failure to parse results in using the default value 663 assertEquals("DeviceConfig.getLong() must return long equivalent value of" 664 + " getProperty() when property is not null", DEFAULT_LONG, result); 665 } 666 667 /** 668 * Checks that getLong() fails with NullPointerException when called with null namespace. 669 */ 670 @Test testGetLong_nullNamespace()671 public void testGetLong_nullNamespace() { 672 try { 673 DeviceConfig.getLong(null, KEY1, DEFAULT_LONG); 674 fail("DeviceConfig.getLong() with null namespace must result in " 675 + "NullPointerException"); 676 } catch (NullPointerException e) { 677 // expected 678 } 679 } 680 681 /** 682 * Checks that getLong() fails with NullPointerException when called with null name. 683 */ 684 @Test testGetLong_nullName()685 public void testGetLong_nullName() { 686 try { 687 DeviceConfig.getLong(NAMESPACE1, null, 0); 688 fail("DeviceConfig.getLong() with null name must result in NullPointerException"); 689 } catch (NullPointerException e) { 690 // expected 691 } 692 } 693 694 /** 695 * Checks that getFloat() for null property returns default value. 696 */ 697 @Test testGetFloat_empty()698 public void testGetFloat_empty() { 699 final float result = DeviceConfig.getFloat(NAMESPACE1, KEY1, DEFAULT_FLOAT); 700 assertEquals("DeviceConfig.getFloat() must return default value if property is null", 701 DEFAULT_FLOAT, result, 0.0); 702 } 703 704 /** 705 * Checks that getFloat() returns float representation of string saved in property. 706 */ 707 @Test testGetFloat_valid()708 public void testGetFloat_valid() { 709 DeviceConfig.setProperty(NAMESPACE1, KEY1, String.valueOf(VALID_FLOAT), 710 /*makeDefault=*/false); 711 712 final float result = DeviceConfig.getFloat(NAMESPACE1, KEY1, DEFAULT_FLOAT); 713 assertEquals("DeviceConfig.getFloat() must return float equivalent value of" 714 + " getProperty() when property is not null", VALID_FLOAT, result, 0.0); 715 } 716 717 /** 718 * Checks that getFloat() returns default value if property is not well-formed float value. 719 */ 720 @Test testGetFloat_invalid()721 public void testGetFloat_invalid() { 722 DeviceConfig.setProperty(NAMESPACE1, KEY1, INVALID_FLOAT, /*makeDefault=*/false); 723 724 final float result = DeviceConfig.getFloat(NAMESPACE1, KEY1, DEFAULT_FLOAT); 725 // Failure to parse results in using the default value 726 assertEquals("DeviceConfig.getFloat() must return float equivalent value of" 727 + " getProperty() when property is not null", DEFAULT_FLOAT, result, 0.0f); 728 } 729 730 /** 731 * Checks that getFloat() fails with NullPointerException when called with null namespace. 732 */ 733 @Test testGetFloat_nullNamespace()734 public void testGetFloat_nullNamespace() { 735 try { 736 DeviceConfig.getFloat(null, KEY1, DEFAULT_FLOAT); 737 fail("DeviceConfig.getFloat() with null namespace must result in " 738 + "NullPointerException"); 739 } catch (NullPointerException e) { 740 // expected 741 } 742 } 743 744 /** 745 * Checks that getFloat() fails with NullPointerException when called with null name. 746 */ 747 @Test testGetFloat_nullName()748 public void testGetFloat_nullName() { 749 try { 750 DeviceConfig.getFloat(NAMESPACE1, null, DEFAULT_FLOAT); 751 fail("DeviceConfig.getFloat() with null name must result in NullPointerException"); 752 } catch (NullPointerException e) { 753 // expected 754 } 755 } 756 757 /** 758 * Checks that setProperty() fails with NullPointerException when called with null namespace. 759 */ 760 @Test testSetProperty_nullNamespace()761 public void testSetProperty_nullNamespace() { 762 try { 763 DeviceConfig.setProperty(null, KEY1, DEFAULT_VALUE, /*makeDefault=*/false); 764 fail("DeviceConfig.setProperty() with null namespace must result in " 765 + "NullPointerException"); 766 } catch (NullPointerException e) { 767 // expected 768 } 769 } 770 771 /** 772 * Checks that setProperty() fails with NullPointerException when called with null name. 773 */ 774 @Test testSetProperty_nullName()775 public void testSetProperty_nullName() { 776 try { 777 DeviceConfig.setProperty(NAMESPACE1, null, DEFAULT_VALUE, /*makeDefault=*/false); 778 fail("DeviceConfig.setProperty() with null name must result in NullPointerException"); 779 } catch (NullPointerException e) { 780 // expected 781 } 782 } 783 784 /** 785 * Checks that Properties.getString() for null property returns default value. 786 */ 787 @Test testGetPropertiesString_empty()788 public void testGetPropertiesString_empty() { 789 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 790 final Properties properties = 791 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 792 final String result = properties.getString(KEY1, DEFAULT_VALUE); 793 assertEquals("DeviceConfig.Properties.getString() must return default value if property " 794 + "is null", DEFAULT_VALUE, result); 795 } 796 797 /** 798 * Checks that Properties.getString() for null property returns default value even if it is 799 * null. 800 */ 801 @Test testGetPropertiesString_nullDefault()802 public void testGetPropertiesString_nullDefault() { 803 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, DEFAULT_VALUE); 804 final Properties properties = 805 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 806 final String result = properties.getString(KEY1, null); 807 assertEquals("DeviceConfig.Properties.getString() must return default value if property is " 808 + "null", null, result); 809 } 810 811 /** 812 * Checks that Properties.getString() returns string saved in property. 813 */ 814 @Test testGetPropertiesString_nonEmpty()815 public void testGetPropertiesString_nonEmpty() { 816 final Properties properties = 817 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 818 819 final String result = properties.getString(KEY1, DEFAULT_VALUE); 820 assertEquals("DeviceConfig.Properties.getString() must return same value as getProperty() " 821 + "when property is not null", VALUE1, result); 822 } 823 824 /** 825 * Checks that Properties.getBoolean() for null property returns default value. 826 */ 827 @Test testGetPropertiesBoolean_empty()828 public void testGetPropertiesBoolean_empty() { 829 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(BOOLEAN_TRUE)); 830 final Properties properties = 831 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 832 final boolean result = properties.getBoolean(KEY1, DEFAULT_BOOLEAN_TRUE); 833 assertEquals("DeviceConfig.Properties.getBoolean() must return default value if property " 834 + "is null", DEFAULT_BOOLEAN_TRUE, result); 835 } 836 837 /** 838 * Checks that Properties.getBoolean() returns boolean representation of string saved in 839 * property. 840 */ 841 @Test testGetPropertiesBoolean_valid()842 public void testGetPropertiesBoolean_valid() { 843 final Properties properties = setPropertiesAndAssertSuccessfulChange( 844 NAMESPACE1, KEY1, String.valueOf(BOOLEAN_TRUE)); 845 final boolean result = properties.getBoolean(KEY1, DEFAULT_BOOLEAN_FALSE); 846 assertEquals("DeviceConfig.Properties.getString() must return boolean equivalent value of" 847 + " getProperty() when property is not null", BOOLEAN_TRUE, result); 848 } 849 850 /** 851 * Checks that Properties.getBoolean() returns false for any invalid (non parselable) property 852 * value. 853 */ 854 @Test testGetPropertiesBoolean_invalid()855 public void testGetPropertiesBoolean_invalid() { 856 final Properties properties = 857 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, INVALID_BOOLEAN); 858 859 final boolean result = properties.getBoolean(KEY1, DEFAULT_BOOLEAN_TRUE); 860 // Anything non-null other than case insensitive "true" parses to false. 861 assertEquals("DeviceConfig.Properties.getBoolean() must return boolean equivalent value of" 862 + " getProperty() when property is not null", BOOLEAN_FALSE, result); 863 } 864 865 /** 866 * Checks that Properties.getInt() for null property returns default value. 867 */ 868 @Test testGetPropertiesInt_empty()869 public void testGetPropertiesInt_empty() { 870 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_INT)); 871 final Properties properties = 872 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 873 874 final int result = properties.getInt(KEY1, DEFAULT_INT); 875 assertEquals("DeviceConfig.Properties.getInt() must return default value if property is " 876 + "null", DEFAULT_INT, result); 877 } 878 879 /** 880 * Checks that Properties.getInt() returns integer representation of string saved in property. 881 */ 882 @Test testGetPropertiesInt_valid()883 public void testGetPropertiesInt_valid() { 884 final Properties properties = 885 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_INT)); 886 887 final int result = properties.getInt(KEY1, DEFAULT_INT); 888 assertEquals("DeviceConfig.Properties.getInt() must return integer equivalent value of" 889 + " getProperty() when property is not null", VALID_INT, result); 890 } 891 892 /** 893 * Checks that Properties.getInt() returns default value if property is not well-formed integer 894 * value. 895 */ 896 @Test testGetPropertiesInt_invalid()897 public void testGetPropertiesInt_invalid() { 898 final Properties properties = 899 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, INVALID_INT); 900 901 final int result = properties.getInt(KEY1, DEFAULT_INT); 902 // Failure to parse results in using the default value 903 assertEquals("DeviceConfig.Properties.getInt() must return integer equivalent value of" 904 + " getProperty() when property is not null", DEFAULT_INT, result); 905 } 906 907 /** 908 * Checks that Properties.getLong() for null property returns default value. 909 */ 910 @Test testGetPropertiesLong_empty()911 public void testGetPropertiesLong_empty() { 912 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_LONG)); 913 final Properties properties = 914 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 915 916 final long result = properties.getLong(KEY1, DEFAULT_LONG); 917 assertEquals("DeviceConfig.Properties.getLong() must return default value if property is " 918 + "null", DEFAULT_LONG, result); 919 } 920 921 /** 922 * Checks that Properties.getLong() returns long representation of string saved in property. 923 */ 924 @Test testGetPropertiesLong_valid()925 public void testGetPropertiesLong_valid() { 926 final Properties properties = 927 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_LONG)); 928 929 final long result = properties.getLong(KEY1, DEFAULT_LONG); 930 assertEquals("DeviceConfig.Properties.getLong() must return long equivalent value of" 931 + " getProperty() when property is not null", VALID_LONG, result); 932 } 933 934 /** 935 * Checks that Properties.getLong() returns default value if property is not well-formed long 936 * value. 937 */ 938 @Test testGetPropertiesLong_invalid()939 public void testGetPropertiesLong_invalid() { 940 final Properties properties = 941 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, INVALID_LONG); 942 943 final long result = properties.getLong(KEY1, DEFAULT_LONG); 944 // Failure to parse results in using the default value 945 assertEquals("DeviceConfig.Properties.getLong() must return long equivalent value of" 946 + " getProperty() when property is not null", DEFAULT_LONG, result); 947 } 948 949 /** 950 * Checks that Properties.getFloat() for null property returns default value. 951 */ 952 @Test testGetPropertiesFloat_empty()953 public void testGetPropertiesFloat_empty() { 954 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_FLOAT)); 955 final Properties properties = 956 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, null); 957 final float result = properties.getFloat(KEY1, DEFAULT_FLOAT); 958 assertEquals("DeviceConfig.Properties.getFloat() must return default value if property is " 959 + "null", DEFAULT_FLOAT, result, 0.0f); 960 } 961 962 /** 963 * Checks that Properties.getFloat() returns float representation of string saved in property. 964 */ 965 @Test testGetPropertiesFloat_valid()966 public void testGetPropertiesFloat_valid() { 967 final Properties properties = setPropertiesAndAssertSuccessfulChange( 968 NAMESPACE1, KEY1, String.valueOf(VALID_FLOAT)); 969 970 final float result = properties.getFloat(KEY1, DEFAULT_FLOAT); 971 assertEquals("DeviceConfig.Properties.getFloat() must return float equivalent value of" 972 + " getProperty() when property is not null", VALID_FLOAT, result, 0.0f); 973 } 974 975 /** 976 * Checks that Properties.getFloat() returns default value if property is not well-formed float 977 * value. 978 */ 979 @Test testGetPropertiesFloat_invalid()980 public void testGetPropertiesFloat_invalid() { 981 final Properties properties = setPropertiesAndAssertSuccessfulChange( 982 NAMESPACE1, KEY1, INVALID_FLOAT); 983 984 final float result = properties.getFloat(KEY1, DEFAULT_FLOAT); 985 // Failure to parse results in using the default value 986 assertEquals("DeviceConfig.Properties.getFloat() must return float equivalent value of" 987 + " getProperty() when property is not null", DEFAULT_FLOAT, result, 0.0f); 988 } 989 990 @Test testDeleteProperty_nullNamespace()991 public void testDeleteProperty_nullNamespace() { 992 try { 993 DeviceConfig.deleteProperty(null, KEY1); 994 fail("DeviceConfig.deleteProperty() with null namespace must result in " 995 + "NullPointerException"); 996 } catch (NullPointerException e) { 997 // expected 998 } 999 } 1000 1001 @Test testDeleteProperty_nullName()1002 public void testDeleteProperty_nullName() { 1003 try { 1004 DeviceConfig.deleteProperty(NAMESPACE1, null); 1005 fail("DeviceConfig.deleteProperty() with null name must result in " 1006 + "NullPointerException"); 1007 } catch (NullPointerException e) { 1008 // expected 1009 } 1010 } 1011 1012 @Test testDeletePropertyString()1013 public void testDeletePropertyString() { 1014 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 1015 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1016 assertEquals("DeviceConfig.Properties.getString() must return default value if " 1017 + "property is deleted", DEFAULT_VALUE, 1018 DeviceConfig.getProperties(NAMESPACE1, KEY1).getString(KEY1, DEFAULT_VALUE)); 1019 } 1020 1021 @Test testDeletePropertyBoolean()1022 public void testDeletePropertyBoolean() { 1023 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(BOOLEAN_TRUE)); 1024 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1025 assertEquals("DeviceConfig.Properties.getBoolean() must return default value if " 1026 + "property is deleted", BOOLEAN_FALSE, 1027 DeviceConfig.getProperties(NAMESPACE1, KEY1).getBoolean(KEY1, 1028 DEFAULT_BOOLEAN_FALSE)); 1029 } 1030 1031 @Test testDeletePropertyInt()1032 public void testDeletePropertyInt() { 1033 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_INT)); 1034 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1035 assertEquals("DeviceConfig.Properties.getInt() must return default value if " 1036 + "property is deleted", DEFAULT_INT, 1037 DeviceConfig.getProperties(NAMESPACE1, KEY1).getInt(KEY1, DEFAULT_INT)); 1038 } 1039 1040 @Test testDeletePropertyLong()1041 public void testDeletePropertyLong() { 1042 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_LONG)); 1043 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1044 assertEquals("DeviceConfig.Properties.getLong() must return default value if " 1045 + "property is deleted", DEFAULT_LONG, 1046 DeviceConfig.getProperties(NAMESPACE1, KEY1).getLong(KEY1, DEFAULT_LONG)); 1047 } 1048 1049 @Test testDeletePropertyFloat()1050 public void testDeletePropertyFloat() { 1051 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, String.valueOf(VALID_FLOAT)); 1052 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1053 assertEquals("DeviceConfig.Properties.getString() must return default value if " 1054 + "property is deleted", DEFAULT_FLOAT, 1055 DeviceConfig.getProperties(NAMESPACE1, KEY1).getFloat(KEY1, DEFAULT_FLOAT), 0.0f); 1056 } 1057 1058 @Test testDeleteProperty_withNonExistingProperty()1059 public void testDeleteProperty_withNonExistingProperty() { 1060 assertNull(DeviceConfig.getProperty(NAMESPACE1, KEY_NON_EXISTING)); 1061 // Test that deletion returns true when the key doesn't exist 1062 deletePropertyAndAssertNoChange(NAMESPACE1, KEY_NON_EXISTING); 1063 } 1064 1065 @Test testDeleteProperty_withUndeletedProperty()1066 public void testDeleteProperty_withUndeletedProperty() { 1067 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 1068 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY2, VALUE2); 1069 assertEquals(VALUE1, DeviceConfig.getProperty(NAMESPACE1, KEY1)); 1070 assertEquals(VALUE2, DeviceConfig.getProperty(NAMESPACE1, KEY2)); 1071 final Properties propertiesBeforeDeletion = DeviceConfig.getProperties( 1072 NAMESPACE1, KEY1, KEY2); 1073 assertEquals(VALUE1, propertiesBeforeDeletion.getString(KEY1, DEFAULT_VALUE)); 1074 assertEquals(VALUE2, propertiesBeforeDeletion.getString(KEY2, DEFAULT_VALUE)); 1075 // Only delete one property, leaving another one undeleted 1076 final Properties propertiesAfterDeletion = deletePropertyAndAssertSuccessfulChange( 1077 NAMESPACE1, KEY1); 1078 final String result = DeviceConfig.getString(NAMESPACE1, KEY1, DEFAULT_VALUE); 1079 assertEquals("DeviceConfig.getString() must return default value if property is " 1080 + "deleted", DEFAULT_VALUE, result); 1081 assertNull("DeviceConfig.getProperty() must return null if property is deleted", 1082 DeviceConfig.getProperty(NAMESPACE1, KEY1)); 1083 assertEquals(VALUE2, DeviceConfig.getProperty(NAMESPACE1, KEY2)); 1084 assertEquals("DeviceConfig.Properties.getString() must return default value if " 1085 + "property is deleted", DEFAULT_VALUE, propertiesAfterDeletion.getString(KEY1, 1086 DEFAULT_VALUE)); 1087 assertEquals(VALUE2, propertiesBeforeDeletion.getString(KEY2, DEFAULT_VALUE)); 1088 } 1089 1090 /** 1091 * Test that properties listener is successfully registered and provides callbacks on value 1092 * change when DeviceConfig.setProperty is called. 1093 */ 1094 @Test testPropertiesListener_setProperty()1095 public void testPropertiesListener_setProperty() { 1096 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 1097 } 1098 1099 /** 1100 * Test that properties listener is successfully registered and provides callbacks on value 1101 * change when DeviceConfig.setProperties is called. 1102 */ 1103 @Test testPropertiesListener_setProperties()1104 public void testPropertiesListener_setProperties() throws Exception { 1105 Properties properties = new Properties.Builder(NAMESPACE1) 1106 .setString(KEY1, VALUE1).setInt(KEY2, VALID_INT).build(); 1107 setPropertiesAndAssertSuccessfulChange(properties); 1108 } 1109 1110 /** 1111 * Test that properties listener is successfully registered and provides callbacks on value 1112 * change when DeviceConfig.deleteProperty is called. 1113 */ 1114 @Test testPropertiesListener_deleteProperty()1115 public void testPropertiesListener_deleteProperty() { 1116 setPropertiesAndAssertSuccessfulChange(NAMESPACE1, KEY1, VALUE1); 1117 deletePropertyAndAssertSuccessfulChange(NAMESPACE1, KEY1); 1118 } 1119 1120 /** 1121 * Test that two properties listeners subscribed to the same namespace are successfully 1122 * registered and unregistered while receiving correct updates in all states. 1123 */ 1124 @Test testTwoPropertiesListenersSameNamespace()1125 public void testTwoPropertiesListenersSameNamespace() { 1126 final List<PropertyUpdate> receivedUpdates1 = new ArrayList<>(); 1127 final List<PropertyUpdate> receivedUpdates2 = new ArrayList<>(); 1128 1129 OnPropertiesChangedListener listener1 = createOnPropertiesChangedListener(receivedUpdates1); 1130 OnPropertiesChangedListener listener2 = createOnPropertiesChangedListener(receivedUpdates2); 1131 1132 try { 1133 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE1, EXECUTOR, listener1); 1134 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 1135 1136 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/1); 1137 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/0); 1138 1139 assertEquals("OnPropertiesListener did not receive expected update", 1140 receivedUpdates1.size(), /*expectedTotalUpdatesCount=*/1); 1141 assertEquals("OnPropertiesListener received unexpected update", 1142 receivedUpdates2.size(), /*expectedTotalUpdatesCount=*/0); 1143 receivedUpdates1.get(0).assertEqual(NAMESPACE1, KEY1, VALUE1); 1144 1145 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE1, EXECUTOR, listener2); 1146 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE2, /*makeDefault=*/false); 1147 1148 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1149 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/1); 1150 1151 assertEquals("OnPropertiesListener did not receive expected update", 1152 receivedUpdates1.size(), 2); 1153 assertEquals("OnPropertiesListener did not receive expected update", 1154 receivedUpdates2.size(), 1); 1155 receivedUpdates1.get(1).assertEqual(NAMESPACE1, KEY1, VALUE2); 1156 receivedUpdates2.get(0).assertEqual(NAMESPACE1, KEY1, VALUE2); 1157 1158 DeviceConfig.removeOnPropertiesChangedListener(listener1); 1159 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 1160 1161 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/2); 1162 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1163 1164 assertEquals("OnPropertiesListener received unexpected update", 1165 receivedUpdates1.size(), 2); 1166 assertEquals("OnPropertiesListener did not receive expected update", 1167 receivedUpdates2.size(), 2); 1168 1169 receivedUpdates2.get(1).assertEqual(NAMESPACE1, KEY1, VALUE1); 1170 1171 DeviceConfig.removeOnPropertiesChangedListener(listener2); 1172 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE2, /*makeDefault=*/false); 1173 1174 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/2); 1175 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1176 1177 assertEquals("OnPropertiesListener received unexpected update", 1178 receivedUpdates1.size(), 2); 1179 assertEquals("OnPropertiesListener received unexpected update", 1180 receivedUpdates2.size(), 2); 1181 } finally { 1182 DeviceConfig.removeOnPropertiesChangedListener(listener1); 1183 DeviceConfig.removeOnPropertiesChangedListener(listener2); 1184 } 1185 } 1186 1187 /** 1188 * Test that two properties listeners subscribed to different namespaces are successfully 1189 * registered and unregistered while receiving correct updates in all states. 1190 */ 1191 @Test testTwoPropertiesListenersDifferentNamespace()1192 public void testTwoPropertiesListenersDifferentNamespace() { 1193 final List<PropertyUpdate> receivedUpdates1 = new ArrayList<>(); 1194 final List<PropertyUpdate> receivedUpdates2 = new ArrayList<>(); 1195 1196 OnPropertiesChangedListener listener1 = createOnPropertiesChangedListener(receivedUpdates1); 1197 OnPropertiesChangedListener listener2 = createOnPropertiesChangedListener(receivedUpdates2); 1198 1199 try { 1200 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE1, EXECUTOR, listener1); 1201 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 1202 1203 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/1); 1204 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/0); 1205 1206 assertEquals("OnPropertiesListener did not receive expected update", 1207 receivedUpdates1.size(), 1); 1208 assertEquals("OnPropertiesListener received unexpected update", 1209 receivedUpdates2.size(), 0); 1210 receivedUpdates1.get(0).assertEqual(NAMESPACE1, KEY1, VALUE1); 1211 1212 DeviceConfig.addOnPropertiesChangedListener(NAMESPACE2, EXECUTOR, listener2); 1213 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE2, /*makeDefault=*/false); 1214 1215 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1216 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/0); 1217 1218 assertEquals("OnPropertiesListener did not receive expected update", 1219 receivedUpdates1.size(), 2); 1220 assertEquals("OnPropertiesListener received unexpected update", 1221 receivedUpdates2.size(), 0); 1222 receivedUpdates1.get(1).assertEqual(NAMESPACE1, KEY1, VALUE2); 1223 1224 DeviceConfig.setProperty(NAMESPACE2, KEY1, VALUE1, /*makeDefault=*/false); 1225 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/1); 1226 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1227 1228 assertEquals("OnPropertiesListener received unexpected update", 1229 receivedUpdates1.size(), 2); 1230 assertEquals("OnPropertiesListener did not receive expected update", 1231 receivedUpdates2.size(), 1); 1232 1233 receivedUpdates2.get(0).assertEqual(NAMESPACE2, KEY1, VALUE1); 1234 1235 DeviceConfig.removeOnPropertiesChangedListener(listener1); 1236 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/false); 1237 1238 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/1); 1239 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1240 1241 assertEquals("OnPropertiesListener received unexpected update", 1242 receivedUpdates1.size(), 2); 1243 assertEquals("OnPropertiesListener received unexpected update", 1244 receivedUpdates2.size(), 1); 1245 1246 DeviceConfig.setProperty(NAMESPACE2, KEY1, VALUE2, /*makeDefault=*/false); 1247 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/2); 1248 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1249 1250 assertEquals("OnPropertiesListener received unexpected update", 1251 receivedUpdates1.size(), 2); 1252 assertEquals("OnPropertiesListener did not receive expected update", 1253 receivedUpdates2.size(), 2); 1254 1255 receivedUpdates2.get(1).assertEqual(NAMESPACE2, KEY1, VALUE2); 1256 DeviceConfig.removeOnPropertiesChangedListener(listener2); 1257 1258 waitForListenerUpdateOrTimeout(receivedUpdates2, /*expectedTotalUpdatesCount=*/2); 1259 waitForListenerUpdateOrTimeout(receivedUpdates1, /*expectedTotalUpdatesCount=*/2); 1260 1261 assertEquals("OnPropertiesListener received unexpected update", 1262 receivedUpdates1.size(), 2); 1263 assertEquals("OnPropertiesListener received unexpected update", 1264 receivedUpdates2.size(), 2); 1265 1266 } catch(Exception e) { 1267 throw e; 1268 } finally { 1269 DeviceConfig.removeOnPropertiesChangedListener(listener1); 1270 DeviceConfig.removeOnPropertiesChangedListener(listener2); 1271 } 1272 } 1273 1274 /** 1275 * Test that reset to package default successfully resets values. 1276 */ 1277 @Test testResetToPackageDefaults()1278 public void testResetToPackageDefaults() { 1279 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE1, /*makeDefault=*/true); 1280 DeviceConfig.setProperty(NAMESPACE1, KEY1, VALUE2, /*makeDefault=*/false); 1281 1282 assertEquals(DeviceConfig.getProperty(NAMESPACE1, KEY1), VALUE2); 1283 1284 DeviceConfig.resetToDefaults(RESET_MODE_PACKAGE_DEFAULTS, NAMESPACE1); 1285 1286 assertEquals(DeviceConfig.getProperty(NAMESPACE1, KEY1), VALUE1); 1287 } 1288 1289 /** 1290 * Test updating syncDisabledMode. 1291 */ 1292 @Test testSetSyncDisabledMode()1293 public void testSetSyncDisabledMode() { 1294 DeviceConfig.setSyncDisabledMode(SYNC_DISABLED_MODE_NONE); 1295 assertEquals(SYNC_DISABLED_MODE_NONE, DeviceConfig.getSyncDisabledMode()); 1296 DeviceConfig.setSyncDisabledMode(RESET_MODE_PACKAGE_DEFAULTS); 1297 assertEquals(RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.getSyncDisabledMode()); 1298 } 1299 1300 1301 /** 1302 * Test getting public name spaces. 1303 */ 1304 @Test testGetPublicNameSpace()1305 public void testGetPublicNameSpace() { 1306 List<String> publicNameSpaces = Arrays.asList("textclassifier", "runtime", "statsd_java", 1307 "statsd_java_boot", "selection_toolbar", "autofill", 1308 "device_policy_manager", "content_capture"); 1309 1310 assertTrue(DeviceConfig.getPublicNamespaces().containsAll(publicNameSpaces)); 1311 } 1312 1313 /** 1314 * Test set monitor callback. 1315 */ 1316 @Test testSetMonitorCallback()1317 public void testSetMonitorCallback() { 1318 final CountDownLatch latch = new CountDownLatch(2); 1319 final TestMonitorCallback callback = new TestMonitorCallback(latch); 1320 1321 DeviceConfig.setMonitorCallback(CONTEXT.getContentResolver(), 1322 Executors.newSingleThreadExecutor(), callback); 1323 try { 1324 DeviceConfig.setProperties(new Properties.Builder(NAMESPACE1) 1325 .setString(KEY1, VALUE1).setString(KEY2, VALUE2).build()); 1326 } catch (DeviceConfig.BadConfigException e) { 1327 fail("Callback set strings" + e.toString()); 1328 } 1329 1330 // Reading properties triggers the monitor callback function. 1331 DeviceConfig.getString(NAMESPACE1, KEY1, null); 1332 1333 try { 1334 if (!latch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1335 fail("Callback function was not called"); 1336 } 1337 } catch (InterruptedException e) { 1338 // this part is executed when an exception (in this example InterruptedException) occurs 1339 fail("Callback function was not called due to interruption" + e.toString()); 1340 } 1341 assertEquals(callback.onNamespaceUpdateCalls, 1); 1342 assertEquals(callback.onDeviceConfigAccessCalls, 1); 1343 DeviceConfig.clearMonitorCallback(CONTEXT.getContentResolver()); 1344 } 1345 1346 /** 1347 * Test clear monitor callback. 1348 */ 1349 @Test testClearMonitorCallback()1350 public void testClearMonitorCallback() { 1351 final CountDownLatch latch = new CountDownLatch(2); 1352 final TestMonitorCallback callback = new TestMonitorCallback(latch); 1353 1354 DeviceConfig.setMonitorCallback(CONTEXT.getContentResolver(), 1355 Executors.newSingleThreadExecutor(), callback); 1356 DeviceConfig.clearMonitorCallback(CONTEXT.getContentResolver()); 1357 // Reading properties triggers the monitor callback function. 1358 DeviceConfig.getString(NAMESPACE1, KEY1, null); 1359 try { 1360 DeviceConfig.setProperties(new Properties.Builder(NAMESPACE1) 1361 .setString(KEY1, VALUE1).setString(KEY2, VALUE2).build()); 1362 } catch (DeviceConfig.BadConfigException e) { 1363 fail("Callback set strings" + e.toString()); 1364 } 1365 1366 try { 1367 if (latch.await(OPERATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 1368 fail("Callback function was called while it has been cleared"); 1369 } 1370 } catch (InterruptedException e) { 1371 // this part is executed when an exception (in this example InterruptedException) occurs 1372 fail("un expected interruption occur" + e.toString()); 1373 } 1374 assertEquals(callback.onNamespaceUpdateCalls, 0); 1375 assertEquals(callback.onDeviceConfigAccessCalls, 0); 1376 } 1377 1378 private class TestMonitorCallback implements DeviceConfig.MonitorCallback { 1379 public int onNamespaceUpdateCalls = 0; 1380 public int onDeviceConfigAccessCalls = 0; 1381 public CountDownLatch latch; 1382 TestMonitorCallback(CountDownLatch latch)1383 TestMonitorCallback(CountDownLatch latch) { 1384 this.latch = latch; 1385 } 1386 onNamespaceUpdate(String updatedNamespace)1387 public void onNamespaceUpdate(String updatedNamespace) { 1388 onNamespaceUpdateCalls++; 1389 latch.countDown(); 1390 } 1391 onDeviceConfigAccess(String callingPackage, String namespace)1392 public void onDeviceConfigAccess(String callingPackage, String namespace) { 1393 onDeviceConfigAccessCalls++; 1394 latch.countDown(); 1395 } 1396 } 1397 createOnPropertiesChangedListener( List<PropertyUpdate> receivedUpdates)1398 private OnPropertiesChangedListener createOnPropertiesChangedListener( 1399 List<PropertyUpdate> receivedUpdates) { 1400 OnPropertiesChangedListener changeListener = new OnPropertiesChangedListener() { 1401 @Override 1402 public void onPropertiesChanged(Properties properties) { 1403 synchronized (mLock) { 1404 receivedUpdates.add(new PropertyUpdate(properties)); 1405 mLock.notifyAll(); 1406 } 1407 } 1408 }; 1409 return changeListener; 1410 } 1411 waitForListenerUpdateOrTimeout( List<PropertyUpdate> receivedUpdates, int expectedTotalUpdatesCount)1412 private void waitForListenerUpdateOrTimeout( 1413 List<PropertyUpdate> receivedUpdates, int expectedTotalUpdatesCount) { 1414 1415 final long startTimeMillis = SystemClock.uptimeMillis(); 1416 synchronized (mLock) { 1417 while (true) { 1418 if (receivedUpdates.size() >= expectedTotalUpdatesCount) { 1419 return; 1420 } 1421 final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis; 1422 if (elapsedTimeMillis >= WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS) { 1423 return; 1424 } 1425 final long remainingTimeMillis = WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS 1426 - elapsedTimeMillis; 1427 try { 1428 mLock.wait(remainingTimeMillis); 1429 } catch (InterruptedException ie) { 1430 /* ignore */ 1431 } 1432 } 1433 } 1434 } 1435 setPropertiesAndAssertSuccessfulChange(String setNamespace, String setName, String setValue)1436 private Properties setPropertiesAndAssertSuccessfulChange(String setNamespace, String setName, 1437 String setValue) { 1438 final List<PropertyUpdate> receivedUpdates = new ArrayList<>(); 1439 OnPropertiesChangedListener changeListener = createOnPropertiesChangedListener(receivedUpdates); 1440 1441 DeviceConfig.addOnPropertiesChangedListener(setNamespace, EXECUTOR, changeListener); 1442 1443 DeviceConfig.setProperty(setNamespace, setName, setValue, /*makeDefault=*/false); 1444 waitForListenerUpdateOrTimeout(receivedUpdates, 1); 1445 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 1446 1447 assertEquals("Failed to receive update to OnPropertiesChangedListener", 1448 receivedUpdates.size(), 1); 1449 PropertyUpdate propertiesUpdate = receivedUpdates.get(0); 1450 propertiesUpdate.assertEqual(setNamespace, setName, setValue); 1451 1452 return propertiesUpdate.properties; 1453 } 1454 setPropertiesAndAssertSuccessfulChange(Properties properties)1455 private Properties setPropertiesAndAssertSuccessfulChange(Properties properties) 1456 throws Exception { 1457 final List<PropertyUpdate> receivedUpdates = new ArrayList<>(); 1458 OnPropertiesChangedListener changeListener 1459 = createOnPropertiesChangedListener(receivedUpdates); 1460 DeviceConfig.addOnPropertiesChangedListener( 1461 properties.getNamespace(), EXECUTOR, changeListener); 1462 1463 DeviceConfig.setProperties(properties); 1464 waitForListenerUpdateOrTimeout(receivedUpdates, 1); 1465 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 1466 1467 assertEquals("Failed to receive update to OnPropertiesChangedListener", 1468 1, receivedUpdates.size()); 1469 PropertyUpdate propertiesUpdate = receivedUpdates.get(0); 1470 propertiesUpdate.assertEqual(properties); 1471 1472 return propertiesUpdate.properties; 1473 } 1474 deletePropertyAndAssertSuccessfulChange(String namespace, String name)1475 private Properties deletePropertyAndAssertSuccessfulChange(String namespace, String name) { 1476 final List<PropertyUpdate> receivedUpdates = new ArrayList<>(); 1477 OnPropertiesChangedListener changeListener = createOnPropertiesChangedListener(receivedUpdates); 1478 1479 DeviceConfig.addOnPropertiesChangedListener(namespace, EXECUTOR, changeListener); 1480 1481 assertTrue(DeviceConfig.deleteProperty(namespace, name)); 1482 assertNull("DeviceConfig.getProperty() must return null if property is deleted", 1483 DeviceConfig.getProperty(namespace, name)); 1484 waitForListenerUpdateOrTimeout(receivedUpdates, 1); 1485 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 1486 1487 assertEquals("Failed to receive update to OnPropertiesChangedListener", 1488 receivedUpdates.size(), 1); 1489 PropertyUpdate propertiesUpdate = receivedUpdates.get(0); 1490 propertiesUpdate.assertEqual(namespace, name, null); 1491 1492 return propertiesUpdate.properties; 1493 } 1494 deletePropertyAndAssertNoChange(String namespace, String name)1495 private Properties deletePropertyAndAssertNoChange(String namespace, String name) { 1496 final List<PropertyUpdate> receivedUpdates = new ArrayList<>(); 1497 OnPropertiesChangedListener changeListener = createOnPropertiesChangedListener( 1498 receivedUpdates); 1499 1500 DeviceConfig.addOnPropertiesChangedListener(namespace, EXECUTOR, changeListener); 1501 1502 assertTrue(DeviceConfig.deleteProperty(namespace, name)); 1503 assertNull("DeviceConfig.getProperty() must return null if property is deleted", 1504 DeviceConfig.getProperty(namespace, name)); 1505 waitForListenerUpdateOrTimeout(receivedUpdates, 1); 1506 DeviceConfig.removeOnPropertiesChangedListener(changeListener); 1507 1508 assertEquals("Received unexpected update to OnPropertiesChangedListener", 1509 receivedUpdates.size(), 0); 1510 PropertyUpdate propertiesUpdate = new PropertyUpdate(DeviceConfig.getProperties( 1511 namespace, "")); 1512 propertiesUpdate.assertEqual(namespace, name, null); 1513 1514 return propertiesUpdate.properties; 1515 } 1516 nullifyProperty(String namespace, String key)1517 private void nullifyProperty(String namespace, String key) { 1518 if (DeviceConfig.getString(namespace, key, null) != null) { 1519 setPropertiesAndAssertSuccessfulChange(namespace, key, null); 1520 } 1521 } 1522 deletePropertyThrowShell(String namespace, String key)1523 private static void deletePropertyThrowShell(String namespace, String key) { 1524 InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand( 1525 "device_config delete " + namespace + " " + key); 1526 } 1527 isSupported()1528 private static boolean isSupported() { 1529 return sUnsupportedReason == null; 1530 } 1531 1532 private static class PropertyUpdate { 1533 Properties properties; 1534 PropertyUpdate(Properties properties)1535 PropertyUpdate(Properties properties) { 1536 this.properties = properties; 1537 } 1538 assertEqual(String namespace, String name, String value)1539 void assertEqual(String namespace, String name, String value) { 1540 Properties properties = 1541 new Properties.Builder(namespace).setString(name, value).build(); 1542 assertEqual(properties); 1543 } 1544 assertEqual(Properties expected)1545 void assertEqual(Properties expected) { 1546 assertEquals(expected.getNamespace(), properties.getNamespace()); 1547 assertEquals(expected.getKeyset().size(), properties.getKeyset().size()); 1548 for (String key : properties.getKeyset()) { 1549 assertEquals(expected.getString(key, DEFAULT_VALUE), 1550 properties.getString(key, DEFAULT_VALUE)); 1551 assertEquals(expected.getBoolean(key, DEFAULT_BOOLEAN_FALSE), 1552 properties.getBoolean(key, DEFAULT_BOOLEAN_FALSE)); 1553 assertEquals(expected.getInt(key, DEFAULT_INT), 1554 properties.getInt(key, DEFAULT_INT)); 1555 assertEquals(expected.getFloat(key, DEFAULT_FLOAT), 1556 properties.getFloat(key, DEFAULT_FLOAT), 0); 1557 assertEquals(expected.getLong(key, DEFAULT_LONG), 1558 properties.getLong(key, DEFAULT_LONG)); 1559 } 1560 } 1561 } 1562 } 1563