1# Copyright 2019 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 5import logging 6import operator 7import re 8import sys 9import xmlrpclib 10 11from autotest_lib.client.common_lib import error 12from autotest_lib.client.common_lib.cros import chip_utils 13from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 14 15 16NO_ARGS = tuple() 17ONE_INT_ARG = (1, ) 18ONE_STR_ARG = ("foo", ) 19SAMPLE_FILE = "/tmp/foo" 20CHIP_FW_NAMES = (chip.fw_name for chip in chip_utils.chip_id_map.itervalues()) 21SAMPLE_CGPT_A = { 22 "UUID": "93EF7B23-606B-014B-A10C-E9D7CF53DFD3", 23 "successful": 1, 24 "partition": 2, 25 "priority": 1, 26 "tries": 0, 27 "Type": "ChromeOS kernel", 28} 29SAMPLE_CGPT_B = { 30 "UUID": "C6604D6B-5563-EE4E-9915-0C50530B158A", 31 "successful": 0, 32 "partition": 4, 33 "priority": 0, 34 "tries": 15, 35 "Type": "ChromeOS kernel", 36} 37 38# RPC_CATEGORIES contains the test cases for all RPCs. 39# For readability, the real definition is at the bottom of this file. 40RPC_CATEGORIES = [{}] 41 42 43def get_rpc_category_by_name(name): 44 """Find a category from RPC_CATEGORIES by its category_name.""" 45 for rpc_category in RPC_CATEGORIES: 46 if rpc_category["category_name"] == name: 47 return rpc_category 48 raise ValueError("No RPC category defined with category_name=%s" % name) 49 50 51def get_rpc_method_names_from_test_case(test_case): 52 """ 53 Extract the method_name or method_names from a test case configuration. 54 55 @param test_case: An element from a test_cases array, 56 like those in RPC_CATEGORIES 57 58 @return: A list of names of RPC methods in that test case. 59 60 """ 61 if (("method_name" in test_case) ^ ("method_names" in test_case)): 62 if "method_name" in test_case: 63 return [test_case["method_name"]] 64 elif "method_names" in test_case: 65 return test_case["method_names"] 66 else: 67 err_msg = "Something strange happened while parsing RPC methods" 68 raise ValueError(err_msg) 69 else: 70 err_msg = "test_case must contain EITHER method_name OR method_names" 71 raise ValueError(err_msg) 72 73 74 75class firmware_FAFTRPC(FirmwareTest): 76 """ 77 This test checks that all RPC commands work as intended. 78 79 For now, we only need to verify that the RPC framework is intact, 80 so we only verify that all RPCs can be called with the 81 expected arguments. 82 83 It would be good to expand this test to verify that all RPCs 84 yields the expected results. 85 86 """ 87 version = 1 88 _stored_values = {} 89 90 91 def initialize(self, host, cmdline_args, dev_mode=False): 92 """Runs before test begins.""" 93 super(firmware_FAFTRPC, self).initialize(host, cmdline_args) 94 self.backup_firmware() 95 self.faft_client.rpc_settings.enable_test_mode() 96 97 98 def cleanup(self): 99 """Runs after test completion.""" 100 self.faft_client.rpc_settings.disable_test_mode() 101 try: 102 if self.is_firmware_saved(): 103 self.restore_firmware() 104 if self.reboot_after_completion: 105 logging.info("Rebooting DUT, as specified in control file") 106 self.switcher.mode_aware_reboot() 107 except Exception as e: 108 logging.error("Caught exception: %s", str(e)) 109 super(firmware_FAFTRPC, self).cleanup() 110 111 112 def _log_success(self, rpc_name, params, success_message): 113 """Report on an info level that a test passed.""" 114 logging.info("RPC test for %s%s successfully %s", 115 rpc_name, params, success_message) 116 117 118 def _fail(self, rpc_name, params, error_msg): 119 """Raise a TestFail error explaining why a test failed.""" 120 raise error.TestFail("RPC function %s%s had an unexpected result: %s" 121 % (rpc_name, params, error_msg)) 122 123 124 def _retrieve_stored_values(self, params): 125 """ 126 Replace any operator.itemgetter params with corresponding stored values. 127 128 @param params: A tuple of args that might be passed into an RPC method, 129 some of which might be operator.itemgetter objects. 130 131 @return: A tuple of pargs to be passed into an RPC method, 132 with stored values swapped in for operator.itemgetters. 133 134 """ 135 new_params = [] 136 for old_param in params: 137 if isinstance(old_param, operator.itemgetter): 138 retrieved_value = old_param(self._stored_values) 139 new_params.append(retrieved_value) 140 else: 141 new_params.append(old_param) 142 new_params = tuple(new_params) 143 return new_params 144 145 146 def _assert_passes(self, category, method, params, allow_error_msg=None, 147 expected_return_type=None, silence_result=False): 148 """ 149 Check whether an RPC function with given input passes, 150 and fail if it does not. 151 152 If an expected_return_type is passed in, then require the RPC function 153 to return a value matching that type, or else fail. 154 155 @param category: The RPC subsystem category; ex. kernel, bios 156 @param method: The name of the RPC function within the subsystem 157 @param params: A tuple containing params to pass into the RPC function 158 @param allow_error_msg: If a regexy string is passed in, and the RPC 159 returns an RPC error matching this regex, 160 then the test will pass instead of failing. 161 @param expected_return_type: If not None, then the RPC return value 162 must be this type, else the test fails. 163 @param silence_result: If True, then the RPC return value will not be 164 logged. 165 166 @raise error.TestFail: If the RPC raises any error (unless handled by 167 allow_error_msg). 168 @raise error.TestFail: If expected_return_type is not None, and the RPC 169 return value is not expected_return_type. 170 171 @return: Not meaningful. 172 173 """ 174 rpc_function = self.get_rpc_function(category, method) 175 if category: 176 rpc_name = '%s.%s' % (category, method) 177 else: 178 rpc_name = method 179 try: 180 result = rpc_function(*params) 181 except xmlrpclib.Fault as e: 182 if allow_error_msg is not None and \ 183 re.search(allow_error_msg, str(e)): 184 success_msg = "raised an acceptable error during RPC handling" 185 self._log_success(rpc_name, params, success_msg) 186 return e 187 error_msg = "Unexpected RPC error: %s" % e 188 self._fail(rpc_name, params, error_msg) 189 except: 190 error_msg = "Unexpected misc error: %s" % sys.exc_info()[0] 191 self._fail(rpc_name, params, error_msg) 192 else: 193 if expected_return_type is None: 194 if silence_result: 195 success_msg = "passed with a silenced result" 196 else: 197 success_msg = "passed with result %s" % result 198 self._log_success(rpc_name, params, success_msg) 199 return result 200 elif isinstance(result, expected_return_type): 201 if silence_result: 202 success_msg = "passed with a silenced result of " \ 203 "expected type %s" % type(result) 204 else: 205 success_msg = "passed with result %s of expected type %s" \ 206 % (result, type(result)) 207 self._log_success(rpc_name, params, success_msg) 208 return result 209 else: 210 error_msg = ("Expected a result of type %s, but got %s " + 211 "of type %s)") \ 212 % (expected_return_type, result, type(result)) 213 self._fail(rpc_name, params, error_msg) 214 215 216 def _assert_fails(self, category, method, params): 217 """ 218 Check whether an RPC function with given input throws an RPC error, 219 and fail if it does not. 220 221 @param category: The RPC subsystem category; ex. kernel, bios 222 @param method: The name of the RPC function within the subsystem 223 @param params: A tuple containing params to pass into the RPC function 224 225 @raise error.TestFail: If the RPC raises no error, or if it raises any 226 error other than xmlrpclib.Fault 227 228 @return: Not meaningful. 229 230 """ 231 rpc_function = self.get_rpc_function(category, method) 232 if category: 233 rpc_name = '%s.%s' % (category, method) 234 else: 235 rpc_name = method 236 try: 237 result = rpc_function(*params) 238 except xmlrpclib.Fault as e: 239 self._log_success(rpc_name, params, "raised RPC error") 240 except: 241 error_msg = "Unexpected misc error: %s" % sys.exc_info()[0] 242 self._fail(rpc_name, params, error_msg) 243 else: 244 error_msg = "Should have raised an RPC error, but did not" 245 self._fail(rpc_name, params, error_msg) 246 247 248 def _assert_output(self, category, method, params, expected_output, 249 allow_error_msg=None): 250 """ 251 Check whether an RPC function with given input 252 returns a particular value, and fail if it does not. 253 254 @param category: The RPC subsystem category; ex. kernel, bios 255 @param method: The name of the RPC function within the subsystem 256 @param params: A tuple containing params to pass into the RPC function 257 @param expected_output: The value that the RPC function should return 258 @param allow_error_msg: If a regexy string is passed in, and the RPC 259 returns an RPC error containing this string, 260 then the test will pass instead of failing. 261 262 @raise error.TestFail: If self._assert_passes(...) fails, or if the 263 RPC return value does not match expected_output 264 265 @return: Not meaningful. 266 267 """ 268 rpc_name = ".".join([category, method]) 269 actual_output = self._assert_passes(category, method, params, 270 allow_error_msg=allow_error_msg) 271 if expected_output == actual_output: 272 success_message = "returned the expected value <%s>" \ 273 % expected_output 274 self._log_success(rpc_name, params, success_message) 275 else: 276 error_msg = "Expected output <%s>, but actually returned <%s>" \ 277 % (expected_output, actual_output) 278 self._fail(rpc_name, params, error_msg) 279 280 281 def get_rpc_function(self, category, method): 282 """ 283 Find a callable RPC function given its name. 284 285 @param category: The name of an RPC subsystem category; ex. kernel, ec 286 @param method: The name of an RPC function within the subsystem 287 288 @return: A callable method of the RPC proxy 289 """ 290 if category: 291 rpc_function_handler = getattr(self.faft_client, category) 292 else: 293 rpc_function_handler = self.faft_client 294 rpc_function = getattr(rpc_function_handler, method) 295 return rpc_function 296 297 298 def run_once(self, category_under_test="*", reboot_after_completion=False): 299 """ 300 Main test logic. 301 302 For all RPC categories being tested, 303 iterate through all test cases defined in RPC_CATEGORIES. 304 305 @param category_under_test: The name of an RPC category to be tested, 306 such as ec, bios, or kernel. 307 Default is '*', which tests all categories. 308 309 """ 310 if category_under_test == "*": 311 logging.info("Testing all %d RPC categories", len(RPC_CATEGORIES)) 312 rpc_categories_to_test = RPC_CATEGORIES 313 else: 314 rpc_categories_to_test = [ 315 get_rpc_category_by_name(category_under_test)] 316 logging.info("Testing RPC category '%s'", category_under_test) 317 self.reboot_after_completion = reboot_after_completion 318 for rpc_category in rpc_categories_to_test: 319 category_name = rpc_category["category_name"] 320 if category_name == "ec" and not self.check_ec_capability(): 321 logging.info("No EC found on DUT. Skipping EC category.") 322 continue 323 324 # Re-enable test mode, in case another category's tests disabled it. 325 self.faft_client.rpc_settings.enable_test_mode() 326 327 test_cases = rpc_category["test_cases"] 328 logging.info("Testing %d cases for RPC category %s", 329 len(test_cases), repr(category_name)) 330 for test_case in test_cases: 331 method_names = get_rpc_method_names_from_test_case(test_case) 332 passing_args = test_case.get("passing_args", []) 333 failing_args = test_case.get("failing_args", []) 334 allow_error_msg = test_case.get("allow_error_msg", None) 335 expected_return_type = test_case.get("expected_return_type", 336 None) 337 store_result_as = test_case.get("store_result_as", None) 338 silence_result = test_case.get("silence_result", False) 339 for method_name in method_names: 340 for passing_arg_tuple in passing_args: 341 passing_arg_tuple = self._retrieve_stored_values( 342 passing_arg_tuple) 343 result = self._assert_passes(category_name, method_name, 344 passing_arg_tuple, 345 allow_error_msg, 346 expected_return_type, 347 silence_result) 348 if store_result_as is not None: 349 self._stored_values[store_result_as] = result 350 for failing_arg_tuple in failing_args: 351 failing_arg_tuple = self._retrieve_stored_values( 352 failing_arg_tuple) 353 self._assert_fails(category_name, method_name, 354 failing_arg_tuple) 355 356 357""" 358RPC_CATEGORIES contains all the test cases for our RPC tests. 359Each element of RPC_CATEGORIES must be a dict containing the following keys: 360 361@key category_name: A string naming the RPC category, such as bios or kernel. 362@key test_cases: A list of test cases, each of which must be a dict containing 363 the following keys: 364 @key method_name (optional): A string naming an RPC method within 365 this category. Either this key or method_names 366 is required (but not both). 367 @key method_names (optional): An array of strings naming RPC methods within 368 this category. Either this key or method_name 369 is required (but not both). 370 @key passing_args: A list of tuples, each of which could be unpacked and 371 then passed into the RPC method as a valid set of 372 parameters. Each tuple might contain instances of 373 operator.itemgetter. If so, those instances will be 374 replaced with values from firmware_FAFTRPC._stored_values 375 before being passed into the RPC method. 376 @key failing_args: A list of tuples, each of which could be unpacked and 377 then passed into the RPC method as a set of parameters 378 which should yield an RPC error. Each tuple might contain 379 instances of operator.itemgetter. If so, those instances 380 will be replaced with values from 381 firmware_FAFTRPC._stored_values before being passed into 382 the RPC method. 383 @key silence_result: Normally, the RPC return value is logged. However, if 384 this key is truthy, then the result is not logged. 385 @key allow_error_msg (optional): String representing a regex pattern. 386 If the RPC method is called with a 387 passing_args tuple, but it yields an RPC 388 error whose message is matched by 389 re.search(allow_error_msg, error_msg), 390 then the test will be considered a pass. 391 @key store_result_as (optional): String. If this field is specified, then 392 the result from the RPC call will be stored 393 in firmware_FAFTRPC._stored_values. This 394 allows us to later reference the result 395 via an operator.itemgetter, as described 396 above in the docstrings for passing_args 397 and failing_args. 398 399""" 400RPC_CATEGORIES = [ 401 { 402 "category_name": 403 "system", 404 "test_cases": [ 405 { 406 "method_names": [ 407 "is_available", 408 "get_platform_name", 409 "get_model_name", 410 "dev_tpm_present", 411 "get_root_dev", 412 "get_root_part", 413 "get_fw_vboot2", 414 "request_recovery_boot", 415 "is_removable_device_boot", 416 "get_internal_device", 417 ], 418 "passing_args": [NO_ARGS], 419 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 420 }, 421 { 422 "method_name": "dump_log", 423 "passing_args": [ 424 NO_ARGS, 425 (True, ), 426 (False, ), 427 ], 428 "failing_args": [ 429 (True, False), 430 ], 431 "expected_return_type": str, 432 "silence_result": True, 433 }, 434 { 435 "method_name": 436 "run_shell_command", 437 "passing_args": [("ls -l", ), ("ls -l", False), 438 ("ls -l", True)], 439 "failing_args": [ 440 NO_ARGS, 441 ("ls", "-l", 'foo'), 442 ], 443 }, 444 { 445 "method_name": "run_shell_command_get_status", 446 "passing_args": [ 447 ("ls", ), 448 ], 449 "failing_args": [ 450 NO_ARGS, 451 ("ls", "-l", 'foo'), 452 ], 453 }, 454 { 455 "method_name": "run_shell_command_get_status", 456 "passing_args": [ 457 ("ls ''", ), 458 ], 459 }, 460 { 461 "method_name": "run_shell_command", 462 "failing_args": [ 463 ("ls ''", ), 464 ], 465 }, 466 { 467 "method_name": 468 "run_shell_command_check_output", 469 "passing_args": [ 470 ("ls -l", "total"), 471 ], 472 "failing_args": [ 473 NO_ARGS, 474 ], 475 }, 476 { 477 "method_name": "run_shell_command_get_output", 478 "passing_args": [ 479 ("ls -l", True), 480 ], 481 "failing_args": [ 482 NO_ARGS, 483 ], 484 }, 485 { 486 "method_name": "get_crossystem_value", 487 "passing_args": [ 488 ("fwid", ), 489 ], 490 "failing_args": [NO_ARGS], 491 }, 492 { 493 "method_name": "set_try_fw_b", 494 "passing_args": [ 495 NO_ARGS, 496 (1, ), 497 ], 498 "failing_args": [ 499 (1, 1), 500 ], 501 }, 502 { 503 "method_name": "set_fw_try_next", 504 "passing_args": [ 505 ("A", ), 506 ("A", 1), 507 ], 508 "failing_args": [ 509 NO_ARGS, 510 ("A", 1, "B"), 511 ], 512 }, 513 { 514 "method_name": "get_dev_boot_usb", 515 "passing_args": [NO_ARGS], 516 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 517 "store_result_as": "dev_boot_usb", 518 }, 519 { 520 "method_name": 521 "set_dev_boot_usb", 522 "passing_args": [ 523 (operator.itemgetter("dev_boot_usb"), 524 ), 525 ], 526 "failing_args": [ 527 NO_ARGS, 528 (True, False), 529 ], 530 }, 531 { 532 "method_name": "create_temp_dir", 533 "passing_args": [ 534 NO_ARGS, 535 ONE_STR_ARG, 536 ], 537 "failing_args": [ 538 ONE_INT_ARG, 539 ("foo", "bar"), 540 ], 541 "expected_return_type": str, 542 "store_result_as": "temp_dir", 543 }, 544 { 545 "method_name": "remove_file", 546 "passing_args": [ 547 (SAMPLE_FILE, ), 548 ], 549 "failing_args": [ 550 NO_ARGS, 551 (1, 2), 552 ], 553 }, 554 { 555 "method_name": "remove_dir", 556 "passing_args": [ 557 (operator.itemgetter("temp_dir"), ), 558 ], 559 "failing_args": [ 560 NO_ARGS, 561 (1, 2), 562 ] 563 }, 564 { 565 "method_name": "check_keys", 566 "passing_args": [ 567 ([], ), 568 ([116], ), 569 ([28, 29, 32], ), 570 ], 571 "failing_args": [ 572 NO_ARGS, 573 ([], [116]), 574 ], 575 "expected_return_type": int, 576 }, 577 ] 578 }, 579 { 580 "category_name": 581 "bios", 582 "test_cases": [ 583 { 584 "method_names": [ 585 "reload", 586 ], 587 "passing_args": [NO_ARGS], 588 "failing_args": [ONE_INT_ARG, ONE_STR_ARG] 589 }, 590 { 591 "method_name": "get_gbb_flags", 592 "passing_args": [NO_ARGS], 593 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 594 "expected_return_type": int, 595 "store_result_as": "gbb_flags", 596 }, 597 { 598 "method_name": "set_gbb_flags", 599 "passing_args": [ 600 (operator.itemgetter("gbb_flags"), ), 601 ], 602 "failing_args": [NO_ARGS], 603 }, 604 { 605 "method_name": "get_preamble_flags", 606 "passing_args": [ 607 ("a", ), 608 ], 609 "failing_args": [NO_ARGS, ONE_INT_ARG], 610 "store_result_as": "preamble_flags", 611 }, 612 { 613 "method_name": 614 "set_preamble_flags", 615 "passing_args": [ 616 ( 617 "a", 618 operator.itemgetter( 619 "preamble_flags"), 620 ), 621 ], 622 "failing_args": [ 623 NO_ARGS, 624 ONE_INT_ARG, 625 ONE_STR_ARG, 626 ( 627 "c", 628 operator.itemgetter( 629 "preamble_flags"), 630 ), 631 ], 632 }, 633 { 634 "method_names": [ 635 "get_body_sha", 636 "get_sig_sha", 637 "get_section_fwid", 638 "get_version", 639 "get_datakey_version", 640 "get_kernel_subkey_version", 641 ], 642 "passing_args": [ 643 ("a", ), 644 ("b", ), 645 ], 646 "failing_args": [ 647 NO_ARGS, 648 ONE_INT_ARG, 649 (("a", "b"), ), 650 ("c", ), 651 ] 652 }, 653 { 654 "method_names": [ 655 "corrupt_sig", 656 "restore_sig", 657 "corrupt_body", 658 "restore_body", 659 "move_version_backward", 660 "move_version_forward", 661 ], 662 "passing_args": [ 663 ("a", ), 664 ("b", ), 665 ], 666 "failing_args": [ 667 NO_ARGS, 668 ONE_INT_ARG, 669 ("c", ), 670 ] 671 }, 672 { 673 "method_names": [ 674 "dump_whole", 675 "write_whole", 676 ], 677 "passing_args": [ 678 (SAMPLE_FILE, ), 679 ], 680 "failing_args": [NO_ARGS], 681 }, 682 { 683 "method_name": "strip_modified_fwids", 684 "passing_args": [NO_ARGS], 685 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 686 "expected_return_type": dict 687 }, 688 { 689 "method_name": 690 "set_write_protect_region", 691 "passing_args": [("WP_RO", ), ("WP_RO", None), 692 ("WP_RO", True), 693 ("WP_RO", False)], 694 "failing_args": 695 [NO_ARGS, (None, ), ("WP_RO", None, "EXTRA")], 696 }, 697 { 698 "method_name": "get_write_protect_status", 699 "passing_args": [NO_ARGS], 700 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 701 "expected_return_type": dict 702 }, 703 { 704 "method_name": 705 "get_write_cmd", 706 "passing_args": [ 707 NO_ARGS, 708 (""), 709 ("bios.bin", ), 710 ], 711 "failing_args": [("bios.bin", []), 712 ("bios.bin", 1), 713 ("bios.bin", [], 'extra')], 714 "expected_return_type": 715 str 716 }, 717 ], 718 }, 719 { 720 "category_name": 721 "ec", 722 "test_cases": [ 723 { 724 "method_names": [ 725 "reload", 726 "get_version", 727 "get_active_hash", 728 "is_efs", 729 ], 730 "passing_args": [NO_ARGS], 731 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 732 "allow_error_msg": 733 "list index out of range", 734 }, 735 { 736 "method_names": 737 ["dump_whole", "write_whole", "dump_firmware"], 738 "passing_args": [ 739 (SAMPLE_FILE, ), 740 ], 741 "failing_args": [NO_ARGS], 742 }, 743 { 744 "method_name": 745 "corrupt_body", 746 "passing_args": [ 747 ("rw", ), 748 ], 749 "failing_args": [ 750 NO_ARGS, 751 ONE_INT_ARG, 752 ("ro", ), 753 ("rw", "rw"), 754 ], 755 }, 756 { 757 "method_name": "set_write_protect", 758 "passing_args": [ 759 (True, ), 760 (False, ), 761 ], 762 "failing_args": [ 763 NO_ARGS, 764 (True, False), 765 ] 766 }, 767 { 768 "method_name": 769 "copy_rw", 770 "passing_args": [ 771 ("rw", "rw"), 772 ], 773 "failing_args": [ 774 NO_ARGS, 775 ("rw", "ro"), 776 ("ro", "rw"), 777 ("rw", ), 778 ], 779 }, 780 { 781 "method_name": "reboot_to_switch_slot", 782 "passing_args": [NO_ARGS], 783 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 784 "allow_error_msg": "CmdError", 785 }, 786 { 787 "method_name": 788 "get_write_cmd", 789 "passing_args": [ 790 NO_ARGS, 791 (""), 792 ("ec.bin", ), 793 ], 794 "failing_args": [("ec.bin", []), ("ec.bin", 1), 795 ("ec.bin", [], 'extra')], 796 "expected_return_type": 797 str 798 }, 799 ], 800 }, 801 { 802 "category_name": 803 "kernel", 804 "test_cases": [{ 805 "method_names": [ 806 "corrupt_sig", 807 "restore_sig", 808 "move_version_backward", 809 "move_version_forward", 810 ], 811 "passing_args": [ 812 ("a", ), 813 ("b", ), 814 ], 815 "failing_args": [ 816 NO_ARGS, 817 ONE_INT_ARG, 818 ("c", ), 819 ("a", "b"), 820 ], 821 }, { 822 "method_names": [ 823 "get_version", 824 "get_datakey_version", 825 "get_sha", 826 ], 827 "passing_args": [ 828 ("a", ), 829 ("b", ), 830 ], 831 "failing_args": [ 832 (("a", "b"), ), 833 ("c", ), 834 NO_ARGS, 835 ONE_INT_ARG, 836 ], 837 }, { 838 "method_name": "diff_a_b", 839 "passing_args": [NO_ARGS], 840 "failing_args": [ 841 ONE_INT_ARG, 842 ONE_STR_ARG, 843 ], 844 "expected_return_type": bool, 845 }, { 846 "method_name": 847 "resign_with_keys", 848 "passing_args": [ 849 ("a", ), 850 ("b", ), 851 ("b", SAMPLE_FILE), 852 ], 853 "failing_args": [ 854 (("a", "b"), ), 855 ("c", ), 856 NO_ARGS, 857 ONE_INT_ARG, 858 ], 859 }, { 860 "method_names": [ 861 "dump", 862 "write", 863 ], 864 "passing_args": [ 865 ("a", SAMPLE_FILE), 866 ("b", SAMPLE_FILE), 867 ], 868 "failing_args": [ 869 (("a", "b"), SAMPLE_FILE), 870 ("c", SAMPLE_FILE), 871 ("a", ), 872 NO_ARGS, 873 ] 874 }], 875 }, 876 { 877 "category_name": 878 "tpm", 879 "test_cases": [ 880 { 881 "method_names": [ 882 "get_firmware_version", 883 "get_firmware_datakey_version", 884 "get_kernel_version", 885 "get_kernel_datakey_version", 886 "get_tpm_version", 887 "stop_daemon", 888 "restart_daemon", 889 ], 890 "passing_args": [NO_ARGS], 891 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 892 }, 893 ] 894 }, 895 { 896 "category_name": 897 "cgpt", 898 "test_cases": [{ 899 "method_name": "get_attributes", 900 "passing_args": [NO_ARGS], 901 "failing_args": [ 902 ONE_INT_ARG, 903 ONE_STR_ARG, 904 ], 905 }, { 906 "method_name": 907 "set_attributes", 908 "passing_args": [ 909 NO_ARGS, 910 (SAMPLE_CGPT_A, ), 911 (None, SAMPLE_CGPT_B), 912 (SAMPLE_CGPT_A, SAMPLE_CGPT_B), 913 (None, None), 914 ], 915 "failing_args": [ 916 (None, None, None), 917 ], 918 }] 919 }, 920 { 921 "category_name": 922 "updater", 923 "test_cases": [ 924 # TODO (gredelston): 925 # Uncomment the methods which write to flash memory, 926 # once we are able to set the firmware_updater to "emulate" mode. 927 { 928 "method_names": [ 929 "cleanup", 930 "stop_daemon", 931 "start_daemon", 932 # "modify_ecid_and_flash_to_bios", 933 "get_ec_hash", 934 "reset_shellball", 935 # "run_factory_install", 936 # "run_recovery", 937 "cbfs_setup_work_dir", 938 # "cbfs_sign_and_flash", 939 "get_temp_path", 940 "get_keys_path", 941 "get_work_path", 942 "get_bios_relative_path", 943 "get_ec_relative_path", 944 "get_ec_hash" 945 ], 946 "passing_args": [ 947 NO_ARGS, 948 ], 949 "failing_args": [ 950 ONE_INT_ARG, 951 ONE_STR_ARG, 952 ], 953 "allow_error_msg": 954 ("command cp -rf " 955 "/usr/local/tmp/faft/autest/work " 956 "/usr/local/tmp/faft/autest/cbfs failed|" 957 "Could not detect a usable ec flash device") 958 }, 959 { 960 "method_name": 961 "get_section_fwid", 962 "passing_args": [ 963 NO_ARGS, 964 ("bios", ), 965 ("ec", ), 966 ("bios", "b"), 967 ("ec", "rw"), 968 ], 969 "failing_args": [ 970 ("foo", ), 971 ("bios", "foo"), 972 ("ec", "foo"), 973 ], 974 "expected_return_type": 975 str, 976 "allow_error_msg": 977 r"is empty|does not contain", 978 }, 979 { 980 "method_names": [ 981 "get_device_fwids", 982 "get_image_fwids", 983 ], 984 "passing_args": [ 985 NO_ARGS, 986 ("bios", ), 987 ("ec", ), 988 ], 989 "failing_args": [ 990 ("foo", ), 991 ], 992 "expected_return_type": 993 dict, 994 "allow_error_msg": (r"is already modified|" 995 r"is empty|" 996 r"does not contain"), 997 }, 998 { 999 "method_name": 1000 "modify_image_fwids", 1001 "passing_args": [ 1002 NO_ARGS, 1003 ("bios", ), 1004 ("ec", ), 1005 ("bios", ("b", "rec")), 1006 ("ec", ("rw_b", )), 1007 ], 1008 "failing_args": [ 1009 ("foo", ), 1010 ("bios", ("foo", )), 1011 ("ec", ("foo", )), 1012 ], 1013 "expected_return_type": 1014 dict, 1015 "allow_error_msg": (r"is already modified|" 1016 r"is empty|" 1017 r"does not contain"), 1018 }, 1019 { 1020 "method_name": "resign_firmware", 1021 "passing_args": [ 1022 ONE_INT_ARG, 1023 (None, ), 1024 ], 1025 "failing_args": [ 1026 NO_ARGS, 1027 ONE_STR_ARG, 1028 (1, 1), 1029 ], 1030 }, 1031 { 1032 "method_names": [ 1033 "repack_shellball", 1034 "extract_shellball", 1035 ], 1036 "passing_args": [ 1037 NO_ARGS, 1038 ("test", ), 1039 (None, ), 1040 ], 1041 "failing_args": [ 1042 ("foo", "bar"), 1043 ] 1044 }, 1045 { 1046 "method_name": 1047 "run_firmwareupdate", 1048 "passing_args": [ 1049 ("autoupdate", ), 1050 ("recovery", ), 1051 ("bootok", ), 1052 ("factory_install", ), 1053 ("bootok", None), 1054 ("bootok", "test"), 1055 ("bootok", "test", ()), 1056 ("bootok", "test", ("--noupdate_ec", 1057 "--wp=1")), 1058 ], 1059 "failing_args": [NO_ARGS], 1060 }, 1061 { 1062 "method_name": 1063 "get_firmwareupdate_command", 1064 "passing_args": [ 1065 ("autoupdate", ), 1066 ("recovery", ), 1067 ("factory_install", ), 1068 ], 1069 "failing_args": [NO_ARGS], 1070 "expected_return_type": 1071 str 1072 }, 1073 { 1074 "method_names": [ 1075 "run_autoupdate", 1076 "run_bootok", 1077 ], 1078 "passing_args": [ 1079 ("test", ), 1080 ], 1081 "failing_args": [ 1082 NO_ARGS, 1083 ("foo", "bar"), 1084 ], 1085 }, 1086 { 1087 "method_names": [ 1088 "cbfs_extract_chip", 1089 "cbfs_get_chip_hash", 1090 "cbfs_replace_chip", 1091 ], 1092 "passing_args": 1093 [(chip_fw_name, ) 1094 for chip_fw_name in CHIP_FW_NAMES], 1095 "failing_args": [ 1096 NO_ARGS, 1097 ONE_INT_ARG, 1098 ], 1099 "allow_error_msg": 1100 "cbfstool /usr/local/tmp/faft/" 1101 }, 1102 { 1103 "method_name": 1104 "copy_bios", 1105 "passing_args": [('/tmp/fake-bios.bin', )], 1106 "failing_args": 1107 [NO_ARGS, ('/tmp/fake-bios.bin', "foo")], 1108 "expected_return_type": 1109 str 1110 }, 1111 { 1112 "method_name": "get_image_gbb_flags", 1113 "passing_args": 1114 [NO_ARGS, ('/tmp/fake-bios.bin', )], 1115 "failing_args": 1116 [('/tmp/fake-bios.bin', 'bogus')], 1117 "store_result_as": "gbb_flags" 1118 }, 1119 { 1120 "method_name": 1121 "set_image_gbb_flags", 1122 "passing_args": [ 1123 (operator.itemgetter('gbb_flags'), ), 1124 (operator.itemgetter('gbb_flags'), 1125 '/tmp/fake-bios.bin'), 1126 ], 1127 "failing_args": 1128 [NO_ARGS, ('too', 'many', 'args')] 1129 } 1130 ] 1131 }, 1132 { 1133 "category_name": 1134 "rootfs", 1135 "test_cases": [ 1136 { 1137 "method_name": 1138 "verify_rootfs", 1139 "passing_args": [ 1140 ("A", ), 1141 ("B", ), 1142 ], 1143 "failing_args": [ 1144 NO_ARGS, 1145 ONE_INT_ARG, 1146 ("C", ), 1147 ("A", "B"), 1148 ], 1149 }, 1150 ] 1151 }, 1152 { 1153 "category_name": 1154 '', 1155 "test_cases": [ 1156 # explicit connect 1157 { 1158 "method_name": "quit", 1159 "passing_args": [NO_ARGS] 1160 }, 1161 { 1162 "method_name": "connect", 1163 "passing_args": [NO_ARGS] 1164 }, 1165 { 1166 "method_name": "ready", 1167 "passing_args": [NO_ARGS] 1168 }, 1169 { 1170 "method_name": "disconnect", 1171 "passing_args": [NO_ARGS] 1172 }, 1173 { 1174 "method_name": "connect", 1175 "passing_args": [NO_ARGS] 1176 }, 1177 { 1178 "method_name": "ready", 1179 "passing_args": [NO_ARGS] 1180 }, 1181 1182 # implicit connect 1183 { 1184 "method_name": "quit", 1185 "passing_args": [NO_ARGS] 1186 }, 1187 { 1188 "method_name": "ready", 1189 "passing_args": [NO_ARGS] 1190 }, 1191 { 1192 "method_name": "disconnect", 1193 "passing_args": [NO_ARGS] 1194 }, 1195 { 1196 "method_name": "ready", 1197 "passing_args": [NO_ARGS] 1198 }, 1199 ] 1200 } 1201] 1202