Commit 6bc04064530d2138f207be18ba7325863afd46b7

Authored by Christian Herdtweck
1 parent 3c3b7093

tests: Add warnings to log_helper test

Encountered an example where a 3rd-party library issued a warning that
messed up the json output. Create test to reproduce this.
tests/common/log_helper/log_helper_test_imported.py
... ... @@ -4,6 +4,7 @@ by the main test file
4 4 """
5 5  
6 6 from oletools.common.log_helper import log_helper
  7 +import warnings
7 8  
8 9 DEBUG_MESSAGE = 'imported: debug log'
9 10 INFO_MESSAGE = 'imported: info log'
... ... @@ -11,7 +12,10 @@ WARNING_MESSAGE = 'imported: warning log'
11 12 ERROR_MESSAGE = 'imported: error log'
12 13 CRITICAL_MESSAGE = 'imported: critical log'
13 14 RESULT_MESSAGE = 'imported: result log'
  15 +
14 16 RESULT_TYPE = 'imported: result'
  17 +ACTUAL_WARNING = 'Feature XYZ provided by this module might be deprecated at '\
  18 + 'some point in the future ... or not'
15 19  
16 20 logger = log_helper.get_or_create_silent_logger('test_imported')
17 21  
... ... @@ -27,3 +31,7 @@ def log():
27 31 logger.error(ERROR_MESSAGE)
28 32 logger.critical(CRITICAL_MESSAGE)
29 33 logger.info(RESULT_MESSAGE, type=RESULT_TYPE)
  34 +
  35 +
  36 +def warn():
  37 + warnings.warn(ACTUAL_WARNING)
... ...
tests/common/log_helper/log_helper_test_main.py
... ... @@ -2,6 +2,7 @@
2 2  
3 3 import sys
4 4 import logging
  5 +import warnings
5 6 from tests.common.log_helper import log_helper_test_imported
6 7 from oletools.common.log_helper import log_helper
7 8  
... ... @@ -11,7 +12,9 @@ WARNING_MESSAGE = 'main: warning log'
11 12 ERROR_MESSAGE = 'main: error log'
12 13 CRITICAL_MESSAGE = 'main: critical log'
13 14 RESULT_MESSAGE = 'main: result log'
  15 +
14 16 RESULT_TYPE = 'main: result'
  17 +ACTUAL_WARNING = 'Warnings can pop up anywhere, have to be prepared!'
15 18  
16 19 logger = log_helper.get_or_create_silent_logger('test_main')
17 20  
... ... @@ -24,7 +27,8 @@ def enable_logging():
24 27  
25 28 def main(args):
26 29 """
27   - Try to cover possible logging scenarios. For each scenario covered, here's the expected args and outcome:
  30 + Try to cover possible logging scenarios. For each scenario covered, here's
  31 + the expected args and outcome:
28 32 - Log without enabling: ['<level>']
29 33 * logging when being imported - should never print
30 34 - Log as JSON without enabling: ['as-json', '<level>']
... ... @@ -35,6 +39,8 @@ def main(args):
35 39 * logging as JSON when being run as script - should log messages as JSON
36 40 - Enable, log as JSON and throw: ['enable', 'as-json', 'throw', '<level>']
37 41 * should produce JSON-compatible output, even after an unhandled exception
  42 + - Enable, log as JSON and warn: ['enable', 'as-json', 'warn', '<level>']
  43 + * should produce JSON-compatible output, even after a warning
38 44 """
39 45  
40 46 # the level should always be the last argument passed
... ... @@ -42,6 +48,7 @@ def main(args):
42 48 use_json = 'as-json' in args
43 49 throw = 'throw' in args
44 50 percent_autoformat = '%-autoformat' in args
  51 + warn = 'warn' in args
45 52  
46 53 log_helper_test_imported.logger.setLevel(logging.ERROR)
47 54  
... ... @@ -53,6 +60,10 @@ def main(args):
53 60 if throw:
54 61 raise Exception('An exception occurred before ending the logging')
55 62  
  63 + if warn:
  64 + warnings.warn(ACTUAL_WARNING)
  65 + log_helper_test_imported.warn()
  66 +
56 67 log_helper.end_logging()
57 68  
58 69  
... ...
tests/common/log_helper/test_log_helper.py
... ... @@ -142,6 +142,32 @@ class TestLogHelper(unittest.TestCase):
142 142 self.assertIn('INFO:test_main:main: info log', output)
143 143 self.assertIn('INFO:test_imported:imported: info log', output)
144 144  
  145 + def test_json_correct_on_warnings(self):
  146 + """
  147 + Test that even on warnings our JSON is always correct
  148 + """
  149 + output = self._run_test(['enable', 'as-json', 'warn', 'warning'])
  150 + expected_messages = [
  151 + log_helper_test_main.WARNING_MESSAGE,
  152 + log_helper_test_main.ERROR_MESSAGE,
  153 + log_helper_test_main.CRITICAL_MESSAGE,
  154 + log_helper_test_imported.WARNING_MESSAGE,
  155 + log_helper_test_imported.ERROR_MESSAGE,
  156 + log_helper_test_imported.CRITICAL_MESSAGE,
  157 + ]
  158 +
  159 + for msg in expected_messages:
  160 + self.assertIn(msg, output)
  161 +
  162 + # last two entries of output should be warnings
  163 + jout = json.loads(output)
  164 + self.assertEqual(jout[-2]['level'], 'WARNING')
  165 + self.assertEqual(jout[-1]['level'], 'WARNING')
  166 + self.assertEqual(jout[-2]['type'], 'warning')
  167 + self.assertEqual(jout[-1]['type'], 'warning')
  168 + self.assertIn(log_helper_test_main.ACTUAL_WARNING, jout[-2]['msg'])
  169 + self.assertIn(log_helper_test_imported.ACTUAL_WARNING, jout[-1]['msg'])
  170 +
145 171 def _assert_json_messages(self, output, messages):
146 172 try:
147 173 json_data = json.loads(output)
... ... @@ -163,6 +189,8 @@ class TestLogHelper(unittest.TestCase):
163 189 When arg `run_third_party` is `True`, we do not run the `TEST_FILE` as
164 190 main moduel but the `TEST_FILE_3RD_PARTY` and return contents of
165 191 `stderr` instead of `stdout`.
  192 +
  193 + TODO: use tests.utils.call_and_capture
166 194 """
167 195 all_args = [PYTHON_EXECUTABLE, ]
168 196 if run_third_party:
... ...