diff --git a/metrics_utils.py b/metrics_utils.py index e7ba2beda..4af7eb3c4 100644 --- a/metrics_utils.py +++ b/metrics_utils.py @@ -219,8 +219,11 @@ def return_code_from_exception(exception): """Returns the exit code that would result of raising the exception.""" if exception is None: return 0 - if isinstance(exception[1], SystemExit): - return exception[1].code + e = exception[1] + if isinstance(e, KeyboardInterrupt): + return 130 + if isinstance(e, SystemExit): + return e.code return 1 diff --git a/tests/metrics_test.py b/tests/metrics_test.py index 8042b34c9..3e07e302d 100644 --- a/tests/metrics_test.py +++ b/tests/metrics_test.py @@ -302,6 +302,22 @@ class MetricsCollectorTest(unittest.TestCase): self.assertEqual(cm.exception.code, 0) self.assert_collects_metrics({'exit_code': 0}) + def test_handles_keyboard_interrupt(self): + """Tests that KeyboardInterrupt exits with 130 and metrics are collected.""" + self.FileRead.side_effect = [ + '{"is-googler": true, "countdown": 0, "opt-in": true, "version": 0}' + ] + + @self.collector.collect_metrics('fun') + def fun(): + raise KeyboardInterrupt + + # When an exception is raised, we should catch it, update exit-code, + # collect metrics, and re-raise it. + with self.assertRaises(KeyboardInterrupt): + fun() + self.assert_collects_metrics({'exit_code': 130}) + def test_handles_system_exit_non_zero(self): """Tests that the sys.exit code is respected and metrics are collected.""" self.FileRead.side_effect = [