def test_parse_logline_syslog(self): """Tests if the parse_logline() function parses syslog correctly. """ line = ("Feb 22 10:17:10 host malware-domain-list-collector: ERROR " "Something went wrong") thread = ( "Feb 22 10:17:10 host malware-domain-list-collector.4: ERROR " "Something went wrong") actual = utils.parse_logline(line, regex=utils.SYSLOG_REGEX) self.assertEqual( { 'bot_id': 'malware-domain-list-collector', 'date': '%d-02-22T10:17:10' % datetime.datetime.now().year, 'thread_id': None, 'log_level': 'ERROR', 'message': 'Something went wrong' }, actual) actual = utils.parse_logline(thread, regex=utils.SYSLOG_REGEX) self.assertEqual( { 'bot_id': 'malware-domain-list-collector', 'date': '%d-02-22T10:17:10' % datetime.datetime.now().year, 'thread_id': 4, 'log_level': 'ERROR', 'message': 'Something went wrong' }, actual)
def test_parse_logline(self): """Tests if the parse_logline() function works as expected""" line = ("2015-05-29 21:00:24,379 - malware-domain-list-collector - " "ERROR - Something went wrong") thread = ( "2015-05-29 21:00:24,379 - malware-domain-list-collector.4 - " "ERROR - Something went wrong") fields = utils.parse_logline(line) self.assertDictEqual( { 'date': '2015-05-29T21:00:24.379000', 'bot_id': 'malware-domain-list-collector', 'thread_id': None, 'log_level': 'ERROR', 'message': 'Something went wrong' }, fields) fields = utils.parse_logline(thread) self.assertDictEqual( { 'date': '2015-05-29T21:00:24.379000', 'bot_id': 'malware-domain-list-collector', 'thread_id': 4, 'log_level': 'ERROR', 'message': 'Something went wrong' }, fields)
def read_bot_log(self, bot_id, log_level, number_of_lines): if self.parameters.logging_handler == 'file': bot_log_path = os.path.join(self.parameters.logging_path, bot_id + '.log') if not os.path.isfile(bot_log_path): logger.error("Log path not found: {}".format(bot_log_path)) return [] elif self.parameters.logging_handler == 'syslog': bot_log_path = '/var/log/syslog' if not os.access(bot_log_path, os.R_OK): self.logger.error('File %r is not readable.' % bot_log_path) return 'error' messages = list() message_overflow = '' message_count = 0 for line in utils.reverse_readline(bot_log_path): if self.parameters.logging_handler == 'file': log_message = utils.parse_logline(line) if self.parameters.logging_handler == 'syslog': log_message = utils.parse_logline(line, regex=utils.SYSLOG_REGEX) if type(log_message) is not dict: if self.parameters.logging_handler == 'file': message_overflow = '\n'.join([line, message_overflow]) continue if log_message['bot_id'] != bot_id: continue if LOG_LEVEL[log_message['log_level']] < LOG_LEVEL[log_level]: continue if message_overflow: log_message['extended_message'] = message_overflow message_overflow = '' if self.parameters.logging_handler == 'syslog': log_message['message'] = log_message['message'].replace( '#012', '\n') message_count += 1 messages.append(log_message) if message_count >= number_of_lines and number_of_lines != -1: break log_log_messages(messages[::-1]) return messages[::-1]
def read_bot_log(self, bot_id, log_level, number_of_lines): if self.parameters.logging_handler == 'file': bot_log_path = os.path.join(self.parameters.logging_path, bot_id + '.log') if not os.path.isfile(bot_log_path): logger.error("Log path not found: %s", bot_log_path) return 2, [] elif self.parameters.logging_handler == 'syslog': bot_log_path = '/var/log/syslog' else: self.abort("Unknow logging handler %r" % self.parameters.logging_handler) if not os.access(bot_log_path, os.R_OK): self.logger.error('File %r is not readable.', bot_log_path) return 1, 'error' messages = [] message_overflow = '' message_count = 0 for line in utils.reverse_readline(bot_log_path): if self.parameters.logging_handler == 'file': log_message = utils.parse_logline(line) if self.parameters.logging_handler == 'syslog': log_message = utils.parse_logline(line, regex=utils.SYSLOG_REGEX) if type(log_message) is not dict: if self.parameters.logging_handler == 'file': message_overflow = '\n'.join([line, message_overflow]) continue if log_message['bot_id'] != bot_id: continue if LOG_LEVEL[log_message['log_level']] < LOG_LEVEL[log_level]: continue if message_overflow: log_message['extended_message'] = message_overflow message_overflow = '' if self.parameters.logging_handler == 'syslog': log_message['message'] = log_message['message'].replace('#012', '\n') message_count += 1 messages.append(log_message) if message_count >= number_of_lines and number_of_lines != -1: break log_log_messages(messages[::-1]) return 0, messages[::-1]
def test_logs(self): """ Test if bot log messages are correctly formatted. """ self.run_bot() self.assertLoglineMatches( 0, "{} initialized with id {} and version" " [0-9.]{{5}} \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" " as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") for logline in self.loglines: fields = utils.parse_logline(logline) self.assertTrue(fields['message'][-1] in '.?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue( fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not beginn with an upper case char.' ''.format(fields['message'])) self.assertNotRegexpMatchesLog("(ERROR.*?){}" "".format(self.allowed_error_count)) self.assertNotRegexpMatchesLog("CRITICAL") # """ Test if all pipes are created with correct names. """ pipenames = ["{}-input", "{}-input-internal", "{}-output"] self.assertSetEqual({x.format(self.bot_id) for x in pipenames}, set(self.pipe.state.keys()))
def read_bot_log(self, bot_id, log_level, number_of_lines): bot_log_path = os.path.join(self.parameters.logging_path, bot_id + '.log') if not os.path.isfile(bot_log_path): logger.error("Log path not found: {}".format(bot_log_path)) return [] messages = list() message_overflow = '' message_count = 0 for line in utils.reverse_readline(bot_log_path): log_message = utils.parse_logline(line) if type(log_message) is not dict: message_overflow = '\n'.join([line, message_overflow]) continue if LOG_LEVEL[log_message['log_level']] < log_level: continue if message_overflow: log_message['extended_message'] = message_overflow message_overflow = '' message_count += 1 messages.append(log_message) if message_count >= number_of_lines and number_of_lines != -1: break log_log_messages(messages[::-1]) return messages[::-1]
def run_bot(self, iterations: int = 1, error_on_pipeline: bool = False): """ Call this method for actually doing a test run for the specified bot. Parameters: iterations: Bot instance will be run the given times, defaults to 1. """ self.prepare_bot() with mock.patch('intelmq.lib.utils.load_configuration', new=self.mocked_config): with mock.patch('intelmq.lib.utils.log', self.mocked_log): for run in range(iterations): self.bot.start(error_on_pipeline=error_on_pipeline, source_pipeline=self.pipe, destination_pipeline=self.pipe) self.loglines_buffer = self.log_stream.getvalue() self.loglines = self.loglines_buffer.splitlines() """ Test if all pipes are created with correct names. """ pipenames = ["{}-input", "{}-input-internal", "{}-output"] self.assertSetEqual({x.format(self.bot_id) for x in pipenames}, set(self.pipe.state.keys())) """ Test if report has required fields. """ if self.bot_type == 'collector': for report_json in self.get_output_queue(): report = message.MessageFactory.unserialize( report_json, harmonization=self.harmonization) self.assertIsInstance(report, message.Report) self.assertIn('feed.name', report) self.assertIn('raw', report) self.assertIn('time.observation', report) """ Test if event has required fields. """ if self.bot_type == 'parser': for event_json in self.get_output_queue(): event = message.MessageFactory.unserialize( event_json, harmonization=self.harmonization) self.assertIsInstance(event, message.Event) self.assertIn('classification.type', event) self.assertIn('raw', event) """ Test if bot log messages are correctly formatted. """ self.assertLoglineMatches( 0, "{} initialized with id {} and version" " [0-9.]{{5}} \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" " as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") self.assertNotRegexpMatchesLog("(ERROR.*?){%d}" % (self.allowed_error_count + 1)) self.assertNotRegexpMatchesLog("CRITICAL") """ If no error happened (incl. tracebacks, we can check for formatting) """ if not self.allowed_error_count: # This would fail for tracebacks currently for logline in self.loglines: fields = utils.parse_logline(logline) self.assertTrue(fields['message'][-1] in '.:?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue( fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not begin with an upper case char.' ''.format(fields['message']))
def test_logs(self): # """ Test if bot logs initialized message. """ self.run_bot() self.assertLoglineMatches(0, "{} initialized with id {} and version" " [0-9.]{{5}} \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" " as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") for logline in self.loglines: fields = utils.parse_logline(logline) self.assertTrue(fields['message'][-1] in '.?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue(fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not beginn with an upper case char.' ''.format(fields['message'])) self.assertNotRegexpMatchesLog("(ERROR.*?){}" "".format(self.allowed_error_count)) self.assertNotRegexpMatchesLog("CRITICAL") # """ Test if all pipes are created with correct names. """ pipenames = ["{}-input", "{}-input-internal", "{}-output"] self.assertSetEqual({x.format(self.bot_id) for x in pipenames}, set(self.pipe.state.keys()))
def test_log_end_dot(self): """ Test if every log lines ends with a dot. """ for logline in self.loglines: fields = utils.parse_logline(logline) self.assertTrue(fields['message'].endswith('.'), msg='Logline {} does not end with dot.' ''.format(fields['message']))
def read_bot_log(self, bot_id, log_level, number_of_lines): bot_log_path = os.path.join(self.system['logging_path'], bot_id + '.log') if not os.path.isfile(bot_log_path): logger.error("Log path not found: {}".format(bot_log_path)) return [] messages = list() message_overflow = '' message_count = 0 for line in utils.reverse_readline(bot_log_path): log_message = utils.parse_logline(line) if type(log_message) is not dict: message_overflow = '\n'.join([line, message_overflow]) continue if LOG_LEVEL[log_message['log_level']] < log_level: continue if message_overflow: log_message['extended_message'] = message_overflow message_overflow = '' message_count += 1 messages.append(log_message) if message_count >= number_of_lines and number_of_lines != -1: break log_log_messages(messages[::-1]) return messages[::-1]
def assertLoglineEqual(self, line_no: int, message: str, levelname: str = "ERROR"): """ Asserts if a logline matches a specific requirement. Parameters: line_no: Number of the logline which is asserted message: Message text which is compared levelname: Log level of logline which is asserted """ if sys.version_info >= (3, 7): return True self.assertIsNotNone(self.loglines) logline = self.loglines[line_no] fields = utils.parse_logline(logline) self.assertEqual( self.bot_id, fields["bot_id"], "bot_id %s didn't match %s" "".format(self.bot_id, fields["bot_id"])) self.assertEqual(levelname, fields["log_level"]) self.assertEqual(message, fields["message"])
def test_parse_logline_invalid(self): """Tests if the parse_logline() function returns the line. """ line = (" report = self.receive_message()\n File" " \"/usr/local/lib/python3.4/dist-packages/intelmq-1.0.0" "-py3.4.egg/intelmq/lib/bot.py\", line 259, in" " receive_message") actual = utils.parse_logline(line) self.assertEqual(line, actual)
def run_bot(self, iterations=1): """ Call this method for actually doing a test run for the specified bot. Parameters ---------- iterations : integer Bot instance will be run the given times, defaults to 1. """ self.prepare_bot() with mock.patch('intelmq.lib.utils.load_configuration', new=self.mocked_config): with mock.patch('intelmq.lib.utils.log', self.mocked_log): for run in range(iterations): self.bot.start(error_on_pipeline=False, source_pipeline=self.pipe, destination_pipeline=self.pipe) self.loglines_buffer = self.log_stream.getvalue() self.loglines = self.loglines_buffer.splitlines() """ Test if report has required fields. """ if self.bot_type == 'collector': for report_json in self.get_output_queue(): report = message.MessageFactory.unserialize(report_json) self.assertIsInstance(report, message.Report) self.assertIn('feed.name', report) self.assertIn('raw', report) self.assertIn('time.observation', report) """ Test if event has required fields. """ if self.bot_type == 'parser': for event_json in self.get_output_queue(): event = message.MessageFactory.unserialize(event_json) self.assertIsInstance(event, message.Event) self.assertIn('classification.type', event) self.assertIn('raw', event) """ Test if bot log messages are correctly formatted. """ self.assertLoglineMatches(0, "{} initialized with id {} and version" " [0-9.]{{5}} \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" " as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") self.assertNotRegexpMatchesLog("(ERROR.*?){%d}" % (self.allowed_error_count + 1)) self.assertNotRegexpMatchesLog("CRITICAL") """ If no error happened (incl. tracebacks, we can check for formatting) """ if not self.allowed_error_count: # This would fail for tracebacks currently for logline in self.loglines: fields = utils.parse_logline(logline) self.assertTrue(fields['message'][-1] in '.:?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue(fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not beginn with an upper case char.' ''.format(fields['message']))
def test_parse_logline_syslog(self): """Tests if the parse_logline() function parses syslog correctly. """ line = ("Feb 22 10:17:10 host malware-domain-list-collector: ERROR " "Something went wrong") actual = utils.parse_logline(line, regex=utils.SYSLOG_REGEX) self.assertEqual({'bot_id': 'malware-domain-list-collector', 'date': '%d-02-22T10:17:10' % datetime.datetime.now().year, 'log_level': 'ERROR', 'message': 'Something went wrong'}, actual)
def test_parse_logline(self): """Tests if the parse_logline() function works as expected""" line = ("2015-05-29 21:00:24,379 - malware-domain-list-collector - " "ERROR - Something went wrong") fields = utils.parse_logline(line) self.assertDictEqual({'asctime': '2015-05-29 21:00:24,379', 'name': 'malware-domain-list-collector', 'levelname': 'ERROR', 'message': 'Something went wrong'}, fields)
def test_parse_logline(self): """Tests if the parse_logline() function works as expected""" line = ("2015-05-29 21:00:24,379 - malware-domain-list-collector - " "ERROR - Something went wrong") fields = utils.parse_logline(line) self.assertDictEqual({'date': '2015-05-29 21:00:24,379', 'bot_id': 'malware-domain-list-collector', 'log_level': 'ERROR', 'message': 'Something went wrong'}, fields)
def assertLogMatches(self, pattern, levelname="ERROR"): """Asserts if any logline matches a specific requirement. Args: pattern: Message text which is compared type: Type of logline which is asserted""" self.assertIsNotNone(self.loglines) for logline in self.loglines: fields = utils.parse_logline(logline) if levelname == fields["log_level"] and re.match(pattern, fields["message"]): break else: raise ValueError('No matching logline found.')
def assertAnyLoglineEqual(self, message, levelname="ERROR"): """Asserts if any logline matches a specific requirement. Args: message: Message text which is compared type: Type of logline which is asserted""" self.assertIsNotNone(self.loglines) for logline in self.loglines: fields = utils.parse_logline(logline) if levelname == fields["log_level"] and message == fields["message"]: return else: raise ValueError('Logline with level {!r} and message {!r} not found' ''.format(levelname, message))
def assertLoglineMatches(self, line_no, pattern, levelname="ERROR"): """Asserts if a logline matches a specific requirement. Args: line_no: Number of the logline which is asserted pattern: Message text which is compared type: Type of logline which is asserted""" self.assertIsNotNone(self.loglines) logline = self.loglines[line_no] fields = utils.parse_logline(logline) self.assertEqual( self.bot_id, fields["bot_id"], "bot_id %s didn't match %s" "".format(self.bot_id, fields["bot_id"])) self.assertEqual(levelname, fields["log_level"]) self.assertRegex(fields["message"], pattern)
def assertLoglineMatches(self, line_no, pattern, levelname="ERROR"): """Asserts if a logline matches a specific requirement. Args: line_no: Number of the logline which is asserted pattern: Message text which is compared type: Type of logline which is asserted""" self.assertIsNotNone(self.loglines) logline = self.loglines[line_no] fields = utils.parse_logline(logline) self.assertEqual(self.bot_id, fields["bot_id"], "bot_id %s didn't match %s" "".format(self.bot_id, fields["bot_id"])) self.assertEqual(levelname, fields["log_level"]) self.assertRegex(fields["message"], pattern)
def assertLoglineEqual(self, line_no: int, message: str, levelname: str = "ERROR"): """ Asserts if a logline matches a specific requirement. Parameters: line_no: Number of the logline which is asserted message: Message text which is compared levelname: Log level of logline which is asserted """ self.assertIsNotNone(self.loglines) logline = self.loglines[line_no] fields = utils.parse_logline(logline) self.assertEqual(self.bot_id, fields["bot_id"], "bot_id %s didn't match %s" "".format(self.bot_id, fields["bot_id"])) self.assertEqual(levelname, fields["log_level"]) self.assertEqual(message, fields["message"])
def assertLogMatches(self, pattern: str, levelname: str = "ERROR"): """ Asserts if any logline matches a specific requirement. Parameters: pattern: Message text which is compared, regular expression. levelname: Log level of the logline which is asserted, upper case. """ self.assertIsNotNone(self.loglines) for logline in self.loglines: fields = utils.parse_logline(logline) # Exception tracebacks if isinstance(fields, str): if levelname == "ERROR" and re.match(pattern, fields): break elif levelname == fields["log_level"] and re.match(pattern, fields["message"]): break else: raise ValueError('No matching logline found.') # pragma: no cover
def assertLogMatches(self, pattern: str, levelname: str = "ERROR"): """ Asserts if any logline matches a specific requirement. Parameters: pattern: Message text which is compared, regular expression. levelname: Log level of the logline which is asserted, upper case. """ self.assertIsNotNone(self.loglines) for logline in self.loglines: fields = utils.parse_logline(logline) # Exception tracebacks if isinstance(fields, str): if levelname == "ERROR" and re.match(pattern, fields): break elif levelname == fields["log_level"] and re.match(pattern, fields["message"]): break else: raise ValueError('No matching logline found.')
def run_bot(self, iterations: int = 1, error_on_pipeline: bool = False, prepare=True, parameters={}): """ Call this method for actually doing a test run for the specified bot. Parameters: iterations: Bot instance will be run the given times, defaults to 1. parameters: passed to prepare_bot """ if prepare: self.prepare_bot(parameters=parameters) with mock.patch('intelmq.lib.utils.load_configuration', new=self.mocked_config): with mock.patch('intelmq.lib.utils.log', self.mocked_log): for run in range(iterations): self.bot.start(error_on_pipeline=error_on_pipeline, source_pipeline=self.pipe, destination_pipeline=self.pipe) self.loglines_buffer = self.log_stream.getvalue() self.loglines = self.loglines_buffer.splitlines() """ Test if input queue is empty. """ self.assertEqual( self.input_queue, [], 'Not all input messages have been processed. ' 'You probably need to increase the number of ' 'iterations of `run_bot`.') """ Test if report has required fields. """ if self.bot_type == 'collector': for report_json in self.get_output_queue(): report = message.MessageFactory.unserialize( report_json, harmonization=self.harmonization) self.assertIsInstance(report, message.Report) self.assertIn('feed.name', report) self.assertIn('raw', report) self.assertIn('time.observation', report) """ Test if event has required fields. """ if self.bot_type == 'parser': for event_json in self.get_output_queue(): event = message.MessageFactory.unserialize( event_json, harmonization=self.harmonization) self.assertIsInstance(event, message.Event) self.assertIn('classification.type', event) self.assertIn('raw', event) """ Test if bot log messages are correctly formatted. """ self.assertLoglineMatches( 0, "{} initialized with id {} and intelmq [0-9a-z.]* and python" r" [0-9a-z.]{{5,8}}\+? \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" r" as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") self.assertNotRegexpMatchesLog("(ERROR.*?){%d}" % (self.allowed_error_count + 1)) self.assertNotRegexpMatchesLog("(WARNING.*?){%d}" % (self.allowed_warning_count + 1)) self.assertNotRegexpMatchesLog("CRITICAL") """ If no error happened (incl. tracebacks) we can check for formatting """ if not self.allowed_error_count: for logline in self.loglines: fields = utils.parse_logline(logline) if not isinstance(fields, dict): # Traceback continue self.assertTrue(fields['message'][-1] in '.:?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue( fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not begin with an upper case char.' ''.format(fields['message']))
def run_bot(self, iterations: int = 1, error_on_pipeline: bool = False, prepare=True): """ Call this method for actually doing a test run for the specified bot. Parameters: iterations: Bot instance will be run the given times, defaults to 1. """ if prepare: self.prepare_bot() with mock.patch('intelmq.lib.utils.load_configuration', new=self.mocked_config): with mock.patch('intelmq.lib.utils.log', self.mocked_log): for run in range(iterations): self.bot.start(error_on_pipeline=error_on_pipeline, source_pipeline=self.pipe, destination_pipeline=self.pipe) self.loglines_buffer = self.log_stream.getvalue() self.loglines = self.loglines_buffer.splitlines() """ Test if all pipes are created with correct names. """ pipenames = ["{}-input", "{}-input-internal", "{}-output", "{}-other-output", "{}-way1-output", "{}-way2-output"] self.assertSetEqual({x.format(self.bot_id) for x in pipenames}, set(self.pipe.state.keys())) """ Test if input queue is empty. """ self.assertEqual(self.input_queue, [], 'Not all input messages have been processed. ' 'You probably need to increase the number of ' 'iterations of `run_bot`.') """ Test if report has required fields. """ if self.bot_type == 'collector': for report_json in self.get_output_queue(): report = message.MessageFactory.unserialize(report_json, harmonization=self.harmonization) self.assertIsInstance(report, message.Report) self.assertIn('feed.name', report) self.assertIn('raw', report) self.assertIn('time.observation', report) """ Test if event has required fields. """ if self.bot_type == 'parser': for event_json in self.get_output_queue(): event = message.MessageFactory.unserialize(event_json, harmonization=self.harmonization) self.assertIsInstance(event, message.Event) self.assertIn('classification.type', event) self.assertIn('raw', event) """ Test if bot log messages are correctly formatted. """ self.assertLoglineMatches(0, "{} initialized with id {} and intelmq [0-9a-z.]* and python" r" [0-9a-z.]{{5,8}}\+? \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" r" as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") self.assertLoglineEqual(-1, "Bot stopped.", "INFO") self.assertNotRegexpMatchesLog("(ERROR.*?){%d}" % (self.allowed_error_count + 1)) self.assertNotRegexpMatchesLog("(WARNING.*?){%d}" % (self.allowed_warning_count + 1)) self.assertNotRegexpMatchesLog("CRITICAL") """ If no error happened (incl. tracebacks) we can check for formatting """ if not self.allowed_error_count: for logline in self.loglines: fields = utils.parse_logline(logline) if not isinstance(fields, dict): # Traceback continue self.assertTrue(fields['message'][-1] in '.:?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue(fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not begin with an upper case char.' ''.format(fields['message']))
def run_bot(self, iterations: int = 1, error_on_pipeline: bool = False, prepare=True, parameters={}, allowed_error_count=0, allowed_warning_count=0, stop_bot: bool = True): """ Call this method for actually doing a test run for the specified bot. Parameters: iterations: Bot instance will be run the given times, defaults to 1. parameters: passed to prepare_bot allowed_error_count: maximum number allow allowed errors in the logs allowed_warning_count: maximum number allow allowed warnings in the logs bot_stop: If the bot should be stopped/shut down after running it. Set to False, if you are calling this method again afterwards, as the bot shutdown destroys structures (pipeline, etc.) """ if prepare: self.prepare_bot(parameters=parameters) elif parameters: raise ValueError( "Parameter 'parameters' is given, but parameter " "'prepare' is false. Parameters must be passed on " "to 'prepare_bot' to be effective.") with mock.patch('intelmq.lib.utils.load_configuration', new=self.mocked_config): with mock.patch('intelmq.lib.utils.log', self.get_mocked_logger(self.logger)): for run in range(iterations): self.bot.start(error_on_pipeline=error_on_pipeline, source_pipeline=self.pipe, destination_pipeline=self.pipe) if stop_bot: self.bot.stop(exitcode=0) self.loglines_buffer = self.log_stream.getvalue() self.loglines = self.loglines_buffer.splitlines() """ Test if input queue is empty. """ self.assertEqual( self.input_queue, [], 'Not all input messages have been processed. ' 'You probably need to increase the number of ' 'iterations of `run_bot`.') internal_queue_size = len(self.get_input_internal_queue()) self.assertEqual( internal_queue_size, 0, 'The internal input queue is not empty, but has ' f'{internal_queue_size} element(s). ' 'The bot did not acknowledge all messages.') """ Test if report has required fields. """ if self.bot_type == 'collector': for report_json in self.get_output_queue(): report = message.MessageFactory.unserialize( report_json, harmonization=self.harmonization) self.assertIsInstance(report, message.Report) self.assertIn('raw', report) self.assertIn('time.observation', report) """ Test if event has required fields. """ if self.bot_type == 'parser': for event_json in self.get_output_queue(): event = message.MessageFactory.unserialize( event_json, harmonization=self.harmonization) self.assertIsInstance(event, message.Event) self.assertIn('classification.type', event) self.assertIn('raw', event) """ Test if bot log messages are correctly formatted. """ self.assertLoglineMatches( 0, "{} initialized with id {} and intelmq [0-9a-z.]* and python" r" [0-9a-z.]{{5,8}}\+? \([a-zA-Z0-9,:. ]+\)( \[GCC\])?" r" as process [0-9]+\." "".format(self.bot_name, self.bot_id), "INFO") self.assertRegexpMatchesLog("INFO - Bot is starting.") if stop_bot: self.assertLoglineEqual(-1, "Bot stopped.", "INFO") allowed_error_count = max(allowed_error_count, self.allowed_error_count) self.assertLessEqual( len(re.findall(' - ERROR - ', self.loglines_buffer)), allowed_error_count) allowed_warning_count = max(allowed_warning_count, self.allowed_warning_count) self.assertLessEqual( len(re.findall(' - WARNING - ', self.loglines_buffer)), allowed_warning_count) self.assertNotRegexpMatchesLog("CRITICAL") """ If no error happened (incl. tracebacks) we can check for formatting """ if not self.allowed_error_count: for logline in self.loglines: fields = utils.parse_logline(logline) if not isinstance(fields, dict): # Traceback continue self.assertTrue(fields['message'][-1] in '.:?!', msg='Logline {!r} does not end with .? or !.' ''.format(fields['message'])) self.assertTrue( fields['message'].upper() == fields['message'].upper(), msg='Logline {!r} does not begin with an upper case char.' ''.format(fields['message']))