• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python2
2#
3# Copyright 2016 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""Test for generate_report.py."""
7
8from __future__ import division
9from __future__ import print_function
10
11from StringIO import StringIO
12
13import copy
14import json
15import mock
16import test_flag
17import unittest
18
19import generate_report
20import results_report
21
22
23class _ContextualStringIO(StringIO):
24  """StringIO that can be used in `with` statements."""
25
26  def __init__(self, *args):
27    StringIO.__init__(self, *args)
28
29  def __enter__(self):
30    return self
31
32  def __exit__(self, _type, _value, _traceback):
33    pass
34
35
36class GenerateReportTests(unittest.TestCase):
37  """Tests for generate_report.py."""
38
39  def testCountBenchmarks(self):
40    runs = {
41        'foo': [[{}, {}, {}], [{}, {}, {}, {}]],
42        'bar': [],
43        'baz': [[], [{}], [{}, {}, {}]]
44    }
45    results = generate_report.CountBenchmarks(runs)
46    expected_results = [('foo', 4), ('bar', 0), ('baz', 3)]
47    self.assertItemsEqual(expected_results, results)
48
49  def testCutResultsInPlace(self):
50    bench_data = {
51        'foo': [[{
52            'a': 1,
53            'b': 2,
54            'c': 3
55        }, {
56            'a': 3,
57            'b': 2.5,
58            'c': 1
59        }]],
60        'bar': [[{
61            'd': 11,
62            'e': 12,
63            'f': 13
64        }]],
65        'baz': [[{
66            'g': 12,
67            'h': 13
68        }]],
69        'qux': [[{
70            'i': 11
71        }]],
72    }
73    original_bench_data = copy.deepcopy(bench_data)
74
75    max_keys = 2
76    results = generate_report.CutResultsInPlace(
77        bench_data, max_keys=max_keys, complain_on_update=False)
78    # Cuts should be in-place.
79    self.assertIs(results, bench_data)
80    self.assertItemsEqual(original_bench_data.keys(), bench_data.keys())
81    for bench_name, original_runs in original_bench_data.iteritems():
82      bench_runs = bench_data[bench_name]
83      self.assertEquals(len(original_runs), len(bench_runs))
84      # Order of these sub-lists shouldn't have changed.
85      for original_list, new_list in zip(original_runs, bench_runs):
86        self.assertEqual(len(original_list), len(new_list))
87        for original_keyvals, sub_keyvals in zip(original_list, new_list):
88          # sub_keyvals must be a subset of original_keyvals
89          self.assertDictContainsSubset(sub_keyvals, original_keyvals)
90
91  def testCutResultsInPlaceLeavesRetval(self):
92    bench_data = {
93        'foo': [[{
94            'retval': 0,
95            'a': 1
96        }]],
97        'bar': [[{
98            'retval': 1
99        }]],
100        'baz': [[{
101            'RETVAL': 1
102        }]],
103    }
104    results = generate_report.CutResultsInPlace(
105        bench_data, max_keys=0, complain_on_update=False)
106    # Just reach into results assuming we know it otherwise outputs things
107    # sanely. If it doesn't, testCutResultsInPlace should give an indication as
108    # to what, exactly, is broken.
109    self.assertEqual(results['foo'][0][0].items(), [('retval', 0)])
110    self.assertEqual(results['bar'][0][0].items(), [('retval', 1)])
111    self.assertEqual(results['baz'][0][0].items(), [])
112
113  def _RunMainWithInput(self, args, input_obj):
114    assert '-i' not in args
115    args += ['-i', '-']
116    input_buf = _ContextualStringIO(json.dumps(input_obj))
117    with mock.patch('generate_report.PickInputFile', return_value=input_buf) \
118        as patched_pick:
119      result = generate_report.Main(args)
120      patched_pick.assert_called_once_with('-')
121      return result
122
123  @mock.patch('generate_report.RunActions')
124  def testMain(self, mock_run_actions):
125    # Email is left out because it's a bit more difficult to test, and it'll be
126    # mildly obvious if it's failing.
127    args = ['--json', '--html', '--text']
128    return_code = self._RunMainWithInput(args, {'platforms': [], 'data': {}})
129    self.assertEqual(0, return_code)
130    self.assertEqual(mock_run_actions.call_count, 1)
131    ctors = [ctor for ctor, _ in mock_run_actions.call_args[0][0]]
132    self.assertItemsEqual(ctors, [
133        results_report.JSONResultsReport,
134        results_report.TextResultsReport,
135        results_report.HTMLResultsReport,
136    ])
137
138  @mock.patch('generate_report.RunActions')
139  def testMainSelectsHTMLIfNoReportsGiven(self, mock_run_actions):
140    args = []
141    return_code = self._RunMainWithInput(args, {'platforms': [], 'data': {}})
142    self.assertEqual(0, return_code)
143    self.assertEqual(mock_run_actions.call_count, 1)
144    ctors = [ctor for ctor, _ in mock_run_actions.call_args[0][0]]
145    self.assertItemsEqual(ctors, [results_report.HTMLResultsReport])
146
147  # We only mock print_exc so we don't have exception info printed to stdout.
148  @mock.patch('generate_report.WriteFile', side_effect=ValueError('Oh noo'))
149  @mock.patch('traceback.print_exc')
150  def testRunActionsRunsAllActionsRegardlessOfExceptions(
151      self, mock_print_exc, mock_write_file):
152    actions = [(None, 'json'), (None, 'html'), (None, 'text'), (None, 'email')]
153    output_prefix = '-'
154    ok = generate_report.RunActions(
155        actions, {}, output_prefix, overwrite=False, verbose=False)
156    self.assertFalse(ok)
157    self.assertEqual(mock_write_file.call_count, len(actions))
158    self.assertEqual(mock_print_exc.call_count, len(actions))
159
160  @mock.patch('generate_report.WriteFile')
161  def testRunActionsReturnsTrueIfAllActionsSucceed(self, mock_write_file):
162    actions = [(None, 'json'), (None, 'html'), (None, 'text')]
163    output_prefix = '-'
164    ok = generate_report.RunActions(
165        actions, {}, output_prefix, overwrite=False, verbose=False)
166    self.assertEqual(mock_write_file.call_count, len(actions))
167    self.assertTrue(ok)
168
169
170if __name__ == '__main__':
171  test_flag.SetTestMode(True)
172  unittest.main()
173