Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2023-12-11 21:51:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new.25432 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Mon Dec 11 21:51:03 2023 rev:314 rq:1132388 version:4.6.0+20231211.4b74412a Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2023-12-07 19:12:55.088820500 +0100 +++ /work/SRC/openSUSE:Factory/.crmsh.new.25432/crmsh.changes 2023-12-11 21:51:15.809111225 +0100 @@ -1,0 +2,17 @@ +Mon Dec 11 03:00:33 UTC 2023 - xli...@suse.com + +- Update to version 4.6.0+20231211.4b74412a: + * Fix: scripts.health: call `setup_logging()` before importing crmsh.reprot.utils + * Dev: unittest: adjuest unit tests for previous changes + * Dev: behave: adjust regression tests for previous changes + * Dev: log: save backtrace of ValueError in logfile and suppress it in console + * Refactor: log: use levelno instead levelname to filter logs + * Refactor: log: implement lineno in Logger instead of handler + * Refactor: log: remove FileCustomFormatter + * Refactor: log: remove ConsoleReportFormatter + * Refactor: log: add LeveledFormatter to use different formats for different log levels + * Refactor: log: unused code removal + * Refactor: log: refactor DEBUG2 into a standard Logger interface + * Refactor: log: refactor ConsoleCustomFormatter + +------------------------------------------------------------------- Old: ---- crmsh-4.6.0+20231207.89c74e6c.tar.bz2 New: ---- crmsh-4.6.0+20231211.4b74412a.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.kVcgJQ/_old 2023-12-11 21:51:16.369132005 +0100 +++ /var/tmp/diff_new_pack.kVcgJQ/_new 2023-12-11 21:51:16.373132154 +0100 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0-or-later Group: %{pkg_group} -Version: 4.6.0+20231207.89c74e6c +Version: 4.6.0+20231211.4b74412a Release: 0 URL: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.kVcgJQ/_old 2023-12-11 21:51:16.409133489 +0100 +++ /var/tmp/diff_new_pack.kVcgJQ/_new 2023-12-11 21:51:16.409133489 +0100 @@ -9,7 +9,7 @@ </service> <service name="tar_scm"> <param name="url">https://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">89aab78af02c02a04ef9bc99be3386825bda2ae5</param> + <param name="changesrevision">a23bea64548038b55b3650ae73cb3b88f025ad68</param> </service> </servicedata> (No newline at EOF) ++++++ crmsh-4.6.0+20231207.89c74e6c.tar.bz2 -> crmsh-4.6.0+20231211.4b74412a.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/crmsh/log.py new/crmsh-4.6.0+20231211.4b74412a/crmsh/log.py --- old/crmsh-4.6.0+20231207.89c74e6c/crmsh/log.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/crmsh/log.py 2023-12-11 03:36:33.000000000 +0100 @@ -6,15 +6,73 @@ import shutil import logging import logging.config +import typing from contextlib import contextmanager from . import options from . import constants - +DEBUG2 = logging.DEBUG + 5 CRMSH_LOG_FILE = "/var/log/crmsh/crmsh.log" +class DEBUG2Logger(logging.Logger): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def debug2(self, msg, *args, **kwargs): + if self.isEnabledFor(DEBUG2): + self._log(DEBUG2, msg, args, **kwargs) + + +class NumberedLoggerInterface(DEBUG2Logger): + """ + Interface to prepend a number to the message, used for regression test. When this class is used directly, no numbers are prepend. + """ + lineno = -1 + + @classmethod + def reset_lineno(cls, to=0): + pass + + @classmethod + def incr_lineno(cls): + pass + + +class NumberedLogger(NumberedLoggerInterface): + """ + Prepend a number to the message, used for regression test + """ + lineno = -1 + + def _log( self, level, msg, args, **kwargs): + if NumberedLogger.lineno > 0: + msg = f'{self.lineno}: {msg}' + super()._log(level, msg, args, **kwargs) + + @classmethod + def reset_lineno(cls, to=0): + cls.lineno = to + + @classmethod + def incr_lineno(cls): + cls.lineno += 1 + + if (sys.version_info.major, sys.version_info.minor) > (3, 6): + def findCaller(self, stack_info=False, stacklevel=1): + return super().findCaller(stack_info, stacklevel+1) + else: + def findCaller(self, stack_info=False): + if stack_info: + return super().findCaller(stack_info) + else: + f = sys._getframe(4) + co = f.f_code + sinfo = None + return co.co_filename, f.f_lineno, co.co_name, sinfo + + class ConsoleCustomHandler(logging.StreamHandler): """ A custom handler for console @@ -33,62 +91,75 @@ stream.write(self.terminator) -class ConsoleCustomFormatter(logging.Formatter): - """ - A custom formatter for console +class NoBacktraceFormatter(logging.Formatter): + """Suppress backtrace unless option debug is set.""" + def format(self, record): + """ + Format the specified record as text. - Wrap levelname with colors - Wrap message with line number which is used for regression test - """ + The record's attribute dictionary is used as the operand to a + string formatting operation which yields the returned string. + Before formatting the dictionary, a couple of preparatory steps + are carried out. The message attribute of the record is computed + using LogRecord.getMessage(). If the formatting string uses the + time (as determined by a call to usesTime(), formatTime() is + called to format the event time. If there is exception information, + it is formatted using formatException() and appended to the message. + """ + if record.exc_info or record.stack_info: + from crmsh import config + if config.core.debug: + return super().format(record) + else: + record.message = record.getMessage() + if self.usesTime(): + record.asctime = self.formatTime(record, self.datefmt) + return self.formatMessage(record) + else: + return super().format(record) + + +class ConsoleColoredFormatter(NoBacktraceFormatter): + """Print levelname with colors and suppress backtrace.""" COLORS = { - "WARNING": constants.YELLOW, - "INFO": constants.GREEN, - "ERROR": constants.RED + logging.WARNING: constants.YELLOW, + logging.INFO: constants.GREEN, + logging.ERROR: constants.RED } FORMAT = "%(levelname)s: %(message)s" - def __init__(self, lineno=-1, fmt=None): - self.lineno = lineno - if fmt: - super().__init__(fmt=fmt) - else: - super().__init__(fmt=self.FORMAT) + def __init__(self, fmt=None): + super().__init__(fmt) + if not fmt: + fmt = self.FORMAT + self._colored_formatter: typing.Mapping[int, logging.Formatter] = { + level: NoBacktraceFormatter(fmt.replace('%(levelname)s', f'{color}%(levelname)s{constants.END}')) + for level, color in self.COLORS.items() + } def format(self, record): - levelname = record.levelname - # wrap with colors - if levelname in self.COLORS and not options.regression_tests: - record.levelname = self.COLORS[levelname] + levelname + constants.END - # wrap with line number - if self.lineno > 0: - msg = record.msg - record.msg = "{}: {}".format(self.lineno, msg) - record.levelname = levelname - if record.levelname == "DEBUG2": - msg = record.msg - record.msg = f"{record.funcName}: {msg}" - return super().format(record) - - -class ConsoleReportFormatter(ConsoleCustomFormatter): - """ - Custom formatter for crm report - """ - FORMAT_REPORT = "{}: %(levelname)s: %(message)s".format(socket.gethostname()) - - def __init__(self): - super().__init__(fmt=self.FORMAT_REPORT) + colored_formatter = self._colored_formatter.get(record.levelno) + if colored_formatter is not None: + return colored_formatter.format(record) + else: + return super().format(record) -class FileCustomFormatter(logging.Formatter): - """ - A custom formatter for file - """ - FORMAT = "%(asctime)s {} %(name)s: %(levelname)s: %(message)s".format(socket.gethostname()) - DATEFMT = "%b %d %H:%M:%S" +class LeveledFormatter(logging.Formatter): + """Format log according to log level.""" + def __init__(self, base_formatter_factory, default_fmt: str = None, level_fmt: typing.Mapping[int, str] = None): + super().__init__() + self.default_formatter = base_formatter_factory(default_fmt) + self.level_formatter = { + level: base_formatter_factory(fmt) + for level, fmt in level_fmt.items() + } - def __init__(self): - super().__init__(fmt=self.FORMAT, datefmt=self.DATEFMT) + def format(self, record): + formatter = self.level_formatter.get(record.levelno) + if formatter is None: + formatter = self.default_formatter + return formatter.format(record) class DebugCustomFilter(logging.Filter): @@ -97,7 +168,7 @@ """ def filter(self, record): from .config import core - if record.levelname == "DEBUG": + if record.levelno == logging.DEBUG: return core.debug else: return True @@ -109,9 +180,9 @@ """ def filter(self, record): from .config import report - if record.levelname == "DEBUG": + if record.levelno == logging.DEBUG: return int(report.verbosity) >= 1 - if record.levelname == "DEBUG2": + if record.levelno == DEBUG2: return int(report.verbosity) > 1 else: return True @@ -140,13 +211,24 @@ "disable_existing_loggers": "False", "formatters": { "console_report": { - "()": ConsoleReportFormatter + "()": LeveledFormatter, + "base_formatter_factory": ConsoleColoredFormatter, + "default_fmt": "{}: %(levelname)s: %(message)s".format(socket.gethostname()), + "level_fmt": { + DEBUG2: "{}: %(levelname)s: %(funcName)s: %(message)s".format(socket.gethostname()), + }, }, "console": { - "()": ConsoleCustomFormatter + "()": LeveledFormatter, + "base_formatter_factory": ConsoleColoredFormatter, + "default_fmt": "%(levelname)s: %(message)s", + "level_fmt": { + DEBUG2: "%(levelname)s: %(funcName)s %(message)s", + }, }, "file": { - "()": FileCustomFormatter + "format": "%(asctime)s {} %(name)s: %(levelname)s: %(message)s".format(socket.gethostname()), + "datefmt": "%b %d %H:%M:%S", } }, "filters": { @@ -204,29 +286,44 @@ } +NO_COLOR_FORMATTERS = { + "console_report": { + "()": LeveledFormatter, + "base_formatter_factory": logging.Formatter, + "default_fmt": "{}: %(levelname)s: %(message)s".format(socket.gethostname()), + "level_fmt": { + DEBUG2: "{}: %(levelname)s: %(funcName)s: %(message)s".format(socket.gethostname()), + }, + }, + "console": { + "()": LeveledFormatter, + "base_formatter_factory": logging.Formatter, + "default_fmt": "%(levelname)s: %(message)s", + "level_fmt": { + DEBUG2: "%(levelname)s: %(funcName)s %(message)s", + }, + }, + "file": { + "format": "%(asctime)s {} %(name)s: %(levelname)s: %(message)s".format(socket.gethostname()), + "datefmt": "%b %d %H:%M:%S", + } +} + + class LoggerUtils(object): """ A class to keep/update some attributes related with logger Also has methods related with handler and formatter And a set of wrapped log message for specific scenarios """ - def __init__(self, logger): + def __init__(self, logger: NumberedLogger): """ Init function """ self.logger = logger # used in regression test - self.lineno = 0 self.__save_lineno = 0 - def set_debug2_level(self): - """ - Create DEBUG2 level for verbosity - """ - logging.DEBUG2 = logging.DEBUG + 5 - logging.addLevelName(logging.DEBUG2, "DEBUG2") - self.logger.debug2 = lambda msg, *args: self.logger._log(logging.DEBUG2, msg, args) - def get_handler(self, _type): """ Get logger specific handler @@ -244,39 +341,17 @@ console_handler = self.get_handler("console") console_handler.setLevel(logging.WARNING) - def set_console_formatter(self, lineno): - """ - Pass line number to ConsoleCustomFormatter - """ - console_handler = self.get_handler("console") - console_handler.setFormatter(ConsoleCustomFormatter(lineno=lineno)) - def reset_lineno(self, to=0): """ Reset line number """ - self.lineno = to - self.set_console_formatter(to) + self.logger.reset_lineno(to) def incr_lineno(self): """ Increase line number """ - self.lineno += 1 - self.set_console_formatter(self.lineno) - - @contextmanager - def suppress_new_line(self): - """ - Supress new line in console - """ - console_handler = self.get_handler("console") - try: - console_handler.terminator = "" - yield - finally: - sys.stdout.flush() - console_handler.terminator = "\n" + self.logger.incr_lineno() @contextmanager def only_file(self): @@ -330,11 +405,11 @@ Mark the line number in the log record """ try: - self.__save_lineno = self.lineno + self.__save_lineno = self.logger.lineno self.reset_lineno() yield finally: - self.reset_lineno(self.__save_lineno) + self.logger.reset_lineno(self.__save_lineno) @contextmanager def status_long(self, msg): @@ -469,7 +544,14 @@ except (PermissionError, FileNotFoundError) as e: print('{}WARNING:{} Failed to open log file: {}'.format(constants.YELLOW, constants.END, e), file=sys.stderr) LOGGING_CFG["handlers"]["file"] = {'class': 'logging.NullHandler'} - logging.config.dictConfig(LOGGING_CFG) + logging.addLevelName(DEBUG2, "DEBUG2") + if os.environ.get('CRMSH_REGRESSION_TEST'): + logging.setLoggerClass(NumberedLogger) + LOGGING_CFG['formatters'] = NO_COLOR_FORMATTERS + logging.config.dictConfig(LOGGING_CFG) + else: + logging.setLoggerClass(NumberedLoggerInterface) + logging.config.dictConfig(LOGGING_CFG) def setup_logger(name): @@ -489,6 +571,4 @@ Get the logger for crm report """ logger = setup_logger(name) - logger_utils = LoggerUtils(logger) - logger_utils.set_debug2_level() return logger diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/crmsh/main.py new/crmsh-4.6.0+20231211.4b74412a/crmsh/main.py --- old/crmsh-4.6.0+20231207.89c74e6c/crmsh/main.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/crmsh/main.py 2023-12-11 03:36:33.000000000 +0100 @@ -45,8 +45,8 @@ try: if not context.run(inp): raise ValueError("Error in RC file: " + rcfile) - except ValueError as msg: - logger.error(msg) + except ValueError as e: + logger.error(e, exc_info=e) f.close() sys.stdin = save_stdin @@ -261,14 +261,16 @@ try: if not context.run(inp): rc = 1 - except ValueError as msg: + except ValueError as e: rc = 1 - logger.error(msg) + logger.error(e, exc_info=e) except KeyboardInterrupt: if options.interactive and not options.batch: print("Ctrl-C, leaving") context.quit(1) - return rc + except Exception as e: + logger.error(e, exc_info=e) + context.quit(1) def compgen(): @@ -374,11 +376,10 @@ print("Ctrl-C, leaving") sys.exit(1) except ValueError as e: - if config.core.debug: - import traceback - traceback.print_exc() - sys.stdout.flush() - logger.error(str(e)) + logger.error(e, exc_info=e) sys.exit(1) + except Exception as e: + logger.error(e, exc_info=e) + raise # vim:ts=4:sw=4:et: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/crmsh/ui_context.py new/crmsh-4.6.0+20231211.4b74412a/crmsh/ui_context.py --- old/crmsh-4.6.0+20231207.89c74e6c/crmsh/ui_context.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/crmsh/ui_context.py 2023-12-11 03:36:33.000000000 +0100 @@ -84,12 +84,8 @@ if cmd: utils.check_user_access(self.current_level().name) rv = self.execute_command() is not False - except (ValueError, IOError) as msg: - if config.core.debug or options.regression_tests: - import traceback - traceback.print_exc() - sys.stdout.flush() - logger.error("%s: %s", self.get_qualified_name(), msg) + except (ValueError, IOError) as e: + logger.error("%s: %s", self.get_qualified_name(), e, exc_info=e) rv = False except utils.TerminateSubCommand: return False diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/scripts/health/collect.py new/crmsh-4.6.0+20231211.4b74412a/scripts/health/collect.py --- old/crmsh-4.6.0+20231207.89c74e6c/scripts/health/collect.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/scripts/health/collect.py 2023-12-11 03:36:33.000000000 +0100 @@ -6,7 +6,11 @@ import hashlib import platform import crm_script + +import crmsh.log +crmsh.log.setup_logging() from crmsh.report import utils + data = crm_script.get_input() PACKAGES = ['booth', 'cluster-glue', 'corosync', 'crmsh', 'csync2', 'drbd', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/evaltest.sh new/crmsh-4.6.0+20231211.4b74412a/test/evaltest.sh --- old/crmsh-4.6.0+20231207.89c74e6c/test/evaltest.sh 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/evaltest.sh 2023-12-11 03:36:33.000000000 +0100 @@ -7,6 +7,7 @@ CRM_NO_REG="$CRM" CRM="$CRM -R" export PYTHONUNBUFFERED=1 +export CRMSH_REGRESSION_TEST=1 if [ "$1" = prof ]; then CRM="$CRM -X regtest.profile" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/edit.exp new/crmsh-4.6.0+20231211.4b74412a/test/testcases/edit.exp --- old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/edit.exp 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/testcases/edit.exp 2023-12-11 03:36:33.000000000 +0100 @@ -68,7 +68,7 @@ .INP: primitive d3 ocf:heartbeat:Dummy .INP: group g2 d1 d2 .INP: filter "sed '/g2/s/d1/p1/;/g1/s/p1/d1/'" -ERROR: Cannot create group:g1: Child primitive:d1 already in group:g2 +ERROR: 29: Cannot create group:g1: Child primitive:d1 already in group:g2 .INP: filter "sed '/g1/s/d1/p1/;/g2/s/p1/d1/'" .INP: filter "sed '$alocation loc-d1 d1 rule $id=r1 -inf: not_defined webserver rule $id=r2 webserver: defined webserver'" .INP: filter "sed 's/not_defined webserver/& or mem number:lte 0/'" loc-d1 @@ -83,33 +83,33 @@ .INP: modgroup g1 add p1 ERROR: 1: syntax in group: child p1 listed more than once in group g1 parsing 'group g1 p1 p2 d3 p1' .INP: modgroup g1 remove st +ERROR: 42: configure.modgroup: st is not member of g1 Traceback (most recent call last): rv = self.execute_command() is not False rv = self.command_info.function(*arglist) context.fatal_error("%s is not member of %s" % (prim_id, group_id)) raise ValueError(msg) ValueError: st is not member of g1 -ERROR: 42: configure.modgroup: st is not member of g1 .INP: modgroup g1 remove c1 +ERROR: 43: configure.modgroup: c1 is not member of g1 Traceback (most recent call last): rv = self.execute_command() is not False rv = self.command_info.function(*arglist) context.fatal_error("%s is not member of %s" % (prim_id, group_id)) raise ValueError(msg) ValueError: c1 is not member of g1 -ERROR: 43: configure.modgroup: c1 is not member of g1 .INP: modgroup g1 remove nosuch +ERROR: 44: configure.modgroup: nosuch is not member of g1 Traceback (most recent call last): rv = self.execute_command() is not False rv = self.command_info.function(*arglist) context.fatal_error("%s is not member of %s" % (prim_id, group_id)) raise ValueError(msg) ValueError: nosuch is not member of g1 -ERROR: 44: configure.modgroup: nosuch is not member of g1 .INP: modgroup g1 add c1 -ERROR: a group may contain only primitives; c1 is clone +ERROR: 45: a group may contain only primitives; c1 is clone .INP: modgroup g1 add nosuch -ERROR: g1 refers to missing object nosuch +ERROR: 46: g1 refers to missing object nosuch .INP: filter "sed 's/^/# this is a comment\n/'" loc-d1 .INP: rsc_defaults $id="rsc_options" failure-timeout=10m .INP: filter "sed 's/2m/60s/'" op-options diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/scripts.exp new/crmsh-4.6.0+20231211.4b74412a/test/testcases/scripts.exp --- old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/scripts.exp 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/testcases/scripts.exp 2023-12-11 03:36:33.000000000 +0100 @@ -240,13 +240,13 @@ virtual-ip vmware .INP: list bogus +ERROR: 7: script.list: Unexpected argument 'bogus': expected [all|names] Traceback (most recent call last): rv = self.execute_command() is not False rv = self.command_info.function(*arglist) context.fatal_error("Unexpected argument '%s': expected [all|names]" % (arg)) raise ValueError(msg) ValueError: Unexpected argument 'bogus': expected [all|names] -ERROR: 7: script.list: Unexpected argument 'bogus': expected [all|names] .INP: show mailto mailto (Basic) E-Mail diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/shadow.exp new/crmsh-4.6.0+20231211.4b74412a/test/testcases/shadow.exp --- old/crmsh-4.6.0+20231207.89c74e6c/test/testcases/shadow.exp 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/testcases/shadow.exp 2023-12-11 03:36:33.000000000 +0100 @@ -11,13 +11,13 @@ .EXT >/dev/null </dev/null crm_shadow -b -C 'regtest' --force INFO: 5: cib.commit: committed 'regtest' shadow CIB to the cluster .INP: delete regtest +ERROR: 6: cib.delete: regtest shadow CIB is in use Traceback (most recent call last): rv = self.execute_command() is not False rv = self.command_info.function(*arglist) context.fatal_error("%s shadow CIB is in use" % name) raise ValueError(msg) ValueError: regtest shadow CIB is in use -ERROR: 6: cib.delete: regtest shadow CIB is in use .INP: use .INP: delete regtest .EXT >/dev/null </dev/null crm_shadow -b -D 'regtest' --force diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_collect.py new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_collect.py --- old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_collect.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_collect.py 2023-12-11 03:36:33.000000000 +0100 @@ -1,5 +1,6 @@ from subprocess import TimeoutExpired from crmsh.report import collect, constants +import crmsh.log import unittest from unittest import mock @@ -80,13 +81,12 @@ self.assertEqual(collect.get_corosync_log(), mock_get_value.return_value) @mock.patch('crmsh.report.utils.real_path') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.utils.get_cmd_output') - @mock.patch('logging.Logger.debug') @mock.patch('crmsh.report.utils.ts_to_str') - def test_collect_journal_logs(self, mock_ts_to_str, mock_debug, mock_get_cmd_output, - mock_str2file, mock_debug2, mock_real_path): + def test_collect_journal_logs(self, mock_ts_to_str, mock_get_cmd_output, + mock_str2file, mock_logger, mock_real_path): mock_real_path.side_effect = [ constants.JOURNAL_F, constants.JOURNAL_PCMK_F, @@ -113,14 +113,14 @@ mock.call(cmd_list[2]), mock.call(cmd_list[3]), ]) - mock_debug2.assert_has_calls([ + mock_logger.debug2.assert_has_calls([ mock.call("Collect journal logs since: 10.10 until: 10.12"), mock.call(f"Running command: {cmd_list[0]}"), mock.call(f"Running command: {cmd_list[1]}"), mock.call(f"Running command: {cmd_list[2]}"), mock.call(f"Running command: {cmd_list[3]}"), ]) - mock_debug.assert_has_calls([ + mock_logger.debug.assert_has_calls([ mock.call(f"Dump jounal log for default into {constants.JOURNAL_F}"), mock.call(f"Dump jounal log for pacemaker into {constants.JOURNAL_PCMK_F}"), mock.call(f"Dump jounal log for corosync into {constants.JOURNAL_COROSYNC_F}"), @@ -214,13 +214,13 @@ mock_warning.assert_called_once_with('pe_to_dot: %s -> %s failed', '/opt/pe-input-0.bz2', '/opt/pe-input-0.dot') @mock.patch('crmsh.report.utils.find_files_in_timespan') - @mock.patch('crmsh.report.collect.logger.debug2') - def test_collect_pe_inputs_no_found(self, mock_debug, mock_find_files): + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) + def test_collect_pe_inputs_no_found(self, mock_logger, mock_find_files): mock_ctx_inst = mock.Mock(pe_dir="/opt/pe_dir") mock_find_files.return_value = [] collect.collect_pe_inputs(mock_ctx_inst) mock_find_files.assert_called_once_with(mock_ctx_inst, [mock_ctx_inst.pe_dir]) - mock_debug.assert_has_calls([ + mock_logger.debug2.assert_has_calls([ mock.call(f"Looking for PE files in {mock_ctx_inst.pe_dir}"), mock.call("No PE file found for the giving time") ]) @@ -230,9 +230,8 @@ @mock.patch('os.symlink') @mock.patch('crmsh.utils.mkdirp') @mock.patch('crmsh.report.utils.find_files_in_timespan') - @mock.patch('crmsh.report.collect.logger.debug2') - @mock.patch('logging.Logger.debug') - def test_collect_pe_inputs(self, mock_debug, mock_debug2, mock_find_files, mock_mkdir, mock_symlink, mock_to_dot, mock_real_path): + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) + def test_collect_pe_inputs(self, mock_logger, mock_find_files, mock_mkdir, mock_symlink, mock_to_dot, mock_real_path): mock_real_path.return_value = "pe_dir" mock_ctx_inst = mock.Mock(pe_dir="/opt/pe_dir", work_dir="/opt/work_dir", speed_up=False) mock_find_files.return_value = ["/opt/pe_dir/pe_input1", "/opt/pe_dir/pe_input2"] @@ -240,18 +239,17 @@ collect.collect_pe_inputs(mock_ctx_inst) mock_find_files.assert_called_once_with(mock_ctx_inst, [mock_ctx_inst.pe_dir]) - mock_debug2.assert_has_calls([ + mock_logger.debug2.assert_has_calls([ mock.call(f"Looking for PE files in {mock_ctx_inst.pe_dir}"), mock.call(f"Found 2 PE files in {mock_ctx_inst.pe_dir}"), ]) - mock_debug.assert_called_once_with(f"Dump PE files into pe_dir") + mock_logger.debug.assert_called_once_with(f"Dump PE files into pe_dir") @mock.patch('crmsh.report.utils.real_path') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') - @mock.patch('logging.Logger.warning') @mock.patch('crmsh.report.utils.get_cmd_output') - def test_collect_sys_stats(self, mock_run, mock_warning, mock_str2file, mock_debug2, mock_real_path): + def test_collect_sys_stats(self, mock_run, mock_str2file, mock_logger, mock_real_path): mock_real_path.return_value = constants.SYSSTATS_F mock_run.side_effect = [ "data_hostname", "data_uptime", "data_ps_axf", "data_ps_auxw", @@ -260,7 +258,7 @@ ] mock_ctx_inst = mock.Mock(work_dir="/opt") collect.collect_sys_stats(mock_ctx_inst) - mock_warning.assert_called_once_with(f"Timeout while running command: df") + mock_logger.warning.assert_called_once_with(f"Timeout while running command: df") mock_run.assert_has_calls([ mock.call("hostname", timeout=5), mock.call("uptime", timeout=5), @@ -302,7 +300,7 @@ @mock.patch('crmsh.report.utils.real_path') @mock.patch('crmsh.report.collect.dump_configurations') @mock.patch('crmsh.report.collect.consume_cib_in_workdir') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.collect.dump_runtime_state') @mock.patch('crmsh.report.collect.ServiceManager') @@ -317,7 +315,7 @@ @mock.patch('crmsh.report.utils.real_path') @mock.patch('crmsh.report.collect.dump_configurations') @mock.patch('crmsh.report.collect.consume_cib_in_workdir') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('shutil.copy2') @mock.patch('crmsh.report.collect.ServiceManager') @@ -348,24 +346,23 @@ mock.call("data2", f"/workdir/{constants.CRM_VERIFY_F}") ]) - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.report.collect.sh.cluster_shell') - def test_collect_ratraces_return(self, mock_run, mock_debug): + def test_collect_ratraces_return(self, mock_run, mock_logger): mock_run_inst = mock.Mock() mock_run.return_value = mock_run_inst mock_run_inst.get_rc_stdout_stderr_without_input.return_value = (0, "data", None) mock_ctx_inst = mock.Mock(node_list=["node1"]) collect.collect_ratraces(mock_ctx_inst) - mock_debug.assert_not_called() + mock_logger.debug2.assert_not_called() @mock.patch('crmsh.report.utils.real_path') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('shutil.copy2') @mock.patch('crmsh.utils.mkdirp') @mock.patch('crmsh.report.utils.find_files_in_timespan') - @mock.patch('logging.Logger.debug') @mock.patch('crmsh.report.collect.sh.cluster_shell') - def test_collect_ratraces(self, mock_run, mock_debug, mock_find, mock_mkdirp, mock_copy, mock_debug2, mock_real_path): + def test_collect_ratraces(self, mock_run, mock_find, mock_mkdirp, mock_copy, mock_logger, mock_real_path): mock_real_path.return_value = "/var/log" mock_run_inst = mock.Mock() mock_run.return_value = mock_run_inst @@ -376,8 +373,8 @@ collect.collect_ratraces(mock_ctx_inst) - mock_debug2.assert_called_once_with('Looking for RA trace files in "%s"', '/var/log/cluster') - mock_debug.assert_called_once_with(f'Dump RA trace files into {mock_real_path.return_value}') + mock_logger.debug2.assert_called_once_with('Looking for RA trace files in "%s"', '/var/log/cluster') + mock_logger.debug.assert_called_once_with(f'Dump RA trace files into {mock_real_path.return_value}') @mock.patch('crmsh.report.collect.ShellUtils') def test_lsof_ocfs2_device(self, mock_run): @@ -406,7 +403,7 @@ res = collect.ocfs2_commands_output() self.assertEqual(res, "\n\n#===== [ Command ] ==========================#\n# mount\ndata") - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.collect.ShellUtils') def test_collect_ocfs2_info_error(self, mock_run, mock_str2file, mock_debug2): @@ -417,7 +414,7 @@ collect.collect_ocfs2_info(mock_ctx_inst) mock_str2file.assert_called_once_with('Failed to run "mounted.ocfs2 -d": error', '/opt/workdir/ocfs2.txt') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.collect.ShellUtils') def test_collect_ocfs2_info_no_found(self, mock_run, mock_str2file, mock_debug2): @@ -432,7 +429,7 @@ @mock.patch('crmsh.report.collect.ocfs2_commands_output') @mock.patch('crmsh.report.collect.lsof_ocfs2_device') @mock.patch('crmsh.report.collect.dump_D_process') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.collect.ShellUtils') def test_collect_ocfs2_info(self, mock_run, mock_str2file, mock_debug2, mock_D, mock_lsof, mock_output, mock_real_path): @@ -492,19 +489,17 @@ self.assertEqual("Core core.1 was generated by /usr/sbin/crm_mon", res) @mock.patch('crmsh.report.utils.real_path') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') - @mock.patch('logging.Logger.warning') @mock.patch('shutil.which') - def test_dump_core_info_no_gdb(self, mock_which, mock_warning, mock_str2file, mock_debug2, mock_real_path): + def test_dump_core_info_no_gdb(self, mock_which, mock_str2file, mock_logger, mock_real_path): mock_real_path.return_value = constants.COREDUMP_F mock_which.return_value = False collect.dump_core_info("/opt/workdir", ["core.1"]) - mock_warning.assert_called_once_with("Please install gdb to get more info for coredump files") - mock_debug2(f"Dump coredump info into {constants.COREDUMP_F}") + mock_logger.warning.assert_called_once_with("Please install gdb to get more info for coredump files") @mock.patch('crmsh.report.utils.real_path') - @mock.patch('crmsh.report.collect.logger.debug2') + @mock.patch('crmsh.report.collect.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.str2file') @mock.patch('crmsh.report.collect.find_binary_path_for_core') @mock.patch('shutil.which') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_core.py new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_core.py --- old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_core.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_core.py 2023-12-11 03:36:33.000000000 +0100 @@ -1,5 +1,6 @@ from crmsh import config from crmsh.report import core, constants, utils, collect +import crmsh.log import sys import argparse @@ -164,30 +165,30 @@ ]) @mock.patch('os.path.basename') - @mock.patch('crmsh.report.core.logger.debug2') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.mkdirp') @mock.patch('crmsh.report.core.is_collector') @mock.patch('crmsh.report.core.tmpfiles.create_dir') - def test_setup_workdir_collector(self, mock_create_dir, mock_collector, mock_mkdirp, mock_debug, mock_basename): + def test_setup_workdir_collector(self, mock_create_dir, mock_collector, mock_mkdirp, mock_logger, mock_basename): mock_create_dir.return_value = "/tmp/tmp_dir" mock_ctx_inst = mock.Mock(dest="/opt/report", work_dir="/opt/work_dir", me="node1") mock_collector.return_value = True mock_basename.return_value = "report" core.setup_workdir(mock_ctx_inst) - mock_debug.assert_called_once_with(f"Setup work directory in {mock_ctx_inst.work_dir}") + mock_logger.debug2.assert_called_once_with(f"Setup work directory in {mock_ctx_inst.work_dir}") @mock.patch('os.path.basename') - @mock.patch('crmsh.report.core.logger.debug2') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.mkdirp') @mock.patch('crmsh.report.core.is_collector') @mock.patch('crmsh.report.core.tmpfiles.create_dir') - def test_setup_workdir(self, mock_create_dir, mock_collector, mock_mkdirp, mock_debug, mock_basename): + def test_setup_workdir(self, mock_create_dir, mock_collector, mock_mkdirp, mock_logger, mock_basename): mock_create_dir.return_value = "/tmp/tmp_dir" mock_ctx_inst = mock.Mock(dest="/opt/report", work_dir="/opt/work_dir") mock_collector.return_value = False mock_basename.return_value = "report" core.setup_workdir(mock_ctx_inst) - mock_debug.assert_called_once_with(f"Setup work directory in {mock_ctx_inst.work_dir}") + mock_logger.debug2.assert_called_once_with(f"Setup work directory in {mock_ctx_inst.work_dir}") @mock.patch('os.path.isdir') @mock.patch('crmsh.report.core.load_from_crmsh_config') @@ -242,8 +243,8 @@ @mock.patch('crmsh.report.core.adjust_verbosity') @mock.patch('crmsh.report.core.config') @mock.patch('json.loads') - @mock.patch('crmsh.report.core.logger.debug2') - def test_load_context(self, mock_debug2, mock_json_loads, mock_config, mock_verbosity): + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) + def test_load_context(self, mock_logger, mock_json_loads, mock_config, mock_verbosity): class Context: def __str__(self): return "data" @@ -255,7 +256,7 @@ mock_json_loads.return_value = {"key": "value", "debug": "true"} mock_ctx_inst = Context() core.load_context(mock_ctx_inst) - mock_debug2.assert_called_once_with("Loading context from collector: data") + mock_logger.debug2.assert_called_once_with("Loading context from collector: data") @mock.patch('crmsh.report.core.adjust_verbosity') @mock.patch('crmsh.report.core.process_arguments') @@ -361,10 +362,10 @@ core.add_arguments() - @mock.patch('crmsh.report.core.logger.debug2') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.to_ascii') @mock.patch('crmsh.report.core.ShellUtils') - def test_push_data(self, mock_sh_utils, mock_to_ascii, mock_debug): + def test_push_data(self, mock_sh_utils, mock_to_ascii, mock_logger): mock_sh_utils_inst = mock.Mock() mock_sh_utils.return_value = mock_sh_utils_inst mock_sh_utils_inst.get_stdout_stderr.return_value = (0, "data", "error") @@ -375,7 +376,7 @@ core.push_data(mock_ctx_inst) self.assertEqual("error", str(err.exception)) - mock_debug.assert_called_once_with("Pushing data from node1:/opt/work_dir to node1") + mock_logger.debug2.assert_called_once_with("Pushing data from node1:/opt/work_dir to node1") mock_sh_utils_inst.get_stdout_stderr.assert_called_once_with("cd /opt/work_dir/.. && tar -h -c node1", raw=True) @mock.patch('crmsh.report.core.finalword') @@ -392,7 +393,7 @@ @mock.patch('crmsh.report.core.finalword') @mock.patch('crmsh.report.core.sh.cluster_shell') - @mock.patch('crmsh.report.core.logger.debug2') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.report.utils.create_description_template') @mock.patch('crmsh.report.utils.analyze') @mock.patch('crmsh.report.utils.do_sanitize') @@ -478,21 +479,19 @@ mock_ctx_inst = mock.Mock(from_time=123, to_time=150) core.process_arguments(mock_ctx_inst) - @mock.patch('crmsh.report.core.logger.debug2') - @mock.patch('logging.Logger.warning') - @mock.patch('logging.Logger.debug') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.utils.check_ssh_passwd_need') @mock.patch('crmsh.report.core.userdir.getuser') @mock.patch('crmsh.report.core.userdir.get_sudoer') - def test_find_ssh_user_not_found(self, mock_get_sudoer, mock_getuser, mock_check_ssh, mock_debug, mock_warn, mock_debug2): + def test_find_ssh_user_not_found(self, mock_get_sudoer, mock_getuser, mock_check_ssh, mock_logger): mock_get_sudoer.return_value = "" mock_getuser.return_value = "user2" mock_check_ssh.return_value = True mock_ctx_inst = mock.Mock(ssh_user="", ssh_askpw_node_list=[], node_list=["node1", "node2"], me="node1") core.find_ssh_user(mock_ctx_inst) - mock_warn.assert_called_once_with(f"passwordless ssh to node(s) ['node2'] does not work") + mock_logger.warning.assert_called_once_with(f"passwordless ssh to node(s) ['node2'] does not work") - @mock.patch('crmsh.report.core.logger.debug2') + @mock.patch('crmsh.report.core.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('logging.Logger.warning') @mock.patch('logging.Logger.debug') @mock.patch('crmsh.utils.check_ssh_passwd_need') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_utils.py new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_utils.py --- old/crmsh-4.6.0+20231207.89c74e6c/test/unittests/test_report_utils.py 2023-12-07 10:20:33.000000000 +0100 +++ new/crmsh-4.6.0+20231211.4b74412a/test/unittests/test_report_utils.py 2023-12-11 03:36:33.000000000 +0100 @@ -3,6 +3,7 @@ from crmsh import config from crmsh import utils as crmutils from crmsh.report import utils, constants +import crmsh.log import unittest from unittest import mock @@ -160,19 +161,19 @@ self.assertEqual(self.s_inst.cib_data, "data") mock_read.assert_called_once_with(f"/opt/node1/{constants.CIB_F}") - @mock.patch('crmsh.report.utils.logger.debug2') - def test_parse_sensitive_set_no_set(self, mock_debug2): + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) + def test_parse_sensitive_set_no_set(self, mock_logger): config.report.sanitize_rule = "" self.s_inst_no_sanitize_set._parse_sensitive_set() self.assertEqual(self.s_inst_no_sanitize_set.sensitive_regex_set, set(utils.Sanitizer.DEFAULT_RULE_LIST)) - mock_debug2.assert_called_once_with(f"Regex set to match sensitive data: {set(utils.Sanitizer.DEFAULT_RULE_LIST)}") + mock_logger.debug2.assert_called_once_with(f"Regex set to match sensitive data: {set(utils.Sanitizer.DEFAULT_RULE_LIST)}") - @mock.patch('crmsh.report.utils.logger.debug2') - def test_parse_sensitive_set(self, mock_debug2): + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) + def test_parse_sensitive_set(self, mock_logger): config.report.sanitize_rule = "passw.*" self.s_inst._parse_sensitive_set() self.assertEqual(self.s_inst.sensitive_regex_set, set(['test_patt', 'passw.*'])) - mock_debug2.assert_called_once_with(f"Regex set to match sensitive data: {set(['test_patt', 'passw.*'])}") + mock_logger.debug2.assert_called_once_with(f"Regex set to match sensitive data: {set(['test_patt', 'passw.*'])}") def test_sanitize_return(self): self.s_inst_no_sanitize.sanitize() @@ -234,10 +235,10 @@ @mock.patch('builtins.sorted', side_effect=lambda x, *args, **kwargs: x[::-1]) @mock.patch('crmsh.report.utils.get_timespan_str') - @mock.patch('crmsh.report.utils.logger.debug2') + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('glob.glob') @mock.patch('crmsh.report.utils.is_our_log') - def test_arch_logs(self, mock_is_our_log, mock_glob, mock_debug2, mock_timespan, mock_sorted): + def test_arch_logs(self, mock_is_our_log, mock_glob, mock_logger, mock_timespan, mock_sorted): mock_is_our_log.return_value = utils.LogType.GOOD mock_glob.return_value = [] mock_ctx_inst = mock.Mock() @@ -247,7 +248,7 @@ self.assertEqual(return_list, ["file1"]) self.assertEqual(log_type, utils.LogType.GOOD) - mock_debug2.assert_called_once_with("Found logs ['file1'] in 0101-0202") + mock_logger.debug2.assert_called_once_with("Found logs ['file1'] in 0101-0202") @mock.patch('sys.stdout.flush') @mock.patch('traceback.print_exc') @@ -360,7 +361,7 @@ self.assertEqual(res, expected_result) @mock.patch('crmsh.report.utils.get_timespan_str') - @mock.patch('crmsh.report.utils.logger.debug2') + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.report.utils.arch_logs') def test_dump_logset_return(self, mock_arch, mock_debug, mock_timespan): mock_arch.return_value = [[], ""] @@ -428,7 +429,7 @@ @mock.patch('crmsh.utils.read_from_file') @mock.patch('os.path.exists') - @mock.patch('crmsh.report.utils.logger.debug2') + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) def test_get_distro_info(self, mock_debug2, mock_exists, mock_read): mock_exists.return_value = True mock_read.return_value = """ @@ -442,7 +443,7 @@ @mock.patch('shutil.which') @mock.patch('crmsh.report.utils.sh.LocalShell') @mock.patch('os.path.exists') - @mock.patch('crmsh.report.utils.logger.debug2') + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) def test_get_distro_info_lsb(self, mock_debug2, mock_exists, mock_sh, mock_which): mock_which.return_value = True mock_exists.return_value = False @@ -643,15 +644,15 @@ self.assertEqual(res, "") @mock.patch('crmsh.report.utils.filter_lines') - @mock.patch('crmsh.report.utils.logger.debug2') + @mock.patch('crmsh.report.utils.logger', spec=crmsh.log.DEBUG2Logger) @mock.patch('crmsh.report.utils.findln_by_timestamp') @mock.patch('crmsh.utils.read_from_file') - def test_print_logseg(self, mock_read, mock_findln, mock_debug, mock_filter): + def test_print_logseg(self, mock_read, mock_findln, mock_logger, mock_filter): mock_read.return_value = "line1\nline2\nline3" mock_filter.return_value = "line1\nline2\nline3" res = utils.print_logseg("log1", 0, 0) self.assertEqual(res, mock_filter.return_value) - mock_debug.assert_called_once_with("Including segment [%d-%d] from %s", 1, 3, "log1") + mock_logger.debug2.assert_called_once_with("Including segment [%d-%d] from %s", 1, 3, "log1") def test_head(self): data = "line1\nline2\nline3"