1 /* 2 * Copyright (C) 2010 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.tradefed.config; 17 18 import com.android.ddmlib.Log.LogLevel; 19 import com.android.tradefed.build.BuildRetrievalError; 20 import com.android.tradefed.build.IBuildProvider; 21 import com.android.tradefed.command.CommandOptions; 22 import com.android.tradefed.command.ICommandOptions; 23 import com.android.tradefed.config.ConfigurationDef.OptionDef; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.IDeviceRecovery; 26 import com.android.tradefed.device.IDeviceSelection; 27 import com.android.tradefed.device.TestDeviceOptions; 28 import com.android.tradefed.invoker.InvocationContext; 29 import com.android.tradefed.log.ILeveledLogOutput; 30 import com.android.tradefed.result.ITestInvocationListener; 31 import com.android.tradefed.result.TextResultReporter; 32 import com.android.tradefed.targetprep.ITargetPreparer; 33 import com.android.tradefed.testtype.IRemoteTest; 34 import com.android.tradefed.util.FileUtil; 35 import com.android.tradefed.util.MultiMap; 36 37 import junit.framework.TestCase; 38 39 import org.easymock.EasyMock; 40 import org.json.JSONArray; 41 import org.json.JSONException; 42 import org.json.JSONObject; 43 44 import java.io.ByteArrayOutputStream; 45 import java.io.File; 46 import java.io.IOException; 47 import java.io.PrintStream; 48 import java.io.PrintWriter; 49 import java.util.ArrayList; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.Map; 53 54 /** 55 * Unit tests for {@link Configuration}. 56 */ 57 public class ConfigurationTest extends TestCase { 58 59 private static final String CONFIG_NAME = "name"; 60 private static final String CONFIG_DESCRIPTION = "config description"; 61 private static final String CONFIG_OBJECT_TYPE_NAME = "object_name"; 62 private static final String OPTION_DESCRIPTION = "bool description"; 63 private static final String OPTION_NAME = "bool"; 64 private static final String ALT_OPTION_NAME = "map"; 65 66 /** 67 * Interface for test object stored in a {@link IConfiguration}. 68 */ 69 private static interface TestConfig { 70 getBool()71 public boolean getBool(); 72 } 73 74 private static class TestConfigObject implements TestConfig { 75 76 @Option(name = OPTION_NAME, description = OPTION_DESCRIPTION, requiredForRerun = true) 77 private boolean mBool; 78 79 @Option(name = ALT_OPTION_NAME, description = OPTION_DESCRIPTION) 80 private Map<String, Boolean> mBoolMap = new HashMap<String, Boolean>(); 81 82 @Override getBool()83 public boolean getBool() { 84 return mBool; 85 } 86 getMap()87 public Map<String, Boolean> getMap() { 88 return mBoolMap; 89 } 90 } 91 92 private Configuration mConfig; 93 94 /** 95 * {@inheritDoc} 96 */ 97 @Override setUp()98 protected void setUp() throws Exception { 99 super.setUp(); 100 mConfig = new Configuration(CONFIG_NAME, CONFIG_DESCRIPTION); 101 } 102 103 /** 104 * Test that {@link Configuration#getConfigurationObject(String)} can retrieve 105 * a previously stored object. 106 */ testGetConfigurationObject()107 public void testGetConfigurationObject() throws ConfigurationException { 108 TestConfigObject testConfigObject = new TestConfigObject(); 109 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 110 Object fromConfig = mConfig.getConfigurationObject(CONFIG_OBJECT_TYPE_NAME); 111 assertEquals(testConfigObject, fromConfig); 112 } 113 114 /** 115 * Test {@link Configuration#getConfigurationObjectList(String)} 116 */ 117 @SuppressWarnings("unchecked") testGetConfigurationObjectList()118 public void testGetConfigurationObjectList() throws ConfigurationException { 119 TestConfigObject testConfigObject = new TestConfigObject(); 120 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 121 List<TestConfig> configList = (List<TestConfig>)mConfig.getConfigurationObjectList( 122 CONFIG_OBJECT_TYPE_NAME); 123 assertEquals(testConfigObject, configList.get(0)); 124 } 125 126 /** 127 * Test that {@link Configuration#getConfigurationObject(String)} with a name that does 128 * not exist. 129 */ testGetConfigurationObject_wrongname()130 public void testGetConfigurationObject_wrongname() { 131 assertNull(mConfig.getConfigurationObject("non-existent")); 132 } 133 134 /** 135 * Test that calling {@link Configuration#getConfigurationObject(String)} for a built-in config 136 * type that supports lists. 137 */ testGetConfigurationObject_typeIsList()138 public void testGetConfigurationObject_typeIsList() { 139 try { 140 mConfig.getConfigurationObject(Configuration.TEST_TYPE_NAME); 141 fail("IllegalStateException not thrown"); 142 } catch (IllegalStateException e) { 143 // expected 144 } 145 } 146 147 /** 148 * Test that calling {@link Configuration#getConfigurationObject(String)} for a config type 149 * that is a list. 150 */ testGetConfigurationObject_forList()151 public void testGetConfigurationObject_forList() throws ConfigurationException { 152 List<TestConfigObject> list = new ArrayList<TestConfigObject>(); 153 list.add(new TestConfigObject()); 154 list.add(new TestConfigObject()); 155 mConfig.setConfigurationObjectList(CONFIG_OBJECT_TYPE_NAME, list); 156 try { 157 mConfig.getConfigurationObject(CONFIG_OBJECT_TYPE_NAME); 158 fail("IllegalStateException not thrown"); 159 } catch (IllegalStateException e) { 160 // expected 161 } 162 } 163 164 /** 165 * Test that setConfigurationObject throws a ConfigurationException when config object provided 166 * is not the correct type 167 */ testSetConfigurationObject_wrongtype()168 public void testSetConfigurationObject_wrongtype() { 169 try { 170 // arbitrarily, use the "Test" type as expected type 171 mConfig.setConfigurationObject(Configuration.TEST_TYPE_NAME, new TestConfigObject()); 172 fail("setConfigurationObject did not throw ConfigurationException"); 173 } catch (ConfigurationException e) { 174 // expected 175 } 176 } 177 178 /** 179 * Test {@link Configuration#getConfigurationObjectList(String)} when config object 180 * with given name does not exist. 181 */ testGetConfigurationObjectList_wrongname()182 public void testGetConfigurationObjectList_wrongname() { 183 assertNull(mConfig.getConfigurationObjectList("non-existent")); 184 } 185 186 /** 187 * Test {@link Configuration#setConfigurationObjectList(String, List)} when config object 188 * is the wrong type 189 */ testSetConfigurationObjectList_wrongtype()190 public void testSetConfigurationObjectList_wrongtype() { 191 try { 192 List<TestConfigObject> myList = new ArrayList<TestConfigObject>(1); 193 myList.add(new TestConfigObject()); 194 // arbitrarily, use the "Test" type as expected type 195 mConfig.setConfigurationObjectList(Configuration.TEST_TYPE_NAME, myList); 196 fail("setConfigurationObject did not throw ConfigurationException"); 197 } catch (ConfigurationException e) { 198 // expected 199 } 200 } 201 202 /** 203 * Test method for {@link Configuration#getBuildProvider()}. 204 */ testGetBuildProvider()205 public void testGetBuildProvider() throws BuildRetrievalError { 206 // check that the default provider is present and doesn't blow up 207 assertNotNull(mConfig.getBuildProvider().getBuild()); 208 // check set and get 209 final IBuildProvider provider = EasyMock.createMock(IBuildProvider.class); 210 mConfig.setBuildProvider(provider); 211 assertEquals(provider, mConfig.getBuildProvider()); 212 } 213 214 /** 215 * Test method for {@link Configuration#getTargetPreparers()}. 216 */ testGetTargetPreparers()217 public void testGetTargetPreparers() throws Exception { 218 // check that the callback is working and doesn't blow up 219 assertEquals(0, mConfig.getTargetPreparers().size()); 220 // test set and get 221 final ITargetPreparer prep = EasyMock.createMock(ITargetPreparer.class); 222 mConfig.setTargetPreparer(prep); 223 assertEquals(prep, mConfig.getTargetPreparers().get(0)); 224 } 225 226 /** 227 * Test method for {@link Configuration#getTests()}. 228 */ testGetTests()229 public void testGetTests() throws DeviceNotAvailableException { 230 // check that the default test is present and doesn't blow up 231 mConfig.getTests().get(0).run(new TextResultReporter()); 232 IRemoteTest test1 = EasyMock.createMock(IRemoteTest.class); 233 mConfig.setTest(test1); 234 assertEquals(test1, mConfig.getTests().get(0)); 235 } 236 237 /** 238 * Test method for {@link Configuration#getDeviceRecovery()}. 239 */ testGetDeviceRecovery()240 public void testGetDeviceRecovery() { 241 // check that the default recovery is present 242 assertNotNull(mConfig.getDeviceRecovery()); 243 final IDeviceRecovery recovery = EasyMock.createMock(IDeviceRecovery.class); 244 mConfig.setDeviceRecovery(recovery); 245 assertEquals(recovery, mConfig.getDeviceRecovery()); 246 } 247 248 /** 249 * Test method for {@link Configuration#getLogOutput()}. 250 */ testGetLogOutput()251 public void testGetLogOutput() { 252 // check that the default logger is present and doesn't blow up 253 mConfig.getLogOutput().printLog(LogLevel.INFO, "testGetLogOutput", "test"); 254 final ILeveledLogOutput logger = EasyMock.createMock(ILeveledLogOutput.class); 255 mConfig.setLogOutput(logger); 256 assertEquals(logger, mConfig.getLogOutput()); 257 } 258 259 /** 260 * Test method for {@link Configuration#getTestInvocationListeners()}. 261 * @throws ConfigurationException 262 */ testGetTestInvocationListeners()263 public void testGetTestInvocationListeners() throws ConfigurationException { 264 // check that the default listener is present and doesn't blow up 265 ITestInvocationListener defaultListener = mConfig.getTestInvocationListeners().get(0); 266 defaultListener.invocationStarted(new InvocationContext()); 267 defaultListener.invocationEnded(1); 268 269 final ITestInvocationListener listener1 = EasyMock.createMock( 270 ITestInvocationListener.class); 271 mConfig.setTestInvocationListener(listener1); 272 assertEquals(listener1, mConfig.getTestInvocationListeners().get(0)); 273 } 274 275 /** 276 * Test method for {@link Configuration#getCommandOptions()}. 277 */ testGetCommandOptions()278 public void testGetCommandOptions() { 279 // check that the default object is present 280 assertNotNull(mConfig.getCommandOptions()); 281 final ICommandOptions cmdOptions = EasyMock.createMock(ICommandOptions.class); 282 mConfig.setCommandOptions(cmdOptions); 283 assertEquals(cmdOptions, mConfig.getCommandOptions()); 284 } 285 286 /** 287 * Test method for {@link Configuration#getDeviceRequirements()}. 288 */ testGetDeviceRequirements()289 public void testGetDeviceRequirements() { 290 // check that the default object is present 291 assertNotNull(mConfig.getDeviceRequirements()); 292 final IDeviceSelection deviceSelection = EasyMock.createMock( 293 IDeviceSelection.class); 294 mConfig.setDeviceRequirements(deviceSelection); 295 assertEquals(deviceSelection, mConfig.getDeviceRequirements()); 296 } 297 298 /** 299 * Test {@link Configuration#setConfigurationObject(String, Object)} with a 300 * {@link IConfigurationReceiver} 301 */ testSetConfigurationObject_configReceiver()302 public void testSetConfigurationObject_configReceiver() throws ConfigurationException { 303 final IConfigurationReceiver mockConfigReceiver = EasyMock.createMock( 304 IConfigurationReceiver.class); 305 mockConfigReceiver.setConfiguration(mConfig); 306 EasyMock.replay(mockConfigReceiver); 307 mConfig.setConfigurationObject("example", mockConfigReceiver); 308 EasyMock.verify(mockConfigReceiver); 309 } 310 311 /** 312 * Test {@link Configuration#injectOptionValue(String, String)} 313 */ testInjectOptionValue()314 public void testInjectOptionValue() throws ConfigurationException { 315 TestConfigObject testConfigObject = new TestConfigObject(); 316 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 317 mConfig.injectOptionValue(OPTION_NAME, Boolean.toString(true)); 318 assertTrue(testConfigObject.getBool()); 319 assertEquals(1, mConfig.getConfigurationDescription().getRerunOptions().size()); 320 OptionDef optionDef = mConfig.getConfigurationDescription().getRerunOptions().get(0); 321 assertEquals(OPTION_NAME, optionDef.name); 322 } 323 324 /** 325 * Test {@link Configuration#injectOptionValue(String, String, String)} 326 */ testInjectMapOptionValue()327 public void testInjectMapOptionValue() throws ConfigurationException { 328 final String key = "hello"; 329 330 TestConfigObject testConfigObject = new TestConfigObject(); 331 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 332 assertEquals(0, testConfigObject.getMap().size()); 333 mConfig.injectOptionValue(ALT_OPTION_NAME, key, Boolean.toString(true)); 334 335 Map<String, Boolean> map = testConfigObject.getMap(); 336 assertEquals(1, map.size()); 337 assertNotNull(map.get(key)); 338 assertTrue(map.get(key).booleanValue()); 339 } 340 341 /** 342 * Test {@link Configuration#injectOptionValue(String, String)} is throwing an exception 343 * for map options without no map key provided in the option value 344 */ testInjectParsedMapOptionValueNoKey()345 public void testInjectParsedMapOptionValueNoKey() throws ConfigurationException { 346 TestConfigObject testConfigObject = new TestConfigObject(); 347 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 348 assertEquals(0, testConfigObject.getMap().size()); 349 350 try { 351 mConfig.injectOptionValue(ALT_OPTION_NAME, "wrong_value"); 352 fail("ConfigurationException is not thrown for a map option without retrievable key"); 353 } catch (ConfigurationException ignore) { 354 // expected 355 } 356 } 357 358 /** 359 * Test {@link Configuration#injectOptionValue(String, String)} is throwing an exception 360 * for map options with ambiguous map key provided in the option value (multiple equal signs) 361 */ testInjectParsedMapOptionValueAmbiguousKey()362 public void testInjectParsedMapOptionValueAmbiguousKey() throws ConfigurationException { 363 TestConfigObject testConfigObject = new TestConfigObject(); 364 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 365 assertEquals(0, testConfigObject.getMap().size()); 366 367 try { 368 mConfig.injectOptionValue(ALT_OPTION_NAME, "a=b=c"); 369 fail("ConfigurationException is not thrown for a map option with ambiguous key"); 370 } catch (ConfigurationException ignore) { 371 // expected 372 } 373 } 374 375 /** 376 * Test {@link Configuration#injectOptionValue(String, String)} is correctly parsing map options 377 */ testInjectParsedMapOptionValue()378 public void testInjectParsedMapOptionValue() throws ConfigurationException { 379 final String key = "hello\\=key"; 380 381 TestConfigObject testConfigObject = new TestConfigObject(); 382 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 383 assertEquals(0, testConfigObject.getMap().size()); 384 mConfig.injectOptionValue(ALT_OPTION_NAME, key + "=" + Boolean.toString(true)); 385 386 Map<String, Boolean> map = testConfigObject.getMap(); 387 assertEquals(1, map.size()); 388 assertNotNull(map.get(key)); 389 assertTrue(map.get(key)); 390 } 391 392 /** 393 * Test {@link Configuration#injectOptionValues(List)} 394 */ testInjectOptionValues()395 public void testInjectOptionValues() throws ConfigurationException { 396 final String key = "hello"; 397 List<OptionDef> options = new ArrayList<>(); 398 options.add(new OptionDef(OPTION_NAME, Boolean.toString(true), null)); 399 options.add(new OptionDef(ALT_OPTION_NAME, key, Boolean.toString(true), null)); 400 401 TestConfigObject testConfigObject = new TestConfigObject(); 402 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 403 mConfig.injectOptionValues(options); 404 405 assertTrue(testConfigObject.getBool()); 406 Map<String, Boolean> map = testConfigObject.getMap(); 407 assertEquals(1, map.size()); 408 assertNotNull(map.get(key)); 409 assertTrue(map.get(key).booleanValue()); 410 assertEquals(1, mConfig.getConfigurationDescription().getRerunOptions().size()); 411 OptionDef optionDef = mConfig.getConfigurationDescription().getRerunOptions().get(0); 412 assertEquals(OPTION_NAME, optionDef.name); 413 } 414 415 /** 416 * Basic test for {@link Configuration#printCommandUsage(boolean, java.io.PrintStream)}. 417 */ testPrintCommandUsage()418 public void testPrintCommandUsage() throws ConfigurationException { 419 TestConfigObject testConfigObject = new TestConfigObject(); 420 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 421 // dump the print stream results to the ByteArrayOutputStream, so contents can be evaluated 422 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 423 PrintStream mockPrintStream = new PrintStream(outputStream); 424 mConfig.printCommandUsage(false, mockPrintStream); 425 426 // verifying exact contents would be prone to high-maintenance, so instead, just validate 427 // all expected names are present 428 final String usageString = outputStream.toString(); 429 assertTrue("Usage text does not contain config name", usageString.contains(CONFIG_NAME)); 430 assertTrue("Usage text does not contain config description", usageString.contains( 431 CONFIG_DESCRIPTION)); 432 assertTrue("Usage text does not contain object name", usageString.contains( 433 CONFIG_OBJECT_TYPE_NAME)); 434 assertTrue("Usage text does not contain option name", usageString.contains(OPTION_NAME)); 435 assertTrue("Usage text does not contain option description", 436 usageString.contains(OPTION_DESCRIPTION)); 437 438 // ensure help prints out options from default config types 439 assertTrue("Usage text does not contain --serial option name", 440 usageString.contains("serial")); 441 } 442 443 /** 444 * Basic test for {@link Configuration#getJsonCommandUsage()}. 445 */ testGetJsonCommandUsage()446 public void testGetJsonCommandUsage() throws ConfigurationException, JSONException { 447 TestConfigObject testConfigObject = new TestConfigObject(); 448 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfigObject); 449 mConfig.injectOptionValue(ALT_OPTION_NAME, "foo", Boolean.toString(true)); 450 mConfig.injectOptionValue(ALT_OPTION_NAME, "bar", Boolean.toString(false)); 451 452 // General validation of usage elements 453 JSONArray usage = mConfig.getJsonCommandUsage(); 454 JSONObject jsonConfigObject = null; 455 for (int i = 0; i < usage.length(); i++) { 456 JSONObject optionClass = usage.getJSONObject(i); 457 458 // Each element should contain 'name', 'class', and 'options' values 459 assertTrue("Usage element does not contain a 'name' value", optionClass.has("name")); 460 assertTrue("Usage element does not contain a 'class' value", optionClass.has("class")); 461 assertTrue("Usage element does not contain a 'options' value", 462 optionClass.has("options")); 463 464 // General validation of each field 465 JSONArray options = optionClass.getJSONArray("options"); 466 for (int j = 0; j < options.length(); j++) { 467 JSONObject field = options.getJSONObject(j); 468 469 // Each field should at least have 'name', 'description', 'mandatory', 470 // 'javaClass', and 'updateRule' values 471 assertTrue("Option field does not have a 'name' value", field.has("name")); 472 assertTrue("Option field does not have a 'description' value", 473 field.has("description")); 474 assertTrue("Option field does not have a 'mandatory' value", 475 field.has("mandatory")); 476 assertTrue("Option field does not have a 'javaClass' value", 477 field.has("javaClass")); 478 assertTrue("Option field does not have an 'updateRule' value", 479 field.has("updateRule")); 480 } 481 482 // The only elements should either be built-in types, or the configuration object we 483 // added. 484 String name = optionClass.getString("name"); 485 if (name.equals(CONFIG_OBJECT_TYPE_NAME)) { 486 // The object we added should only appear once 487 assertNull("Duplicate JSON usage element", jsonConfigObject); 488 jsonConfigObject = optionClass; 489 } else { 490 assertTrue(String.format("Unexpected JSON usage element: %s", name), 491 Configuration.isBuiltInObjType(name)); 492 } 493 } 494 495 // Verify that the configuration element we added has the expected values 496 assertNotNull("Missing JSON usage element", jsonConfigObject); 497 JSONArray options = jsonConfigObject.getJSONArray("options"); 498 JSONObject jsonOptionField = null; 499 JSONObject jsonAltOptionField = null; 500 for (int i = 0; i < options.length(); i++) { 501 JSONObject field = options.getJSONObject(i); 502 503 if (OPTION_NAME.equals(field.getString("name"))) { 504 assertNull("Duplicate option field", jsonOptionField); 505 jsonOptionField = field; 506 } else if (ALT_OPTION_NAME.equals(field.getString("name"))) { 507 assertNull("Duplication option field", jsonAltOptionField); 508 jsonAltOptionField = field; 509 } 510 } 511 assertNotNull(jsonOptionField); 512 assertEquals(OPTION_DESCRIPTION, jsonOptionField.getString("description")); 513 assertNotNull(jsonAltOptionField); 514 assertEquals(OPTION_DESCRIPTION, jsonAltOptionField.getString("description")); 515 516 // Verify that generics have the fully resolved javaClass name 517 assertEquals("java.util.Map<java.lang.String, java.lang.Boolean>", 518 jsonAltOptionField.getString("javaClass")); 519 } 520 findConfigObjectByName(JSONArray usage, String name)521 private JSONObject findConfigObjectByName(JSONArray usage, String name) throws JSONException { 522 for (int i = 0; i < usage.length(); i++) { 523 JSONObject configObject = usage.getJSONObject(i); 524 if (name != null && name.equals(configObject.getString("name"))) { 525 return configObject; 526 } 527 } 528 return null; 529 } 530 531 /** 532 * Test that {@link Configuration#getJsonCommandUsage()} expands {@link MultiMap} values. 533 */ testGetJsonCommandUsageMapValueExpansion()534 public void testGetJsonCommandUsageMapValueExpansion() throws ConfigurationException, 535 JSONException { 536 537 // Inject a simple config object with a map 538 final MultiMap<String, Integer> mapOption = new MultiMap<>(); 539 mapOption.put("foo", 1); 540 mapOption.put("foo", 2); 541 mapOption.put("foo", 3); 542 mapOption.put("bar", 4); 543 mapOption.put("bar", 5); 544 Object testConfig = new Object() { 545 @Option(name = "map-option") 546 MultiMap<String, Integer> mMapOption = mapOption; 547 }; 548 mConfig.setConfigurationObject(CONFIG_OBJECT_TYPE_NAME, testConfig); 549 550 // Get the JSON usage and find our config object 551 JSONArray usage = mConfig.getJsonCommandUsage(); 552 JSONObject jsonTestConfig = findConfigObjectByName(usage, CONFIG_OBJECT_TYPE_NAME); 553 554 // Get the map option 555 JSONArray options = jsonTestConfig.getJSONArray("options"); 556 JSONObject jsonMapOption = options.getJSONObject(0); 557 558 // Validate the map option value 559 JSONObject jsonMapValue = jsonMapOption.getJSONObject("value"); 560 assertEquals(mapOption.get("foo"), jsonMapValue.get("foo")); 561 assertEquals(mapOption.get("bar"), jsonMapValue.get("bar")); 562 } 563 564 /** 565 * Test that {@link Configuration#validateOptions()} doesn't throw when all mandatory fields 566 * are set. 567 */ testValidateOptions()568 public void testValidateOptions() throws ConfigurationException { 569 mConfig.validateOptions(); 570 } 571 572 /** 573 * Test that {@link Configuration#validateOptions()} throws a config exception when shard 574 * count is negative number. 575 */ testValidateOptionsShardException()576 public void testValidateOptionsShardException() throws ConfigurationException { 577 ICommandOptions option = new CommandOptions() { 578 @Override 579 public Integer getShardCount() {return -1;} 580 }; 581 mConfig.setConfigurationObject(Configuration.CMD_OPTIONS_TYPE_NAME, option); 582 try { 583 mConfig.validateOptions(); 584 fail("Should have thrown an exception."); 585 } catch(ConfigurationException expected) { 586 assertEquals("a shard count must be a positive number", expected.getMessage()); 587 } 588 } 589 590 /** 591 * Test that {@link Configuration#validateOptions()} throws a config exception when shard 592 * index is not valid. 593 */ testValidateOptionsShardIndexException()594 public void testValidateOptionsShardIndexException() throws ConfigurationException { 595 ICommandOptions option = new CommandOptions() { 596 @Override 597 public Integer getShardIndex() { 598 return -1; 599 } 600 }; 601 mConfig.setConfigurationObject(Configuration.CMD_OPTIONS_TYPE_NAME, option); 602 try { 603 mConfig.validateOptions(); 604 fail("Should have thrown an exception."); 605 } catch(ConfigurationException expected) { 606 assertEquals("a shard index must be in range [0, shard count)", expected.getMessage()); 607 } 608 } 609 610 /** 611 * Test that {@link Configuration#validateOptions()} throws a config exception when shard 612 * index is above the shard count. 613 */ testValidateOptionsShardIndexAboveShardCount()614 public void testValidateOptionsShardIndexAboveShardCount() throws ConfigurationException { 615 ICommandOptions option = new CommandOptions() { 616 @Override 617 public Integer getShardIndex() { 618 return 3; 619 } 620 @Override 621 public Integer getShardCount() { 622 return 2; 623 } 624 }; 625 mConfig.setConfigurationObject(Configuration.CMD_OPTIONS_TYPE_NAME, option); 626 try { 627 mConfig.validateOptions(); 628 fail("Should have thrown an exception."); 629 } catch(ConfigurationException expected) { 630 assertEquals("a shard index must be in range [0, shard count)", expected.getMessage()); 631 } 632 } 633 634 /** 635 * Ensure that dynamic file download is not triggered in the parent invocation of local 636 * sharding. If that was the case, the downloaded files would be cleaned up right after the 637 * shards are kicked-off in new invocations. 638 */ testValidateOptions_localSharding_skipDownload()639 public void testValidateOptions_localSharding_skipDownload() throws ConfigurationException { 640 CommandOptions options = new CommandOptions(); 641 options.setShardCount(5); 642 options.setShardIndex(null); 643 mConfig.setCommandOptions(options); 644 TestDeviceOptions deviceOptions = new TestDeviceOptions(); 645 File fakeConfigFile = new File("gs://bucket/remote/file/path"); 646 deviceOptions.setAvdConfigFile(fakeConfigFile); 647 mConfig.setDeviceOptions(deviceOptions); 648 649 // No exception for download is thrown because no download occurred. 650 mConfig.validateOptions(true); 651 // Dynamic file is not resolved. 652 assertEquals(fakeConfigFile, deviceOptions.getAvdConfigFile()); 653 } 654 655 /** 656 * Test that {@link Configuration#dumpXml(PrintWriter)} produce the xml output. 657 */ testDumpXml()658 public void testDumpXml() throws IOException { 659 File test = FileUtil.createTempFile("dumpxml", "xml"); 660 try { 661 PrintWriter out = new PrintWriter(test); 662 mConfig.dumpXml(out); 663 out.flush(); 664 String content = FileUtil.readStringFromFile(test); 665 assertTrue(content.length() > 100); 666 assertTrue(content.contains("<configuration>")); 667 assertTrue(content.contains("<test class")); 668 } finally { 669 FileUtil.deleteFile(test); 670 } 671 } 672 673 /** 674 * Test that {@link Configuration#dumpXml(PrintWriter)} produce the xml output without objects 675 * that have been filtered. 676 */ testDumpXml_withFilter()677 public void testDumpXml_withFilter() throws IOException { 678 File test = FileUtil.createTempFile("dumpxml", "xml"); 679 try { 680 PrintWriter out = new PrintWriter(test); 681 List<String> filters = new ArrayList<>(); 682 filters.add(Configuration.TEST_TYPE_NAME); 683 mConfig.dumpXml(out, filters); 684 out.flush(); 685 String content = FileUtil.readStringFromFile(test); 686 assertTrue(content.length() > 100); 687 assertTrue(content.contains("<configuration>")); 688 assertFalse(content.contains("<test class")); 689 } finally { 690 FileUtil.deleteFile(test); 691 } 692 } 693 694 /** 695 * Test that {@link Configuration#dumpXml(PrintWriter)} produce the xml output even for a multi 696 * device situation. 697 */ testDumpXml_multi_device()698 public void testDumpXml_multi_device() throws Exception { 699 List<IDeviceConfiguration> deviceObjectList = new ArrayList<IDeviceConfiguration>(); 700 deviceObjectList.add(new DeviceConfigurationHolder("device1")); 701 deviceObjectList.add(new DeviceConfigurationHolder("device2")); 702 mConfig.setConfigurationObjectList(Configuration.DEVICE_NAME, deviceObjectList); 703 File test = FileUtil.createTempFile("dumpxml", "xml"); 704 try { 705 PrintWriter out = new PrintWriter(test); 706 mConfig.dumpXml(out); 707 out.flush(); 708 String content = FileUtil.readStringFromFile(test); 709 assertTrue(content.length() > 100); 710 assertTrue(content.contains("<device name=\"device1\">")); 711 assertTrue(content.contains("<device name=\"device2\">")); 712 } finally { 713 FileUtil.deleteFile(test); 714 } 715 } 716 717 /** 718 * Test that {@link Configuration#dumpXml(PrintWriter)} produce the xml output even for a multi 719 * device situation when one of the device is fake. 720 */ testDumpXml_multi_device_fake()721 public void testDumpXml_multi_device_fake() throws Exception { 722 List<IDeviceConfiguration> deviceObjectList = new ArrayList<IDeviceConfiguration>(); 723 deviceObjectList.add(new DeviceConfigurationHolder("device1", true)); 724 deviceObjectList.add(new DeviceConfigurationHolder("device2")); 725 mConfig.setConfigurationObjectList(Configuration.DEVICE_NAME, deviceObjectList); 726 File test = FileUtil.createTempFile("dumpxml", "xml"); 727 try { 728 PrintWriter out = new PrintWriter(test); 729 mConfig.dumpXml(out); 730 out.flush(); 731 String content = FileUtil.readStringFromFile(test); 732 assertTrue(content.length() > 100); 733 assertTrue(content.contains("<device name=\"device1\" isFake=\"true\">")); 734 assertTrue(content.contains("<device name=\"device2\">")); 735 } finally { 736 FileUtil.deleteFile(test); 737 } 738 } 739 } 740