#!/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 in # the expected way. 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()