[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] | f698862 | 2012-07-21 13:57:01 | [diff] [blame^] | 43 | # Make sure there's no environment variable that could do side effects. |
| 44 | os.environ.pop('GTEST_SHARD_INDEX', '') |
| 45 | os.environ.pop('GTEST_TOTAL_SHARDS', '') |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 46 | |
| 47 | def tearDown(self): |
| 48 | if self.temp_file: |
| 49 | os.remove(self.temp_file) |
| 50 | |
| 51 | def _gen_results(self, test_case): |
| 52 | return { |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 53 | u'processes': 1, |
| 54 | u'returncode': 0, |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 55 | u'results': { |
| 56 | u'root': { |
| 57 | u'children': [], |
| 58 | u'command': [ |
| 59 | self.executable, |
| 60 | TARGET_PATH, |
| 61 | u'--gtest_filter=%s' % test_case, |
| 62 | ], |
| 63 | u'executable': self.real_executable, |
| 64 | u'files': [ |
| 65 | { |
| 66 | u'path': os.path.join(u'data', 'gtest_fake', 'gtest_fake.py'), |
| 67 | u'size': os.stat(TARGET_PATH).st_size, |
| 68 | }, |
| 69 | ], |
| 70 | u'initial_cwd': self.initial_cwd, |
| 71 | }, |
| 72 | }, |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 73 | u'valid': True, |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 74 | u'variables': { |
| 75 | u'isolate_dependency_tracked': [ |
| 76 | u'<(PRODUCT_DIR)/gtest_fake/gtest_fake.py', |
| 77 | ], |
| 78 | }, |
| 79 | } |
| 80 | |
| 81 | def _strip_result(self, result): |
| 82 | """Strips mutable information from a flattened test case Results.""" |
| 83 | self.assertTrue(result.pop('duration') > 0.) |
| 84 | self.assertTrue(len(result.pop('output')) > 10) |
| 85 | def strip_pid(proc): |
| 86 | self.assertTrue(proc.pop('pid') > 100) |
| 87 | for child in proc['children']: |
| 88 | strip_pid(child) |
| 89 | strip_pid(result['results']['root']) |
| 90 | |
| 91 | def test_simple(self): |
| 92 | file_handle, self.temp_file = tempfile.mkstemp( |
| 93 | prefix='trace_test_cases_test') |
| 94 | os.close(file_handle) |
| 95 | |
| 96 | cmd = [ |
| 97 | sys.executable, |
| 98 | os.path.join(ROOT_DIR, 'trace_test_cases.py'), |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 99 | # Forces 4 parallel jobs. |
| 100 | '--jobs', '4', |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 101 | '--timeout', '0', |
| 102 | '--out', self.temp_file, |
| 103 | '--root-dir', ROOT_DIR, |
[email protected] | 4aebe8dc | 2012-06-19 01:49:06 | [diff] [blame] | 104 | '--variable', 'PRODUCT_DIR', 'data', |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 105 | TARGET_PATH, |
| 106 | ] |
[email protected] | 4aebe8dc | 2012-06-19 01:49:06 | [diff] [blame] | 107 | if VERBOSE: |
| 108 | cmd.extend(['-v'] * 3) |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 109 | logging.debug(' '.join(cmd)) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 110 | proc = subprocess.Popen( |
| 111 | cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 112 | out, err = proc.communicate() or ('', '') # pylint is confused. |
[email protected] | 23ca807 | 2012-07-06 14:29:05 | [diff] [blame] | 113 | self.assertEquals(0, proc.returncode, (out, err)) |
[email protected] | 162c0a3 | 2012-07-20 17:15:46 | [diff] [blame] | 114 | lines = out.splitlines() |
| 115 | expected_out_re = [ |
| 116 | r'\[1/4\] \d\.\d\ds .+', |
| 117 | r'\[2/4\] \d\.\d\ds .+', |
| 118 | r'\[3/4\] \d\.\d\ds .+', |
| 119 | r'\[4/4\] \d\.\d\ds .+', |
| 120 | r'\d+\.\ds Done post-processing logs\. Parsing logs\.', |
| 121 | r'\d+\.\ds Done parsing logs\.', |
[email protected] | f698862 | 2012-07-21 13:57:01 | [diff] [blame^] | 122 | r'\d+\.\ds Done stripping root\.', |
| 123 | r'\d+\.\ds Done flattening\.', |
[email protected] | 162c0a3 | 2012-07-20 17:15:46 | [diff] [blame] | 124 | ] |
| 125 | for index in range(len(expected_out_re)): |
| 126 | self.assertTrue( |
| 127 | re.match('^%s$' % expected_out_re[index], lines[index]), |
[email protected] | f698862 | 2012-07-21 13:57:01 | [diff] [blame^] | 128 | (index, expected_out_re[index], repr(lines[index]))) |
[email protected] | 162c0a3 | 2012-07-20 17:15:46 | [diff] [blame] | 129 | # Junk is printed on win32. |
| 130 | if sys.platform != 'win32': |
| 131 | self.assertEquals('', err) |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 132 | |
| 133 | expected_json = {} |
| 134 | test_cases = ( |
| 135 | 'Baz.Fail', |
| 136 | 'Foo.Bar1', |
| 137 | 'Foo.Bar2', |
| 138 | 'Foo.Bar3', |
| 139 | ) |
| 140 | for test_case in test_cases: |
| 141 | expected_json[unicode(test_case)] = self._gen_results(test_case) |
[email protected] | 0507fc9d | 2012-06-14 14:09:41 | [diff] [blame] | 142 | expected_json['Baz.Fail']['returncode'] = 1 |
[email protected] | ae831df2 | 2012-06-13 19:31:54 | [diff] [blame] | 143 | with open(self.temp_file, 'r') as f: |
| 144 | result = json.load(f) |
| 145 | |
| 146 | # Trim off 'duration' and 'output', they don't have a constant value. |
| 147 | for value in result.itervalues(): |
| 148 | self._strip_result(value) |
| 149 | self.assertEquals(expected_json, result) |
| 150 | |
| 151 | |
| 152 | if __name__ == '__main__': |
| 153 | VERBOSE = '-v' in sys.argv |
| 154 | logging.basicConfig(level=logging.DEBUG if VERBOSE else logging.ERROR) |
| 155 | unittest.main() |