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 six 9import sys 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.values()) 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 six.moves.xmlrpc_client.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 six.moves.xmlrpc_client.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 six.moves.xmlrpc_client.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 suppress_warning=True): 322 logging.info("No EC found on DUT. Skipping EC category.") 323 continue 324 325 # Re-enable test mode, in case another category's tests disabled it. 326 self.faft_client.rpc_settings.enable_test_mode() 327 328 test_cases = rpc_category["test_cases"] 329 logging.info("Testing %d cases for RPC category %s", 330 len(test_cases), repr(category_name)) 331 for test_case in test_cases: 332 method_names = get_rpc_method_names_from_test_case(test_case) 333 passing_args = test_case.get("passing_args", []) 334 ec_passing_args = test_case.get("ec_passing_args", []) 335 failing_args = test_case.get("failing_args", []) 336 allow_error_msg = test_case.get("allow_error_msg", None) 337 expected_return_type = test_case.get("expected_return_type", 338 None) 339 store_result_as = test_case.get("store_result_as", None) 340 silence_result = test_case.get("silence_result", False) 341 for method_name in method_names: 342 for passing_arg_tuple in passing_args: 343 passing_arg_tuple = self._retrieve_stored_values( 344 passing_arg_tuple) 345 result = self._assert_passes(category_name, method_name, 346 passing_arg_tuple, 347 allow_error_msg, 348 expected_return_type, 349 silence_result) 350 if store_result_as is not None: 351 self._stored_values[store_result_as] = result 352 for failing_arg_tuple in failing_args: 353 failing_arg_tuple = self._retrieve_stored_values( 354 failing_arg_tuple) 355 self._assert_fails(category_name, method_name, 356 failing_arg_tuple) 357 for arg_tuple in ec_passing_args: 358 arg_tuple = self._retrieve_stored_values(arg_tuple) 359 if self.check_ec_capability(suppress_warning=True): 360 result = self._assert_passes( 361 category_name, method_name, arg_tuple, 362 allow_error_msg, expected_return_type, 363 silence_result) 364 if store_result_as is not None: 365 self._stored_values[store_result_as] = result 366 else: 367 self._assert_fails(category_name, method_name, 368 arg_tuple) 369 370 371""" 372RPC_CATEGORIES contains all the test cases for our RPC tests. 373Each element of RPC_CATEGORIES must be a dict containing the following keys: 374 375@key category_name: A string naming the RPC category, such as bios or kernel. 376@key test_cases: A list of test cases, each of which must be a dict containing 377 the following keys: 378 @key method_name (optional): A string naming an RPC method within 379 this category. Either this key or method_names 380 is required (but not both). 381 @key method_names (optional): An array of strings naming RPC methods within 382 this category. Either this key or method_name 383 is required (but not both). 384 @key passing_args: A list of tuples, each of which could be unpacked and 385 then passed into the RPC method as a valid set of 386 parameters. Each tuple might contain instances of 387 operator.itemgetter. If so, those instances will be 388 replaced with values from firmware_FAFTRPC._stored_values 389 before being passed into the RPC method. 390 @key failing_args: A list of tuples, each of which could be unpacked and 391 then passed into the RPC method as a set of parameters 392 which should yield an RPC error. Each tuple might contain 393 instances of operator.itemgetter. If so, those instances 394 will be replaced with values from 395 firmware_FAFTRPC._stored_values before being passed into 396 the RPC method. 397 @key silence_result: Normally, the RPC return value is logged. However, if 398 this key is truthy, then the result is not logged. 399 @key allow_error_msg (optional): String representing a regex pattern. 400 If the RPC method is called with a 401 passing_args tuple, but it yields an RPC 402 error whose message is matched by 403 re.search(allow_error_msg, error_msg), 404 then the test will be considered a pass. 405 @key store_result_as (optional): String. If this field is specified, then 406 the result from the RPC call will be stored 407 in firmware_FAFTRPC._stored_values. This 408 allows us to later reference the result 409 via an operator.itemgetter, as described 410 above in the docstrings for passing_args 411 and failing_args. 412 413""" 414RPC_CATEGORIES = [ 415 { 416 "category_name": 417 "system", 418 "test_cases": [ 419 { 420 "method_names": [ 421 "is_available", 422 "get_platform_name", 423 "get_model_name", 424 "dev_tpm_present", 425 "get_boot_mode", 426 "get_root_dev", 427 "get_root_part", 428 "get_minios_priority", 429 "get_fw_vboot2", 430 "request_recovery_boot", 431 "is_removable_device_boot", 432 "get_internal_device", 433 ], 434 "passing_args": [NO_ARGS], 435 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 436 }, 437 { 438 "method_name": 439 "run_shell_command", 440 "passing_args": [("ls -l", ), ("ls -l", False), 441 ("ls -l", True)], 442 "failing_args": [ 443 NO_ARGS, 444 ("ls", "-l", 'foo'), 445 ], 446 }, 447 { 448 "method_name": "run_shell_command_get_status", 449 "passing_args": [ 450 ("ls", ), 451 ], 452 "failing_args": [ 453 NO_ARGS, 454 ("ls", "-l", 'foo'), 455 ], 456 }, 457 { 458 "method_name": "run_shell_command_get_status", 459 "passing_args": [ 460 ("ls ''", ), 461 ], 462 }, 463 { 464 "method_name": "run_shell_command", 465 "failing_args": [ 466 ("ls ''", ), 467 ], 468 }, 469 { 470 "method_name": 471 "run_shell_command_check_output", 472 "passing_args": [ 473 ("ls -l", "total"), 474 ], 475 "failing_args": [ 476 NO_ARGS, 477 ], 478 }, 479 { 480 "method_name": "run_shell_command_get_output", 481 "passing_args": [ 482 ("ls -l", True), 483 ], 484 "failing_args": [ 485 NO_ARGS, 486 ], 487 }, 488 { 489 "method_name": "get_crossystem_value", 490 "passing_args": [ 491 ("fwid", ), 492 ], 493 "failing_args": [NO_ARGS], 494 }, 495 { 496 "method_name": "set_try_fw_b", 497 "passing_args": [ 498 NO_ARGS, 499 (1, ), 500 ], 501 "failing_args": [ 502 (1, 1), 503 ], 504 }, 505 { 506 "method_name": "set_fw_try_next", 507 "passing_args": [ 508 ("A", ), 509 ("A", 1), 510 ], 511 "failing_args": [ 512 NO_ARGS, 513 ("A", 1, "B"), 514 ], 515 }, 516 { 517 "method_name": "set_minios_priority", 518 "passing_args": [ 519 ("A"), 520 ("B"), 521 ], 522 "failing_args": [ 523 NO_ARGS, 524 ("A", 1), 525 ], 526 }, 527 { 528 "method_name": "get_dev_boot_usb", 529 "passing_args": [NO_ARGS], 530 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 531 "store_result_as": "dev_boot_usb", 532 }, 533 { 534 "method_name": 535 "set_dev_boot_usb", 536 "passing_args": [ 537 (operator.itemgetter("dev_boot_usb"), 538 ), 539 ], 540 "failing_args": [ 541 NO_ARGS, 542 (True, False), 543 ], 544 }, 545 { 546 "method_name": "create_temp_dir", 547 "passing_args": [ 548 NO_ARGS, 549 ONE_STR_ARG, 550 ], 551 "failing_args": [ 552 ONE_INT_ARG, 553 ("foo", "bar"), 554 ], 555 "expected_return_type": str, 556 "store_result_as": "temp_dir", 557 }, 558 { 559 "method_name": "remove_file", 560 "passing_args": [ 561 (SAMPLE_FILE, ), 562 ], 563 "failing_args": [ 564 NO_ARGS, 565 (1, 2), 566 ], 567 }, 568 { 569 "method_name": "remove_dir", 570 "passing_args": [ 571 (operator.itemgetter("temp_dir"), ), 572 ], 573 "failing_args": [ 574 NO_ARGS, 575 (1, 2), 576 ] 577 }, 578 { 579 "method_name": "check_keys", 580 "passing_args": [ 581 ([], ), 582 ([116], ), 583 ([28, 29, 32], ), 584 ], 585 "failing_args": [ 586 NO_ARGS, 587 ([], [116]), 588 ], 589 "expected_return_type": int, 590 }, 591 ] 592 }, 593 { 594 "category_name": 595 "bios", 596 "test_cases": [ 597 { 598 "method_names": [ 599 "reload", 600 ], 601 "passing_args": [NO_ARGS], 602 "failing_args": [ONE_INT_ARG, ONE_STR_ARG] 603 }, 604 { 605 "method_name": "get_gbb_flags", 606 "passing_args": [NO_ARGS], 607 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 608 "expected_return_type": int, 609 "store_result_as": "gbb_flags", 610 }, 611 { 612 "method_name": "set_gbb_flags", 613 "passing_args": [ 614 (operator.itemgetter("gbb_flags"), ), 615 ], 616 "failing_args": [NO_ARGS], 617 }, 618 { 619 "method_name": "get_preamble_flags", 620 "passing_args": [ 621 ("a", ), 622 ], 623 "failing_args": [NO_ARGS, ONE_INT_ARG], 624 "store_result_as": "preamble_flags", 625 }, 626 { 627 "method_name": 628 "set_preamble_flags", 629 "passing_args": [ 630 ( 631 "a", 632 operator.itemgetter( 633 "preamble_flags"), 634 ), 635 ], 636 "failing_args": [ 637 NO_ARGS, 638 ONE_INT_ARG, 639 ONE_STR_ARG, 640 ( 641 "c", 642 operator.itemgetter( 643 "preamble_flags"), 644 ), 645 ], 646 }, 647 { 648 "method_names": [ 649 "get_body_sha", 650 "get_sig_sha", 651 "get_section_fwid", 652 "get_version", 653 "get_datakey_version", 654 "get_kernel_subkey_version", 655 ], 656 "passing_args": [ 657 ("a", ), 658 ("b", ), 659 ], 660 "failing_args": [ 661 NO_ARGS, 662 ONE_INT_ARG, 663 (("a", "b"), ), 664 ("c", ), 665 ] 666 }, 667 { 668 "method_name": "set_version", 669 "passing_args": [ 670 ("a", 0), 671 ("b", 1), 672 ], 673 "failing_args": [ 674 NO_ARGS, 675 ("a", ), 676 ("b", -1), 677 ], 678 }, 679 { 680 "method_names": [ 681 "get_sig_one_byte", 682 "get_body_one_byte", 683 ], 684 "passing_args": [ 685 ("a", ), 686 ("b", ), 687 ], 688 "failing_args": [ 689 NO_ARGS, 690 ONE_INT_ARG, 691 ("c", ), 692 ] 693 }, 694 { 695 "method_names": [ 696 "modify_sig", 697 "modify_body", 698 ], 699 "passing_args": [ 700 ("a", 0, 0xff), 701 ("b", 1, 0xff), 702 ], 703 "failing_args": [ 704 NO_ARGS, 705 ONE_INT_ARG, 706 ], 707 }, 708 { 709 "method_names": [ 710 "dump_whole", 711 "write_whole", 712 ], 713 "passing_args": [ 714 (SAMPLE_FILE, ), 715 ], 716 "failing_args": [NO_ARGS], 717 }, 718 { 719 "method_name": "strip_modified_fwids", 720 "passing_args": [NO_ARGS], 721 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 722 "expected_return_type": dict 723 }, 724 { 725 "method_name": 726 "set_write_protect_region", 727 "passing_args": [("WP_RO", ), ("WP_RO", None), 728 ("WP_RO", True), 729 ("WP_RO", False)], 730 "failing_args": 731 [NO_ARGS, (None, ), ("WP_RO", None, "EXTRA")], 732 }, 733 { 734 "method_name": "get_write_protect_status", 735 "passing_args": [NO_ARGS], 736 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 737 "expected_return_type": dict 738 }, 739 { 740 "method_name": 741 "get_write_cmd", 742 "passing_args": [ 743 NO_ARGS, 744 (""), 745 ("bios.bin", ), 746 ], 747 "failing_args": [("bios.bin", []), 748 ("bios.bin", 1), 749 ("bios.bin", [], 'extra')], 750 "expected_return_type": 751 str 752 }, 753 ], 754 }, 755 { 756 "category_name": 757 "ec", 758 "test_cases": [ 759 { 760 "method_names": [ 761 "reload", 762 "get_active_hash", 763 "is_efs", 764 ], 765 "passing_args": [NO_ARGS], 766 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 767 "allow_error_msg": 768 "list index out of range", 769 }, 770 { 771 "method_name": 772 "get_version", 773 "passing_args": [ 774 NO_ARGS, 775 ("ro", ), 776 ("RW", ), 777 (None, ), 778 ], 779 }, 780 { 781 "method_names": 782 ["dump_whole", "write_whole", "dump_firmware"], 783 "passing_args": [ 784 (SAMPLE_FILE, ), 785 ], 786 "failing_args": [NO_ARGS], 787 }, 788 { 789 "method_name": 790 "corrupt_body", 791 "passing_args": [ 792 ("rw", ), 793 ], 794 "failing_args": [ 795 NO_ARGS, 796 ONE_INT_ARG, 797 ("ro", ), 798 ("rw", "rw"), 799 ], 800 }, 801 { 802 "method_name": "set_write_protect", 803 "passing_args": [ 804 (True, ), 805 (False, ), 806 ], 807 "failing_args": [ 808 NO_ARGS, 809 (True, False), 810 ] 811 }, 812 { 813 "method_name": 814 "copy_rw", 815 "passing_args": [ 816 ("rw", "rw"), 817 ], 818 "failing_args": [ 819 NO_ARGS, 820 ("rw", "ro"), 821 ("ro", "rw"), 822 ("rw", ), 823 ], 824 }, 825 { 826 "method_name": "reboot_to_switch_slot", 827 "passing_args": [NO_ARGS], 828 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 829 "allow_error_msg": "CmdError", 830 }, 831 { 832 "method_name": 833 "get_write_cmd", 834 "passing_args": [ 835 NO_ARGS, 836 (""), 837 ("ec.bin", ), 838 ], 839 "failing_args": [("ec.bin", []), ("ec.bin", 1), 840 ("ec.bin", [], 'extra')], 841 "expected_return_type": 842 str 843 }, 844 ], 845 }, 846 { 847 "category_name": 848 "kernel", 849 "test_cases": [{ 850 "method_names": [ 851 "corrupt_sig", 852 "restore_sig", 853 "move_version_backward", 854 "move_version_forward", 855 ], 856 "passing_args": [ 857 ("a", ), 858 ("b", ), 859 ], 860 "failing_args": [ 861 NO_ARGS, 862 ONE_INT_ARG, 863 ("c", ), 864 ("a", "b"), 865 ], 866 }, { 867 "method_names": [ 868 "get_version", 869 "get_datakey_version", 870 "get_sha", 871 ], 872 "passing_args": [ 873 ("a", ), 874 ("b", ), 875 ], 876 "failing_args": [ 877 (("a", "b"), ), 878 ("c", ), 879 NO_ARGS, 880 ONE_INT_ARG, 881 ], 882 }, { 883 "method_name": "diff_a_b", 884 "passing_args": [NO_ARGS], 885 "failing_args": [ 886 ONE_INT_ARG, 887 ONE_STR_ARG, 888 ], 889 "expected_return_type": bool, 890 }, { 891 "method_name": 892 "resign_with_keys", 893 "passing_args": [ 894 ("a", ), 895 ("b", ), 896 ("b", SAMPLE_FILE), 897 ], 898 "failing_args": [ 899 (("a", "b"), ), 900 ("c", ), 901 NO_ARGS, 902 ONE_INT_ARG, 903 ], 904 }, { 905 "method_names": [ 906 "dump", 907 "write", 908 ], 909 "passing_args": [ 910 ("a", SAMPLE_FILE), 911 ("b", SAMPLE_FILE), 912 ], 913 "failing_args": [ 914 (("a", "b"), SAMPLE_FILE), 915 ("c", SAMPLE_FILE), 916 ("a", ), 917 NO_ARGS, 918 ] 919 }], 920 }, 921 { 922 "category_name": 923 "tpm", 924 "test_cases": [ 925 { 926 "method_names": [ 927 "get_firmware_version", 928 "get_firmware_datakey_version", 929 "get_kernel_version", 930 "get_kernel_datakey_version", 931 "get_tpm_version", 932 "stop_daemon", 933 "restart_daemon", 934 ], 935 "passing_args": [NO_ARGS], 936 "failing_args": [ONE_INT_ARG, ONE_STR_ARG], 937 }, 938 ] 939 }, 940 { 941 "category_name": 942 "cgpt", 943 "test_cases": [{ 944 "method_name": "get_attributes", 945 "passing_args": [NO_ARGS], 946 "failing_args": [ 947 ONE_INT_ARG, 948 ONE_STR_ARG, 949 ], 950 }, { 951 "method_name": 952 "set_attributes", 953 "passing_args": [ 954 NO_ARGS, 955 (SAMPLE_CGPT_A, ), 956 (None, SAMPLE_CGPT_B), 957 (SAMPLE_CGPT_A, SAMPLE_CGPT_B), 958 (None, None), 959 ], 960 "failing_args": [ 961 (None, None, None), 962 ], 963 }] 964 }, 965 { 966 "category_name": 967 "updater", 968 "test_cases": [ 969 { 970 "method_names": [ 971 "cleanup", 972 "stop_daemon", 973 "start_daemon", 974 # "modify_ecid_and_flash_to_bios", 975 "get_ec_hash", 976 "reset_shellball", 977 # "run_factory_install", 978 # "run_recovery", 979 "cbfs_setup_work_dir", 980 # "cbfs_sign_and_flash", 981 "get_temp_path", 982 "get_keys_path", 983 "get_work_path", 984 "get_bios_relative_path", 985 "get_ec_relative_path", 986 "get_ec_hash" 987 ], 988 "passing_args": [ 989 NO_ARGS, 990 ], 991 "failing_args": [ 992 ONE_INT_ARG, 993 ONE_STR_ARG, 994 ], 995 "allow_error_msg": 996 ("command cp -rf " 997 "/usr/local/tmp/faft/autest/work " 998 "/usr/local/tmp/faft/autest/cbfs failed|" 999 "Could not detect a usable ec flash device") 1000 }, 1001 { 1002 "method_name": 1003 "get_section_fwid", 1004 "passing_args": [ 1005 NO_ARGS, 1006 ("bios", ), 1007 ("ec", ), 1008 ("bios", "b"), 1009 ("ec", "rw"), 1010 ], 1011 "failing_args": [ 1012 ("foo", ), 1013 ("bios", "foo"), 1014 ("ec", "foo"), 1015 ], 1016 "expected_return_type": 1017 str, 1018 "allow_error_msg": 1019 r"is empty|does not contain", 1020 }, 1021 { 1022 "method_names": [ 1023 "get_device_fwids", 1024 "get_image_fwids", 1025 ], 1026 "passing_args": [ 1027 NO_ARGS, 1028 ("bios", ), 1029 ], 1030 "ec_passing_args": [ 1031 ("ec", ), 1032 ], 1033 "failing_args": [ 1034 ("foo", ), 1035 ], 1036 "expected_return_type": 1037 dict, 1038 "allow_error_msg": (r"is already modified|" 1039 r"is empty|" 1040 r"does not contain"), 1041 }, 1042 { 1043 "method_name": 1044 "modify_image_fwids", 1045 "passing_args": [ 1046 NO_ARGS, 1047 ("bios", ), 1048 ("ec", ), 1049 ("bios", ("b", "rec")), 1050 ("ec", ("rw_b", )), 1051 ], 1052 "failing_args": [ 1053 ("foo", ), 1054 ("bios", ("foo", )), 1055 ("ec", ("foo", )), 1056 ], 1057 "expected_return_type": 1058 dict, 1059 "allow_error_msg": (r"is already modified|" 1060 r"is empty|" 1061 r"does not contain"), 1062 }, 1063 { 1064 "method_name": "resign_firmware", 1065 "passing_args": [ 1066 ONE_INT_ARG, 1067 (None, ), 1068 ], 1069 "failing_args": [ 1070 NO_ARGS, 1071 ONE_STR_ARG, 1072 (1, 1), 1073 ], 1074 }, 1075 { 1076 "method_names": [ 1077 "repack_shellball", 1078 "extract_shellball", 1079 ], 1080 "passing_args": [ 1081 NO_ARGS, 1082 ("test", ), 1083 (None, ), 1084 ], 1085 "failing_args": [ 1086 ("foo", "bar"), 1087 ] 1088 }, 1089 { 1090 "method_name": 1091 "run_firmwareupdate", 1092 "passing_args": [ 1093 ("autoupdate", ), 1094 ("recovery", ), 1095 ("bootok", ), 1096 ("factory_install", ), 1097 ("bootok", None), 1098 ("bootok", "test"), 1099 ("bootok", "test", ()), 1100 ("bootok", "test", ("--noupdate_ec", 1101 "--wp=1")), 1102 ], 1103 "failing_args": [NO_ARGS], 1104 }, 1105 { 1106 "method_name": 1107 "get_firmwareupdate_command", 1108 "passing_args": [ 1109 ("autoupdate", ), 1110 ("recovery", ), 1111 ("factory_install", ), 1112 ], 1113 "failing_args": [NO_ARGS], 1114 "expected_return_type": 1115 str 1116 }, 1117 { 1118 "method_names": [ 1119 "run_autoupdate", 1120 "run_bootok", 1121 ], 1122 "passing_args": [ 1123 ("test", ), 1124 ], 1125 "failing_args": [ 1126 NO_ARGS, 1127 ("foo", "bar"), 1128 ], 1129 }, 1130 { 1131 "method_names": [ 1132 "cbfs_extract_chip", 1133 "cbfs_get_chip_hash", 1134 "cbfs_replace_chip", 1135 ], 1136 "passing_args": 1137 [(chip_fw_name, ) 1138 for chip_fw_name in CHIP_FW_NAMES], 1139 "failing_args": [ 1140 NO_ARGS, 1141 ONE_INT_ARG, 1142 ], 1143 "allow_error_msg": 1144 "cbfstool /usr/local/tmp/faft/" 1145 }, 1146 { 1147 "method_name": 1148 "copy_bios", 1149 "passing_args": [('/tmp/fake-bios.bin', )], 1150 "failing_args": 1151 [NO_ARGS, ('/tmp/fake-bios.bin', "foo")], 1152 "expected_return_type": 1153 str 1154 }, 1155 { 1156 "method_name": "get_image_gbb_flags", 1157 "passing_args": 1158 [NO_ARGS, ('/tmp/fake-bios.bin', )], 1159 "failing_args": 1160 [('/tmp/fake-bios.bin', 'bogus')], 1161 "store_result_as": "gbb_flags" 1162 }, 1163 { 1164 "method_name": 1165 "set_image_gbb_flags", 1166 "passing_args": [ 1167 (operator.itemgetter('gbb_flags'), ), 1168 (operator.itemgetter('gbb_flags'), 1169 '/tmp/fake-bios.bin'), 1170 ], 1171 "failing_args": 1172 [NO_ARGS, ('too', 'many', 'args')] 1173 } 1174 ] 1175 }, 1176 { 1177 "category_name": 1178 "rootfs", 1179 "test_cases": [ 1180 { 1181 "method_name": 1182 "verify_rootfs", 1183 "passing_args": [ 1184 ("A", ), 1185 ("B", ), 1186 ], 1187 "failing_args": [ 1188 NO_ARGS, 1189 ONE_INT_ARG, 1190 ("C", ), 1191 ("A", "B"), 1192 ], 1193 }, 1194 ] 1195 }, 1196 { 1197 "category_name": 1198 '', 1199 "test_cases": [ 1200 # explicit connect 1201 { 1202 "method_name": "quit", 1203 "passing_args": [NO_ARGS] 1204 }, 1205 { 1206 "method_name": "connect", 1207 "passing_args": [NO_ARGS] 1208 }, 1209 { 1210 "method_name": "ready", 1211 "passing_args": [NO_ARGS] 1212 }, 1213 { 1214 "method_name": "disconnect", 1215 "passing_args": [NO_ARGS] 1216 }, 1217 { 1218 "method_name": "connect", 1219 "passing_args": [NO_ARGS] 1220 }, 1221 { 1222 "method_name": "ready", 1223 "passing_args": [NO_ARGS] 1224 }, 1225 1226 # implicit connect 1227 { 1228 "method_name": "quit", 1229 "passing_args": [NO_ARGS] 1230 }, 1231 { 1232 "method_name": "ready", 1233 "passing_args": [NO_ARGS] 1234 }, 1235 { 1236 "method_name": "disconnect", 1237 "passing_args": [NO_ARGS] 1238 }, 1239 { 1240 "method_name": "ready", 1241 "passing_args": [NO_ARGS] 1242 }, 1243 ] 1244 } 1245] 1246