1 # Copyright 2016 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 """ 6 Unit tests for functions in `assign_stable_images`. 7 """ 8 9 10 import json 11 import mock 12 import os 13 import sys 14 import unittest 15 16 import common 17 from autotest_lib.server import frontend 18 from autotest_lib.site_utils.stable_images import assign_stable_images 19 20 21 # _OMAHA_TEST_DATA - File with JSON data to be used as test input to 22 # `_make_omaha_versions()`. In the file, the various items in the 23 # `omaha_data` list are selected to capture various specific test 24 # cases: 25 # + Board with no "beta" channel. 26 # + Board with "beta" and another channel. 27 # + Board with only a "beta" channel. 28 # + Board with no "chrome_version" entry. 29 # + Obsolete board with "is_active" set to false. 30 # The JSON content of the file is a subset of an actual 31 # `omaha_status.json` file copied when the unit test was last 32 # updated. 33 # 34 # _EXPECTED_OMAHA_VERSIONS - The expected output produced by 35 # _STUB_OMAHA_DATA. 36 # 37 _OMAHA_TEST_DATA = 'test_omaha_status.json' 38 39 _EXPECTED_OMAHA_VERSIONS = {'auron-paine': 'R55-8872.54.0', 40 'gale': 'R55-8872.40.9', 41 'kevin': 'R55-8872.64.0', 42 'zako-freon': 'R41-6680.52.0'} 43 44 _DEFAULT_BOARD = assign_stable_images._DEFAULT_BOARD 45 46 47 class OmahaDataTests(unittest.TestCase): 48 """Tests for the `_make_omaha_versions()` function.""" 49 50 def test_make_omaha_versions(self): 51 """ 52 Test `_make_omaha_versions()` against one simple input. 53 54 This is a trivial sanity test that confirms that a single 55 hard-coded input returns a correct hard-coded output. 56 """ 57 module_dir = os.path.dirname(sys.modules[__name__].__file__) 58 data_file_path = os.path.join(module_dir, _OMAHA_TEST_DATA) 59 omaha_versions = assign_stable_images._make_omaha_versions( 60 json.load(open(data_file_path, 'r'))) 61 self.assertEqual(omaha_versions, _EXPECTED_OMAHA_VERSIONS) 62 63 64 class KeyPathTests(unittest.TestCase): 65 """Tests for the `_get_by_key_path()` function.""" 66 67 DICTDICT = {'level0': 'OK', 'level1_a': {'level1_b': 'OK'}} 68 69 def _get_by_key_path(self, keypath): 70 get_by_key_path = assign_stable_images._get_by_key_path 71 return get_by_key_path(self.DICTDICT, keypath) 72 73 def _check_path_valid(self, keypath): 74 self.assertEqual(self._get_by_key_path(keypath), 'OK') 75 76 def _check_path_invalid(self, keypath): 77 self.assertIsNone(self._get_by_key_path(keypath)) 78 79 def test_one_element(self): 80 """Test a single-element key path with a valid key.""" 81 self._check_path_valid(['level0']) 82 83 def test_two_element(self): 84 """Test a two-element key path with a valid key.""" 85 self._check_path_valid(['level1_a', 'level1_b']) 86 87 def test_one_element_invalid(self): 88 """Test a single-element key path with an invalid key.""" 89 self._check_path_invalid(['absent']) 90 91 def test_two_element_invalid(self): 92 """Test a two-element key path with an invalid key.""" 93 self._check_path_invalid(['level1_a', 'absent']) 94 95 96 class GetFirmwareUpgradesTests(unittest.TestCase): 97 """Tests for _get_firmware_upgrades.""" 98 99 100 def setUp(self): 101 self.version_map = frontend._CrosVersionMap(mock.Mock()) 102 103 104 @mock.patch.object(assign_stable_images, 'get_firmware_versions') 105 def test_get_firmware_upgrades(self, mock_get_firmware_versions): 106 """Test _get_firmware_upgrades.""" 107 mock_get_firmware_versions.side_effect = [ 108 {'auron_paine': 'fw_version'}, 109 {'blue': 'fw_version', 110 'robo360': 'fw_version', 111 'porbeagle': 'fw_version'} 112 ] 113 cros_versions = { 114 'coral': 'R64-10176.65.0', 115 'auron_paine': 'R64-10176.65.0' 116 } 117 boards = ['auron_paine', 'coral'] 118 119 firmware_upgrades = assign_stable_images._get_firmware_upgrades( 120 self.version_map, cros_versions) 121 expected_firmware_upgrades = { 122 'auron_paine': 'fw_version', 123 'blue': 'fw_version', 124 'robo360': 'fw_version', 125 'porbeagle': 'fw_version' 126 } 127 self.assertEqual(firmware_upgrades, expected_firmware_upgrades) 128 129 130 class GetFirmwareVersionsTests(unittest.TestCase): 131 """Tests for get_firmware_versions.""" 132 133 134 def setUp(self): 135 self.version_map = frontend._CrosVersionMap(mock.Mock()) 136 self.cros_version = 'R64-10176.65.0' 137 138 139 @mock.patch.object(assign_stable_images, '_read_gs_json_data') 140 def test_get_firmware_versions_on_normal_build(self, mock_read_gs): 141 """Test get_firmware_versions on normal build.""" 142 metadata_json = """ 143 { 144 "unibuild": false, 145 "board-metadata":{ 146 "auron_paine":{ 147 "main-firmware-version":"Google_Auron_paine.6301.58.98" 148 } 149 } 150 } 151 """ 152 mock_read_gs.return_value = json.loads(metadata_json) 153 board = 'auron_paine' 154 155 fw_version = assign_stable_images.get_firmware_versions( 156 self.version_map, board, self.cros_version) 157 expected_version = {board: "Google_Auron_paine.6301.58.98"} 158 self.assertEqual(fw_version, expected_version) 159 160 161 @mock.patch.object(assign_stable_images, '_read_gs_json_data', 162 side_effect = Exception('GS ERROR')) 163 def test_get_firmware_versions_with_exceptions(self, mock_read_gs): 164 """Test get_firmware_versions on normal build with exceptions.""" 165 afe_mock = mock.Mock() 166 version_map = frontend._CrosVersionMap(afe_mock) 167 168 fw_version = assign_stable_images.get_firmware_versions( 169 self.version_map, 'auron_paine', self.cros_version) 170 self.assertEqual(fw_version, {'auron_paine': None}) 171 172 173 @mock.patch.object(assign_stable_images, '_read_gs_json_data') 174 def test_get_firmware_versions_on_unibuild(self, mock_read_gs): 175 """Test get_firmware_version on uni-build.""" 176 metadata_json = """ 177 { 178 "unibuild": true, 179 "board-metadata":{ 180 "coral":{ 181 "kernel-version":"4.4.114-r1354", 182 "models":{ 183 "blue":{ 184 "main-readonly-firmware-version":"Google_Coral.10068.37.0", 185 "main-readwrite-firmware-version":"Google_Coral.10068.39.0" 186 }, 187 "robo360":{ 188 "main-readonly-firmware-version":"Google_Coral.10068.34.0", 189 "main-readwrite-firmware-version":null 190 }, 191 "porbeagle":{ 192 "main-readonly-firmware-version":null, 193 "main-readwrite-firmware-version":null 194 } 195 } 196 } 197 } 198 } 199 """ 200 mock_read_gs.return_value = json.loads(metadata_json) 201 202 fw_version = assign_stable_images.get_firmware_versions( 203 self.version_map, 'coral', self.cros_version) 204 expected_version = { 205 'blue': 'Google_Coral.10068.39.0', 206 'robo360': 'Google_Coral.10068.34.0', 207 'porbeagle': None 208 } 209 self.assertEqual(fw_version, expected_version) 210 211 212 @mock.patch.object(assign_stable_images, '_read_gs_json_data') 213 def test_get_firmware_versions_on_unibuild_no_models(self, mock_read_gs): 214 """Test get_firmware_versions on uni-build without models dict.""" 215 metadata_json = """ 216 { 217 "unibuild": true, 218 "board-metadata":{ 219 "coral":{ 220 "kernel-version":"4.4.114-r1354" 221 } 222 } 223 } 224 """ 225 mock_read_gs.return_value = json.loads(metadata_json) 226 227 fw_version = assign_stable_images.get_firmware_versions( 228 self.version_map, 'coral', self.cros_version) 229 self.assertEqual(fw_version, {'coral': None}) 230 231 232 class GetUpgradeTests(unittest.TestCase): 233 """Tests for the `_get_upgrade_versions()` function.""" 234 235 # _VERSIONS - a list of sample version strings such as may be used 236 # for Chrome OS, sorted from oldest to newest. These are used to 237 # construct test data in multiple test cases, below. 238 _VERSIONS = ['R1-1.0.0', 'R1-1.1.0', 'R2-4.0.0'] 239 240 def test_board_conversions(self): 241 """ 242 Test proper mapping of names from the AFE to Omaha. 243 244 Board names in Omaha don't have '_' characters; when an AFE 245 board contains '_' characters, they must be converted to '-'. 246 247 Assert that for various forms of name in the AFE mapping, the 248 converted name is the one looked up in the Omaha mapping. 249 """ 250 board_equivalents = [ 251 ('a-b', 'a-b'), ('c_d', 'c-d'), 252 ('e_f-g', 'e-f-g'), ('hi', 'hi')] 253 afe_versions = { 254 _DEFAULT_BOARD: self._VERSIONS[0] 255 } 256 omaha_versions = {} 257 expected = {} 258 boards = set() 259 for afe_board, omaha_board in board_equivalents: 260 boards.add(afe_board) 261 afe_versions[afe_board] = self._VERSIONS[1] 262 omaha_versions[omaha_board] = self._VERSIONS[2] 263 expected[afe_board] = self._VERSIONS[2] 264 upgrades, _ = assign_stable_images._get_upgrade_versions( 265 afe_versions, omaha_versions, boards) 266 self.assertEqual(upgrades, expected) 267 268 def test_afe_default(self): 269 """ 270 Test that the AFE default board mapping is honored. 271 272 If a board isn't present in the AFE dictionary, the mapping 273 for `_DEFAULT_BOARD` should be used. 274 275 Primary assertions: 276 * When a board is present in the AFE mapping, its version 277 mapping is used. 278 * When a board is not present in the AFE mapping, the default 279 version mapping is used. 280 281 Secondarily, assert that when a mapping is absent from Omaha, 282 the AFE mapping is left unchanged. 283 """ 284 afe_versions = { 285 _DEFAULT_BOARD: self._VERSIONS[0], 286 'a': self._VERSIONS[1] 287 } 288 boards = set(['a', 'b']) 289 expected = { 290 'a': self._VERSIONS[1], 291 'b': self._VERSIONS[0] 292 } 293 upgrades, _ = assign_stable_images._get_upgrade_versions( 294 afe_versions, {}, boards) 295 self.assertEqual(upgrades, expected) 296 297 def test_omaha_upgrade(self): 298 """ 299 Test that upgrades from Omaha are detected. 300 301 Primary assertion: 302 * If a board is found in Omaha, and the version in Omaha is 303 newer than the AFE version, the Omaha version is the one 304 used. 305 306 Secondarily, asserts that version comparisons between various 307 specific version strings are all correct. 308 """ 309 boards = set(['a']) 310 for i in range(0, len(self._VERSIONS) - 1): 311 afe_versions = {_DEFAULT_BOARD: self._VERSIONS[i]} 312 for j in range(i+1, len(self._VERSIONS)): 313 omaha_versions = {b: self._VERSIONS[j] for b in boards} 314 upgrades, _ = assign_stable_images._get_upgrade_versions( 315 afe_versions, omaha_versions, boards) 316 self.assertEqual(upgrades, omaha_versions) 317 318 def test_no_upgrade(self): 319 """ 320 Test that if Omaha is behind the AFE, it is ignored. 321 322 Primary assertion: 323 * If a board is found in Omaha, and the version in Omaha is 324 older than the AFE version, the AFE version is the one used. 325 326 Secondarily, asserts that version comparisons between various 327 specific version strings are all correct. 328 """ 329 boards = set(['a']) 330 for i in range(1, len(self._VERSIONS)): 331 afe_versions = {_DEFAULT_BOARD: self._VERSIONS[i]} 332 expected = {b: self._VERSIONS[i] for b in boards} 333 for j in range(0, i): 334 omaha_versions = {b: self._VERSIONS[j] for b in boards} 335 upgrades, _ = assign_stable_images._get_upgrade_versions( 336 afe_versions, omaha_versions, boards) 337 self.assertEqual(upgrades, expected) 338 339 def test_ignore_unused_boards(self): 340 """ 341 Test that unlisted boards are ignored. 342 343 Assert that boards present in the AFE or Omaha mappings aren't 344 included in the return mappings when they aren't in the passed 345 in set of boards. 346 """ 347 unused_boards = set(['a', 'b']) 348 used_boards = set(['c', 'd']) 349 afe_versions = {b: self._VERSIONS[0] for b in unused_boards} 350 afe_versions[_DEFAULT_BOARD] = self._VERSIONS[1] 351 expected = {b: self._VERSIONS[1] for b in used_boards} 352 omaha_versions = expected.copy() 353 omaha_versions.update( 354 {b: self._VERSIONS[0] for b in unused_boards}) 355 upgrades, _ = assign_stable_images._get_upgrade_versions( 356 afe_versions, omaha_versions, used_boards) 357 self.assertEqual(upgrades, expected) 358 359 def test_default_unchanged(self): 360 """ 361 Test correct handling when the default build is unchanged. 362 363 Assert that if in Omaha, one board in a set of three upgrades 364 from the AFE default, that the returned default board mapping is 365 the original default in the AFE. 366 """ 367 boards = set(['a', 'b', 'c']) 368 afe_versions = {_DEFAULT_BOARD: self._VERSIONS[0]} 369 omaha_versions = {b: self._VERSIONS[0] for b in boards} 370 omaha_versions['c'] = self._VERSIONS[1] 371 _, new_default = assign_stable_images._get_upgrade_versions( 372 afe_versions, omaha_versions, boards) 373 self.assertEqual(new_default, self._VERSIONS[0]) 374 375 def test_default_upgrade(self): 376 """ 377 Test correct handling when the default build must change. 378 379 Assert that if in Omaha, two boards in a set of three upgrade 380 from the AFE default, that the returned default board mapping is 381 the new build in Omaha. 382 """ 383 boards = set(['a', 'b', 'c']) 384 afe_versions = {_DEFAULT_BOARD: self._VERSIONS[0]} 385 omaha_versions = {b: self._VERSIONS[1] for b in boards} 386 omaha_versions['c'] = self._VERSIONS[0] 387 _, new_default = assign_stable_images._get_upgrade_versions( 388 afe_versions, omaha_versions, boards) 389 self.assertEqual(new_default, self._VERSIONS[1]) 390 391 392 # Sample version string values to be used when testing 393 # `_apply_upgrades()`. 394 # 395 # _OLD_DEFAULT - Test value representing the default version mapping 396 # in the `old_versions` dictionary in a call to `_apply_upgrades()`. 397 # _NEW_DEFAULT - Test value representing the default version mapping 398 # in the `new_versions` dictionary when a version update is being 399 # tested. 400 # _OLD_VERSION - Test value representing an arbitrary version for a 401 # board that is mapped in the `old_versions` dictionary in a call to 402 # `_apply_upgrades()`. 403 # _NEW_VERSION - Test value representing an arbitrary version for a 404 # board that is mapped in the `new_versions` dictionary in a call to 405 # `_apply_upgrades()`. 406 # 407 _OLD_DEFAULT = 'old-default-version' 408 _NEW_DEFAULT = 'new-default-version' 409 _OLD_VERSION = 'old-board-version' 410 _NEW_VERSION = 'new-board-version' 411 412 413 class _StubAFE(object): 414 """Stubbed out version of `server.frontend.AFE`.""" 415 416 CROS_IMAGE_TYPE = 'cros-image-type' 417 FIRMWARE_IMAGE_TYPE = 'firmware-image-type' 418 419 def get_stable_version_map(self, image_type): 420 return image_type 421 422 423 class _TestUpdater(assign_stable_images._VersionUpdater): 424 """ 425 Subclass of `_VersionUpdater` for testing. 426 427 This class extends `_VersionUpdater` to provide support for testing 428 various assertions about the behavior of the base class and its 429 interactions with `_apply_cros_upgrades()` and 430 `_apply_firmware_upgrades()`. 431 432 The class tests assertions along the following lines: 433 * When applied to the original mappings, the calls to 434 `_do_set_mapping()` and `_do_delete_mapping()` create the 435 expected final mapping state. 436 * Calls to report state changes are made with the expected 437 values. 438 * There's a one-to-one match between reported and actually 439 executed changes. 440 441 """ 442 443 def __init__(self, testcase): 444 super(_TestUpdater, self).__init__(_StubAFE()) 445 self._testcase = testcase 446 self._default_changed = None 447 self._reported_mappings = None 448 self._updated_mappings = None 449 self._reported_deletions = None 450 self._actual_deletions = None 451 self._original_mappings = None 452 self._mappings = None 453 self._expected_mappings = None 454 self._unchanged_boards = None 455 456 def pretest_init(self, initial_versions, expected_versions): 457 """ 458 Initialize for testing. 459 460 @param initial_versions Mappings to be used as the starting 461 point for testing. 462 @param expected_versions The expected final value of the 463 mappings after the test. 464 """ 465 self._default_changed = False 466 self._reported_mappings = {} 467 self._updated_mappings = {} 468 self._reported_deletions = set() 469 self._actual_deletions = set() 470 self._original_mappings = initial_versions.copy() 471 self._mappings = initial_versions.copy() 472 self._expected_mappings = expected_versions 473 self._unchanged_boards = set() 474 475 def check_results(self, change_default): 476 """ 477 Assert that observed changes match expectations. 478 479 Asserts the following: 480 * The `report_default_changed()` method was called (or not) 481 based on whether `change_default` is true (or not). 482 * The changes reported via `_report_board_changed()` match 483 the changes actually applied. 484 * The final mappings after applying requested changes match 485 the actually expected mappings. 486 487 @param old_versions Parameter to be passed to 488 `_apply_cros_upgrades()`. 489 @param new_versions Parameter to be passed to 490 `_apply_cros_upgrades()`. 491 @param change_default Whether the test should include a change 492 to the default version mapping. 493 """ 494 self._testcase.assertEqual(change_default, 495 self._default_changed) 496 self._testcase.assertEqual(self._reported_mappings, 497 self._updated_mappings) 498 self._testcase.assertEqual(self._reported_deletions, 499 self._actual_deletions) 500 self._testcase.assertEqual(self._mappings, 501 self._expected_mappings) 502 503 def report(self, message): 504 """Report message.""" 505 pass 506 507 def report_default_changed(self, old_default, new_default): 508 """ 509 Override of our parent class' method for test purposes. 510 511 Saves a record of the report for testing the final result in 512 `apply_upgrades()`, above. 513 514 Assert the following: 515 * The old and new default values match the values that 516 were passed in the original call's arguments. 517 * This function is not being called for a second time. 518 519 @param old_default The original default version. 520 @param new_default The new default version to be applied. 521 """ 522 self._testcase.assertNotEqual(old_default, new_default) 523 self._testcase.assertEqual(old_default, 524 self._original_mappings[_DEFAULT_BOARD]) 525 self._testcase.assertEqual(new_default, 526 self._expected_mappings[_DEFAULT_BOARD]) 527 self._testcase.assertFalse(self._default_changed) 528 self._default_changed = True 529 self._reported_mappings[_DEFAULT_BOARD] = new_default 530 531 def _report_board_changed(self, board, old_version, new_version): 532 """ 533 Override of our parent class' method for test purposes. 534 535 Saves a record of the report for testing the final result in 536 `apply_upgrades()`, above. 537 538 Assert the following: 539 * The change being reported actually reports two different 540 versions. 541 * If the board isn't mapped to the default version, then the 542 reported old version is the actually mapped old version. 543 * If the board isn't changing to the default version, then the 544 reported new version is the expected new version. 545 * This is not a second report for this board. 546 547 The implementation implicitly requires that the specified board 548 have a valid mapping. 549 550 @param board The board with the changing version. 551 @param old_version The original version mapped to the board. 552 @param new_version The new version to be applied to the board. 553 """ 554 self._testcase.assertNotEqual(old_version, new_version) 555 if board in self._original_mappings: 556 self._testcase.assertEqual(old_version, 557 self._original_mappings[board]) 558 if board in self._expected_mappings: 559 self._testcase.assertEqual(new_version, 560 self._expected_mappings[board]) 561 self._testcase.assertNotIn(board, self._reported_mappings) 562 self._reported_mappings[board] = new_version 563 else: 564 self._testcase.assertNotIn(board, self._reported_deletions) 565 self._reported_deletions.add(board) 566 567 def report_board_unchanged(self, board, old_version): 568 """ 569 Override of our parent class' method for test purposes. 570 571 Assert the following: 572 * The version being reported as unchanged is actually mapped. 573 * The reported old version matches the expected value. 574 * This is not a second report for this board. 575 576 @param board The board that is not changing. 577 @param old_version The board's version mapping. 578 """ 579 self._testcase.assertIn(board, self._original_mappings) 580 self._testcase.assertEqual(old_version, 581 self._original_mappings[board]) 582 self._testcase.assertNotIn(board, self._unchanged_boards) 583 self._unchanged_boards.add(board) 584 585 def _do_set_mapping(self, board, new_version): 586 """ 587 Override of our parent class' method for test purposes. 588 589 Saves a record of the change for testing the final result in 590 `apply_upgrades()`, above. 591 592 Assert the following: 593 * This is not a second change for this board. 594 * If we're changing the default mapping, then every board 595 that will be changing to a non-default mapping has been 596 updated. 597 598 @param board The board with the changing version. 599 @param new_version The new version to be applied to the board. 600 """ 601 self._mappings[board] = new_version 602 self._testcase.assertNotIn(board, self._updated_mappings) 603 self._updated_mappings[board] = new_version 604 if board == _DEFAULT_BOARD: 605 for board in self._expected_mappings: 606 self._testcase.assertIn(board, self._mappings) 607 608 def _do_delete_mapping(self, board): 609 """ 610 Override of our parent class' method for test purposes. 611 612 Saves a record of the change for testing the final result in 613 `apply_upgrades()`, above. 614 615 Assert that the board has a mapping prior to deletion. 616 617 @param board The board with the version to be deleted. 618 """ 619 self._testcase.assertNotEqual(board, _DEFAULT_BOARD) 620 self._testcase.assertIn(board, self._mappings) 621 del self._mappings[board] 622 self._actual_deletions.add(board) 623 624 625 class ApplyCrOSUpgradesTests(unittest.TestCase): 626 """Tests for the `_apply_cros_upgrades()` function.""" 627 628 def _apply_upgrades(self, old_versions, new_versions, change_default): 629 """ 630 Test a single call to `_apply_cros_upgrades()`. 631 632 All assertions are handled by an instance of `_TestUpdater`. 633 634 @param old_versions Parameter to be passed to 635 `_apply_cros_upgrades()`. 636 @param new_versions Parameter to be passed to 637 `_apply_cros_upgrades()`. 638 @param change_default Whether the test should include a change 639 to the default version mapping. 640 """ 641 old_versions[_DEFAULT_BOARD] = _OLD_DEFAULT 642 if change_default: 643 new_default = _NEW_DEFAULT 644 else: 645 new_default = _OLD_DEFAULT 646 expected_versions = { 647 b: v for b, v in new_versions.items() if v != new_default 648 } 649 expected_versions[_DEFAULT_BOARD] = new_default 650 updater = _TestUpdater(self) 651 updater.pretest_init(old_versions, expected_versions) 652 assign_stable_images._apply_cros_upgrades( 653 updater, old_versions, new_versions, new_default) 654 updater.check_results(change_default) 655 656 def test_no_changes(self): 657 """ 658 Test an empty upgrade that does nothing. 659 660 Test the boundary case of an upgrade where there are no boards, 661 and the default does not change. 662 """ 663 self._apply_upgrades({}, {}, False) 664 665 def test_change_default(self): 666 """ 667 Test an empty upgrade that merely changes the default. 668 669 Test the boundary case of an upgrade where there are no boards, 670 but the default is upgraded. 671 """ 672 self._apply_upgrades({}, {}, True) 673 674 def test_board_default_no_changes(self): 675 """ 676 Test that a board at default stays with an unchanged default. 677 678 Test the case of a board that is mapped to the default, where 679 neither the board nor the default change. 680 """ 681 self._apply_upgrades({}, {'board': _OLD_DEFAULT}, False) 682 683 def test_board_left_behind(self): 684 """ 685 Test a board left at the old default after a default upgrade. 686 687 Test the case of a board that stays mapped to the old default as 688 the default board is upgraded. 689 """ 690 self._apply_upgrades({}, {'board': _OLD_DEFAULT}, True) 691 692 def test_board_upgrade_from_default(self): 693 """ 694 Test upgrading a board from a default that doesn't change. 695 696 Test the case of upgrading a board from default to non-default, 697 where the default doesn't change. 698 """ 699 self._apply_upgrades({}, {'board': _NEW_VERSION}, False) 700 701 def test_board_and_default_diverge(self): 702 """ 703 Test upgrading a board that diverges from the default. 704 705 Test the case of upgrading a board and default together from the 706 same to different versions. 707 """ 708 self._apply_upgrades({}, {'board': _NEW_VERSION}, True) 709 710 def test_board_tracks_default(self): 711 """ 712 Test upgrading a board to track a default upgrade. 713 714 Test the case of upgrading a board and the default together. 715 """ 716 self._apply_upgrades({}, {'board': _NEW_DEFAULT}, True) 717 718 def test_board_non_default_no_changes(self): 719 """ 720 Test an upgrade with no changes to a board or the default. 721 722 Test the case of an upgrade with a board in it, where neither 723 the board nor the default change. 724 """ 725 self._apply_upgrades({'board': _NEW_VERSION}, 726 {'board': _NEW_VERSION}, 727 False) 728 729 def test_board_upgrade_and_keep_default(self): 730 """ 731 Test a board upgrade with an unchanged default. 732 733 Test the case of upgrading a board while the default stays the 734 same. 735 """ 736 self._apply_upgrades({'board': _OLD_VERSION}, 737 {'board': _NEW_VERSION}, 738 False) 739 740 def test_board_upgrade_and_change_default(self): 741 """ 742 Test upgrading a board and the default separately. 743 744 Test the case of upgrading both a board and the default, each 745 from and to different versions. 746 """ 747 self._apply_upgrades({'board': _OLD_VERSION}, 748 {'board': _NEW_VERSION}, 749 True) 750 751 def test_board_leads_default(self): 752 """ 753 Test a board that upgrades ahead of the new default. 754 755 Test the case of upgrading both a board and the default, where 756 the board's old version is the new default version. 757 """ 758 self._apply_upgrades({'board': _NEW_DEFAULT}, 759 {'board': _NEW_VERSION}, 760 True) 761 762 def test_board_lags_to_old_default(self): 763 """ 764 Test a board that upgrades behind the old default. 765 766 Test the case of upgrading both a board and the default, where 767 the board's new version is the old default version. 768 """ 769 self._apply_upgrades({'board': _OLD_VERSION}, 770 {'board': _OLD_DEFAULT}, 771 True) 772 773 def test_board_joins_old_default(self): 774 """ 775 Test upgrading a board to a default that doesn't change. 776 777 Test the case of upgrading board to the default, where the 778 default mapping stays unchanged. 779 """ 780 self._apply_upgrades({'board': _OLD_VERSION}, 781 {'board': _OLD_DEFAULT}, 782 False) 783 784 def test_board_joins_new_default(self): 785 """ 786 Test upgrading a board to match the new default. 787 788 Test the case of upgrading board and the default to the same 789 version. 790 """ 791 self._apply_upgrades({'board': _OLD_VERSION}, 792 {'board': _NEW_DEFAULT}, 793 True) 794 795 def test_board_becomes_default(self): 796 """ 797 Test a board that becomes default after a default upgrade. 798 799 Test the case of upgrading the default to a version already 800 mapped for an existing board. 801 """ 802 self._apply_upgrades({'board': _NEW_DEFAULT}, 803 {'board': _NEW_DEFAULT}, 804 True) 805 806 807 class ApplyFirmwareUpgradesTests(unittest.TestCase): 808 """Tests for the `_apply_firmware_upgrades()` function.""" 809 810 def _apply_upgrades(self, old_versions, new_versions): 811 """ 812 Test a single call to `_apply_firmware_upgrades()`. 813 814 All assertions are handled by an instance of `_TestUpdater`. 815 816 @param old_versions Parameter to be passed to 817 `_apply_firmware_upgrades()`. 818 @param new_versions Parameter to be passed to 819 `_apply_firmware_upgrades()`. 820 """ 821 updater = _TestUpdater(self) 822 updater.pretest_init(old_versions, new_versions) 823 assign_stable_images._apply_firmware_upgrades( 824 updater, old_versions, new_versions) 825 updater.check_results(False) 826 827 def test_no_changes(self): 828 """ 829 Test an empty upgrade that does nothing. 830 831 Test the boundary case of an upgrade where there are no boards. 832 """ 833 self._apply_upgrades({}, {}) 834 835 def test_board_added(self): 836 """ 837 Test an upgrade that adds a new board. 838 839 Test the case of an upgrade where a board that was previously 840 unmapped is added. 841 """ 842 self._apply_upgrades({}, {'board': _NEW_VERSION}) 843 844 def test_board_unchanged(self): 845 """ 846 Test an upgrade with no changes to a board. 847 848 Test the case of an upgrade with a board that stays the same. 849 """ 850 self._apply_upgrades({'board': _NEW_VERSION}, 851 {'board': _NEW_VERSION}) 852 853 def test_board_upgrade_and_change_default(self): 854 """ 855 Test upgrading a board. 856 857 Test the case of upgrading a board to a new version. 858 """ 859 self._apply_upgrades({'board': _OLD_VERSION}, 860 {'board': _NEW_VERSION}) 861 862 863 if __name__ == '__main__': 864 unittest.main() 865