| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # Copyright 2016 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Test for generate_report.py.""" |
| |
| from __future__ import division |
| from __future__ import print_function |
| |
| import copy |
| import json |
| import unittest |
| import unittest.mock as mock |
| |
| import generate_report |
| import results_report |
| import test_flag |
| |
| # pylint: disable=deprecated-module |
| try: |
| from StringIO import StringIO # for Python 2 |
| except ImportError: |
| from io import StringIO # for Python 3 |
| |
| |
| class _ContextualStringIO(StringIO): |
| """StringIO that can be used in `with` statements.""" |
| |
| def __init__(self, *args): |
| StringIO.__init__(self, *args) |
| |
| def __enter__(self): |
| return self |
| |
| def __exit__(self, _type, _value, _traceback): |
| pass |
| |
| |
| class GenerateReportTests(unittest.TestCase): |
| """Tests for generate_report.py.""" |
| |
| def testCountBenchmarks(self): |
| runs = { |
| 'foo': [[{}, {}, {}], [{}, {}, {}, {}]], |
| 'bar': [], |
| 'baz': [[], [{}], [{}, {}, {}]] |
| } |
| results = generate_report.CountBenchmarks(runs) |
| expected_results = [('foo', 4), ('bar', 0), ('baz', 3)] |
| self.assertCountEqual(expected_results, results) |
| |
| def testCutResultsInPlace(self): |
| bench_data = { |
| 'foo': [[{ |
| 'a': 1, |
| 'b': 2, |
| 'c': 3 |
| }, { |
| 'a': 3, |
| 'b': 2.5, |
| 'c': 1 |
| }]], |
| 'bar': [[{ |
| 'd': 11, |
| 'e': 12, |
| 'f': 13 |
| }]], |
| 'baz': [[{ |
| 'g': 12, |
| 'h': 13 |
| }]], |
| 'qux': [[{ |
| 'i': 11 |
| }]], |
| } |
| original_bench_data = copy.deepcopy(bench_data) |
| |
| max_keys = 2 |
| results = generate_report.CutResultsInPlace( |
| bench_data, max_keys=max_keys, complain_on_update=False) |
| # Cuts should be in-place. |
| self.assertIs(results, bench_data) |
| self.assertCountEqual( |
| list(original_bench_data.keys()), list(bench_data.keys())) |
| for bench_name, original_runs in original_bench_data.items(): |
| bench_runs = bench_data[bench_name] |
| self.assertEqual(len(original_runs), len(bench_runs)) |
| # Order of these sub-lists shouldn't have changed. |
| for original_list, new_list in zip(original_runs, bench_runs): |
| self.assertEqual(len(original_list), len(new_list)) |
| for original_keyvals, sub_keyvals in zip(original_list, new_list): |
| # sub_keyvals must be a subset of original_keyvals |
| self.assertDictContainsSubset(sub_keyvals, original_keyvals) |
| |
| def testCutResultsInPlaceLeavesRetval(self): |
| bench_data = { |
| 'foo': [[{ |
| 'retval': 0, |
| 'a': 1 |
| }]], |
| 'bar': [[{ |
| 'retval': 1 |
| }]], |
| 'baz': [[{ |
| 'RETVAL': 1 |
| }]], |
| } |
| results = generate_report.CutResultsInPlace( |
| bench_data, max_keys=0, complain_on_update=False) |
| # Just reach into results assuming we know it otherwise outputs things |
| # sanely. If it doesn't, testCutResultsInPlace should give an indication as |
| # to what, exactly, is broken. |
| self.assertEqual(list(results['foo'][0][0].items()), [('retval', 0)]) |
| self.assertEqual(list(results['bar'][0][0].items()), [('retval', 1)]) |
| self.assertEqual(list(results['baz'][0][0].items()), []) |
| |
| def _RunMainWithInput(self, args, input_obj): |
| assert '-i' not in args |
| args += ['-i', '-'] |
| input_buf = _ContextualStringIO(json.dumps(input_obj)) |
| with mock.patch('generate_report.PickInputFile', return_value=input_buf) \ |
| as patched_pick: |
| result = generate_report.Main(args) |
| patched_pick.assert_called_once_with('-') |
| return result |
| |
| @mock.patch('generate_report.RunActions') |
| def testMain(self, mock_run_actions): |
| # Email is left out because it's a bit more difficult to test, and it'll be |
| # mildly obvious if it's failing. |
| args = ['--json', '--html', '--text'] |
| return_code = self._RunMainWithInput(args, {'platforms': [], 'data': {}}) |
| self.assertEqual(0, return_code) |
| self.assertEqual(mock_run_actions.call_count, 1) |
| ctors = [ctor for ctor, _ in mock_run_actions.call_args[0][0]] |
| self.assertEqual(ctors, [ |
| results_report.JSONResultsReport, |
| results_report.TextResultsReport, |
| results_report.HTMLResultsReport, |
| ]) |
| |
| @mock.patch('generate_report.RunActions') |
| def testMainSelectsHTMLIfNoReportsGiven(self, mock_run_actions): |
| args = [] |
| return_code = self._RunMainWithInput(args, {'platforms': [], 'data': {}}) |
| self.assertEqual(0, return_code) |
| self.assertEqual(mock_run_actions.call_count, 1) |
| ctors = [ctor for ctor, _ in mock_run_actions.call_args[0][0]] |
| self.assertEqual(ctors, [results_report.HTMLResultsReport]) |
| |
| # We only mock print_exc so we don't have exception info printed to stdout. |
| @mock.patch('generate_report.WriteFile', side_effect=ValueError('Oh noo')) |
| @mock.patch('traceback.print_exc') |
| def testRunActionsRunsAllActionsRegardlessOfExceptions( |
| self, mock_print_exc, mock_write_file): |
| actions = [(None, 'json'), (None, 'html'), (None, 'text'), (None, 'email')] |
| output_prefix = '-' |
| ok = generate_report.RunActions( |
| actions, {}, output_prefix, overwrite=False, verbose=False) |
| self.assertFalse(ok) |
| self.assertEqual(mock_write_file.call_count, len(actions)) |
| self.assertEqual(mock_print_exc.call_count, len(actions)) |
| |
| @mock.patch('generate_report.WriteFile') |
| def testRunActionsReturnsTrueIfAllActionsSucceed(self, mock_write_file): |
| actions = [(None, 'json'), (None, 'html'), (None, 'text')] |
| output_prefix = '-' |
| ok = generate_report.RunActions( |
| actions, {}, output_prefix, overwrite=False, verbose=False) |
| self.assertEqual(mock_write_file.call_count, len(actions)) |
| self.assertTrue(ok) |
| |
| |
| if __name__ == '__main__': |
| test_flag.SetTestMode(True) |
| unittest.main() |