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