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