[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | import json |
| 7 | import logging |
| 8 | import os |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 9 | import re |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 10 | import subprocess |
| 11 | import sys |
| 12 | import tempfile |
| 13 | import unittest |
| 14 | |
| 15 | import trace_inputs |
| 16 | |
| 17 | FILE_PATH = os.path.realpath(unicode(os.path.abspath(__file__))) |
| 18 | ROOT_DIR = os.path.dirname(FILE_PATH) |
| 19 | TARGET_PATH = os.path.join(ROOT_DIR, 'data', 'gtest_fake', 'gtest_fake.py') |
| 20 | |
| 21 | |
| 22 | class TraceTestCases(unittest.TestCase): |
| 23 | def setUp(self): |
| 24 | self.temp_file = None |
| 25 | |
| 26 | self.initial_cwd = ROOT_DIR |
| 27 | if sys.platform == 'win32': |
| 28 | # Windows has no kernel mode concept of current working directory. |
| 29 | self.initial_cwd = None |
| 30 | |
| 31 | # There's 2 kinds of references to python, self.executable, |
| 32 | # self.real_executable. It depends how python was started and on which OS. |
| 33 | self.executable = unicode(sys.executable) |
| 34 | if sys.platform == 'darwin': |
| 35 | # /usr/bin/python is a thunk executable that decides which version of |
| 36 | # python gets executed. |
| 37 | suffix = '.'.join(map(str, sys.version_info[0:2])) |
| 38 | if os.access(self.executable + suffix, os.X_OK): |
| 39 | # So it'll look like /usr/bin/python2.7 |
| 40 | self.executable += suffix |
| 41 | |
[email protected] | b9d1e261 | 2012-07-05 02:14:51 | [diff] [blame] | 42 | self.real_executable = trace_inputs.get_native_path_case(self.executable) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 43 | |
| 44 | def tearDown(self): |
| 45 | if self.temp_file: |
| 46 | os.remove(self.temp_file) |
| 47 | |
| 48 | def _gen_results(self, test_case): |
| 49 | return { |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 50 | u'processes': 1, |
| 51 | u'returncode': 0, |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 52 | u'results': { |
| 53 | u'root': { |
| 54 | u'children': [], |
| 55 | u'command': [ |
| 56 | self.executable, |
| 57 | TARGET_PATH, |
| 58 | u'--gtest_filter=%s' % test_case, |
| 59 | ], |
| 60 | u'executable': self.real_executable, |
| 61 | u'files': [ |
| 62 | { |
| 63 | u'path': os.path.join(u'data', 'gtest_fake', 'gtest_fake.py'), |
| 64 | u'size': os.stat(TARGET_PATH).st_size, |
| 65 | }, |
| 66 | ], |
| 67 | u'initial_cwd': self.initial_cwd, |
| 68 | }, |
| 69 | }, |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 70 | u'valid': True, |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 71 | u'variables': { |
| 72 | u'isolate_dependency_tracked': [ |
| 73 | u'<(PRODUCT_DIR)/gtest_fake/gtest_fake.py', |
| 74 | ], |
| 75 | }, |
| 76 | } |
| 77 | |
| 78 | def _strip_result(self, result): |
| 79 | """Strips mutable information from a flattened test case Results.""" |
| 80 | self.assertTrue(result.pop('duration') > 0.) |
| 81 | self.assertTrue(len(result.pop('output')) > 10) |
| 82 | def strip_pid(proc): |
| 83 | self.assertTrue(proc.pop('pid') > 100) |
| 84 | for child in proc['children']: |
| 85 | strip_pid(child) |
| 86 | strip_pid(result['results']['root']) |
| 87 | |
| 88 | def test_simple(self): |
| 89 | file_handle, self.temp_file = tempfile.mkstemp( |
| 90 | prefix='trace_test_cases_test') |
| 91 | os.close(file_handle) |
| 92 | |
| 93 | cmd = [ |
| 94 | sys.executable, |
| 95 | os.path.join(ROOT_DIR, 'trace_test_cases.py'), |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 96 | # Forces 4 parallel jobs. |
| 97 | '--jobs', '4', |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 98 | '--timeout', '0', |
| 99 | '--out', self.temp_file, |
| 100 | '--root-dir', ROOT_DIR, |
[email protected] | 4aebe8dc | 2012-06-19 01:49:06 | [diff] [blame] | 101 | '--variable', 'PRODUCT_DIR', 'data', |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 102 | TARGET_PATH, |
| 103 | ] |
[email protected] | 4aebe8dc | 2012-06-19 01:49:06 | [diff] [blame] | 104 | if VERBOSE: |
| 105 | cmd.extend(['-v'] * 3) |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 106 | logging.debug(' '.join(cmd)) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 107 | proc = subprocess.Popen( |
| 108 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 109 | out, err = proc.communicate() or ('', '') # pylint is confused. |
[email protected] | 23ca807 | 2012-07-06 14:29:05 | [diff] [blame^] | 110 | self.assertEquals(0, proc.returncode, (out, err)) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 111 | if sys.platform == 'win32': |
| 112 | # TODO(maruel): Figure out why replace('\r\n', '\n') doesn't work. |
| 113 | out = out.replace('\r', '') |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 114 | expected_out_re = '\n'.join([ |
| 115 | r'', |
| 116 | r'\d+\.\ds Done post-processing logs\. Parsing logs\.', |
| 117 | r'\d+\.\ds Done parsing logs\.', |
[email protected] | 4aebe8dc | 2012-06-19 01:49:06 | [diff] [blame] | 118 | r'\d+.\ds Done stripping root\.', |
| 119 | r'\d+.\ds Done flattening\.', |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 120 | r'', |
| 121 | ]) |
| 122 | self.assertTrue(re.match('^%s$' % expected_out_re, out), repr(out)) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 123 | self.assertTrue(err.startswith('\r'), err) |
| 124 | |
| 125 | expected_json = {} |
| 126 | test_cases = ( |
| 127 | 'Baz.Fail', |
| 128 | 'Foo.Bar1', |
| 129 | 'Foo.Bar2', |
| 130 | 'Foo.Bar3', |
| 131 | ) |
| 132 | for test_case in test_cases: |
| 133 | expected_json[unicode(test_case)] = self._gen_results(test_case) |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 134 | expected_json['Baz.Fail']['returncode'] = 1 |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 135 | with open(self.temp_file, 'r') as f: |
| 136 | result = json.load(f) |
| 137 | |
| 138 | # Trim off 'duration' and 'output', they don't have a constant value. |
| 139 | for value in result.itervalues(): |
| 140 | self._strip_result(value) |
| 141 | self.assertEquals(expected_json, result) |
| 142 | |
| 143 | |
| 144 | if __name__ == '__main__': |
| 145 | VERBOSE = '-v' in sys.argv |
| 146 | logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
| 147 | unittest.main() |