xref: /aosp_15_r20/external/autotest/site_utils/lxc/unittest_setup.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright 2017 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li
5*9c5db199SXin Liimport argparse
6*9c5db199SXin Liimport getpass
7*9c5db199SXin Liimport logging
8*9c5db199SXin Liimport sys
9*9c5db199SXin Li
10*9c5db199SXin Liimport common
11*9c5db199SXin Lifrom autotest_lib.client.common_lib import utils
12*9c5db199SXin Li
13*9c5db199SXin Li
14*9c5db199SXin Lidef setup_logging(log_level):
15*9c5db199SXin Li    """Sets up direct logging to stdout for unittests.
16*9c5db199SXin Li
17*9c5db199SXin Li    @param log_level: Level of logging to redirect to stdout, default to INFO.
18*9c5db199SXin Li    """
19*9c5db199SXin Li    # Lifted from client.common_lib.logging_config.
20*9c5db199SXin Li    FORMAT = ('%(asctime)s.%(msecs)03d %(levelname)-5.5s|%(module)18.18s:'
21*9c5db199SXin Li              '%(lineno)4.4d| %(threadName)16.16s(%(thread)d)| %(message)s')
22*9c5db199SXin Li
23*9c5db199SXin Li    logger = logging.getLogger()
24*9c5db199SXin Li    logger.setLevel(log_level)
25*9c5db199SXin Li    handler = logging.StreamHandler(sys.stdout)
26*9c5db199SXin Li    handler.setLevel(log_level)
27*9c5db199SXin Li    formatter = logging.Formatter(FORMAT)
28*9c5db199SXin Li    handler.setFormatter(formatter)
29*9c5db199SXin Li    logger.handlers = []
30*9c5db199SXin Li    logger.addHandler(handler)
31*9c5db199SXin Li
32*9c5db199SXin Li
33*9c5db199SXin Lidef verify_user(require_sudo=True):
34*9c5db199SXin Li    """Checks that the current user is not root, but has sudo.
35*9c5db199SXin Li
36*9c5db199SXin Li    Running unit tests as root can mask permissions problems, as not all the
37*9c5db199SXin Li    code runs as root in production.
38*9c5db199SXin Li    """
39*9c5db199SXin Li    # Ensure this process is not running as root.
40*9c5db199SXin Li    if getpass.getuser() == 'root':
41*9c5db199SXin Li        raise EnvironmentError('Unittests should not be run as root.')
42*9c5db199SXin Li
43*9c5db199SXin Li    # However, most of the unit tests do require sudo.
44*9c5db199SXin Li    # TODO(dshi): crbug.com/459344 Set remove this enforcement when test
45*9c5db199SXin Li    # container can be unprivileged container.
46*9c5db199SXin Li    if require_sudo and utils.sudo_require_password():
47*9c5db199SXin Li        logging.warning('SSP requires root privilege to run commands, please '
48*9c5db199SXin Li                     'grant root access to this process.')
49*9c5db199SXin Li        utils.run('sudo true')
50*9c5db199SXin Li
51*9c5db199SXin Li
52*9c5db199SXin Liclass Config(object):
53*9c5db199SXin Li    """A class for parsing and storing command line options.
54*9c5db199SXin Li
55*9c5db199SXin Li    A convenience class for helping with unit test setup.  A global instance of
56*9c5db199SXin Li    this class is set up by the setup function.  Clients can then check this
57*9c5db199SXin Li    object for flags set on the command line.
58*9c5db199SXin Li    """
59*9c5db199SXin Li    def parse_options(self):
60*9c5db199SXin Li        """Parses command line flags for unittests."""
61*9c5db199SXin Li        parser = argparse.ArgumentParser()
62*9c5db199SXin Li        parser.add_argument('-v', '--verbose', action='store_true',
63*9c5db199SXin Li                            default=False,
64*9c5db199SXin Li                            help='Print out ALL entries.')
65*9c5db199SXin Li        parser.add_argument('-s', '--skip_cleanup', action='store_true',
66*9c5db199SXin Li                            default=False,
67*9c5db199SXin Li                            help='Skip deleting test containers.')
68*9c5db199SXin Li        args, argv = parser.parse_known_args()
69*9c5db199SXin Li
70*9c5db199SXin Li        for attr, value in vars(args).items():
71*9c5db199SXin Li            setattr(self, attr, value)
72*9c5db199SXin Li
73*9c5db199SXin Li        # Hack: python unittest also processes args.  Construct an argv to pass
74*9c5db199SXin Li        # to it, that filters out the options it won't recognize.  Then replace
75*9c5db199SXin Li        # sys.argv with the constructed argv so that calling unittest.main "just
76*9c5db199SXin Li        # works".
77*9c5db199SXin Li        if args.verbose:
78*9c5db199SXin Li            argv.insert(0, '-v')
79*9c5db199SXin Li        argv.insert(0, sys.argv[0])
80*9c5db199SXin Li        sys.argv = argv
81*9c5db199SXin Li
82*9c5db199SXin Li
83*9c5db199SXin Li# Global namespace object for storing unittest options specified on the command
84*9c5db199SXin Li# line.
85*9c5db199SXin Liconfig = Config()
86*9c5db199SXin Li
87*9c5db199SXin Lidef setup(require_sudo=True):
88*9c5db199SXin Li    """Performs global setup for unit-tests."""
89*9c5db199SXin Li    global setup_run
90*9c5db199SXin Li    config.parse_options()
91*9c5db199SXin Li
92*9c5db199SXin Li    verify_user(require_sudo)
93*9c5db199SXin Li
94*9c5db199SXin Li    log_level = logging.DEBUG if config.verbose else logging.INFO
95*9c5db199SXin Li    setup_logging(log_level)
96