xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/unittest/_log.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Workerimport logging
2*cda5da8dSAndroid Build Coastguard Workerimport collections
3*cda5da8dSAndroid Build Coastguard Worker
4*cda5da8dSAndroid Build Coastguard Workerfrom .case import _BaseTestCaseContext
5*cda5da8dSAndroid Build Coastguard Worker
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Worker_LoggingWatcher = collections.namedtuple("_LoggingWatcher",
8*cda5da8dSAndroid Build Coastguard Worker                                         ["records", "output"])
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Workerclass _CapturingHandler(logging.Handler):
11*cda5da8dSAndroid Build Coastguard Worker    """
12*cda5da8dSAndroid Build Coastguard Worker    A logging handler capturing all (raw and formatted) logging output.
13*cda5da8dSAndroid Build Coastguard Worker    """
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
16*cda5da8dSAndroid Build Coastguard Worker        logging.Handler.__init__(self)
17*cda5da8dSAndroid Build Coastguard Worker        self.watcher = _LoggingWatcher([], [])
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard Worker    def flush(self):
20*cda5da8dSAndroid Build Coastguard Worker        pass
21*cda5da8dSAndroid Build Coastguard Worker
22*cda5da8dSAndroid Build Coastguard Worker    def emit(self, record):
23*cda5da8dSAndroid Build Coastguard Worker        self.watcher.records.append(record)
24*cda5da8dSAndroid Build Coastguard Worker        msg = self.format(record)
25*cda5da8dSAndroid Build Coastguard Worker        self.watcher.output.append(msg)
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard Worker
28*cda5da8dSAndroid Build Coastguard Workerclass _AssertLogsContext(_BaseTestCaseContext):
29*cda5da8dSAndroid Build Coastguard Worker    """A context manager for assertLogs() and assertNoLogs() """
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker    LOGGING_FORMAT = "%(levelname)s:%(name)s:%(message)s"
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, test_case, logger_name, level, no_logs):
34*cda5da8dSAndroid Build Coastguard Worker        _BaseTestCaseContext.__init__(self, test_case)
35*cda5da8dSAndroid Build Coastguard Worker        self.logger_name = logger_name
36*cda5da8dSAndroid Build Coastguard Worker        if level:
37*cda5da8dSAndroid Build Coastguard Worker            self.level = logging._nameToLevel.get(level, level)
38*cda5da8dSAndroid Build Coastguard Worker        else:
39*cda5da8dSAndroid Build Coastguard Worker            self.level = logging.INFO
40*cda5da8dSAndroid Build Coastguard Worker        self.msg = None
41*cda5da8dSAndroid Build Coastguard Worker        self.no_logs = no_logs
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker    def __enter__(self):
44*cda5da8dSAndroid Build Coastguard Worker        if isinstance(self.logger_name, logging.Logger):
45*cda5da8dSAndroid Build Coastguard Worker            logger = self.logger = self.logger_name
46*cda5da8dSAndroid Build Coastguard Worker        else:
47*cda5da8dSAndroid Build Coastguard Worker            logger = self.logger = logging.getLogger(self.logger_name)
48*cda5da8dSAndroid Build Coastguard Worker        formatter = logging.Formatter(self.LOGGING_FORMAT)
49*cda5da8dSAndroid Build Coastguard Worker        handler = _CapturingHandler()
50*cda5da8dSAndroid Build Coastguard Worker        handler.setLevel(self.level)
51*cda5da8dSAndroid Build Coastguard Worker        handler.setFormatter(formatter)
52*cda5da8dSAndroid Build Coastguard Worker        self.watcher = handler.watcher
53*cda5da8dSAndroid Build Coastguard Worker        self.old_handlers = logger.handlers[:]
54*cda5da8dSAndroid Build Coastguard Worker        self.old_level = logger.level
55*cda5da8dSAndroid Build Coastguard Worker        self.old_propagate = logger.propagate
56*cda5da8dSAndroid Build Coastguard Worker        logger.handlers = [handler]
57*cda5da8dSAndroid Build Coastguard Worker        logger.setLevel(self.level)
58*cda5da8dSAndroid Build Coastguard Worker        logger.propagate = False
59*cda5da8dSAndroid Build Coastguard Worker        if self.no_logs:
60*cda5da8dSAndroid Build Coastguard Worker            return
61*cda5da8dSAndroid Build Coastguard Worker        return handler.watcher
62*cda5da8dSAndroid Build Coastguard Worker
63*cda5da8dSAndroid Build Coastguard Worker    def __exit__(self, exc_type, exc_value, tb):
64*cda5da8dSAndroid Build Coastguard Worker        self.logger.handlers = self.old_handlers
65*cda5da8dSAndroid Build Coastguard Worker        self.logger.propagate = self.old_propagate
66*cda5da8dSAndroid Build Coastguard Worker        self.logger.setLevel(self.old_level)
67*cda5da8dSAndroid Build Coastguard Worker
68*cda5da8dSAndroid Build Coastguard Worker        if exc_type is not None:
69*cda5da8dSAndroid Build Coastguard Worker            # let unexpected exceptions pass through
70*cda5da8dSAndroid Build Coastguard Worker            return False
71*cda5da8dSAndroid Build Coastguard Worker
72*cda5da8dSAndroid Build Coastguard Worker        if self.no_logs:
73*cda5da8dSAndroid Build Coastguard Worker            # assertNoLogs
74*cda5da8dSAndroid Build Coastguard Worker            if len(self.watcher.records) > 0:
75*cda5da8dSAndroid Build Coastguard Worker                self._raiseFailure(
76*cda5da8dSAndroid Build Coastguard Worker                    "Unexpected logs found: {!r}".format(
77*cda5da8dSAndroid Build Coastguard Worker                        self.watcher.output
78*cda5da8dSAndroid Build Coastguard Worker                    )
79*cda5da8dSAndroid Build Coastguard Worker                )
80*cda5da8dSAndroid Build Coastguard Worker
81*cda5da8dSAndroid Build Coastguard Worker        else:
82*cda5da8dSAndroid Build Coastguard Worker            # assertLogs
83*cda5da8dSAndroid Build Coastguard Worker            if len(self.watcher.records) == 0:
84*cda5da8dSAndroid Build Coastguard Worker                self._raiseFailure(
85*cda5da8dSAndroid Build Coastguard Worker                    "no logs of level {} or higher triggered on {}"
86*cda5da8dSAndroid Build Coastguard Worker                    .format(logging.getLevelName(self.level), self.logger.name))
87