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