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