Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Tests generated CIPD packages. | 6 """Tests generated CIPD packages. |
| 7 | 7 |
| 8 Supposed to be invoked after build.py has run. Uses packages from out/*.cipd and | 8 Supposed to be invoked after build.py has run. Uses packages from out/*.cipd and |
| 9 tests from tests/*.py. | 9 tests from tests/*.py. |
| 10 | 10 |
| 11 Assumes cipd client is built in ../go/bin/cipd (true after build.py has run). | 11 Assumes cipd client is built in out/.cipd_client/cipd_* (true after build.py has |
| 12 run). | |
| 12 """ | 13 """ |
| 13 | 14 |
| 14 import argparse | 15 import argparse |
| 15 import glob | 16 import glob |
| 16 import os | 17 import os |
| 17 import re | 18 import re |
| 18 import shutil | 19 import shutil |
| 19 import subprocess | 20 import subprocess |
| 20 import sys | 21 import sys |
| 21 import tempfile | 22 import tempfile |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 45 def get_docstring(test_script): | 46 def get_docstring(test_script): |
| 46 """Hacky way to grab a first line of a module docstring using regexps.""" | 47 """Hacky way to grab a first line of a module docstring using regexps.""" |
| 47 with open(test_script, 'rt') as f: | 48 with open(test_script, 'rt') as f: |
| 48 text = f.read() | 49 text = f.read() |
| 49 m = re.match(r'^.*"""(.*?)"""', text, re.DOTALL) | 50 m = re.match(r'^.*"""(.*?)"""', text, re.DOTALL) |
| 50 if not m: | 51 if not m: |
| 51 return None | 52 return None |
| 52 return m.group(1).strip().splitlines()[0] | 53 return m.group(1).strip().splitlines()[0] |
| 53 | 54 |
| 54 | 55 |
| 56 def find_cipd_client(out_dir): | |
| 57 """Returns path to cipd client built by build.py. | |
| 58 | |
| 59 See build_cipd_client in build.py. It puts cipd client into | |
| 60 '<out_dir>/.cipd_client/cipd_<digest>' and there's only one such file there. | |
| 61 | |
| 62 Prints error message and returns None if the file cannot be found. | |
| 63 """ | |
| 64 out_dir = os.path.join(out_dir, '.cipd_client') | |
| 65 files = [f for f in os.listdir(out_dir) if f.startswith('cipd_')] | |
| 66 if not files: | |
| 67 print >> sys.stderr, 'Cannot find CIPD client in %s' % out_dir | |
| 68 return None | |
| 69 if len(files) != 1: | |
| 70 print >> sys.stderr, ( | |
| 71 'There should be only one cipd client binary in %s, found %s' % | |
| 72 (out_dir, files)) | |
| 73 return None | |
| 74 cipd_client = os.path.join(out_dir, files[0]) | |
| 75 if not os.access(cipd_client, os.X_OK): | |
| 76 print >> sys.stderr, 'CIPD client at %s is not runnable' | |
| 77 return None | |
| 78 return cipd_client | |
| 79 | |
| 80 | |
| 55 def run_test(cipd_client, package, work_dir, test_script): | 81 def run_test(cipd_client, package, work_dir, test_script): |
| 56 """Extracts a package to a dir and runs test_script with cwd == work_dir.""" | 82 """Extracts a package to a dir and runs test_script with cwd == work_dir.""" |
| 57 print_title('Deploying %s' % os.path.basename(package)) | 83 print_title('Deploying %s' % os.path.basename(package)) |
| 58 if not os.access(cipd_client, os.X_OK): | |
| 59 print >> sys.stderr, ( | |
| 60 'CIPD client at %s doesn\'t exist or not runnable. Run build.py to ' | |
| 61 'build it.' % cipd_client) | |
| 62 return 1 | |
| 63 cmd_line = ['cipd', 'pkg-deploy', '-root', work_dir, package] | 84 cmd_line = ['cipd', 'pkg-deploy', '-root', work_dir, package] |
| 64 print ' '.join(cmd_line) | 85 print ' '.join(cmd_line) |
| 65 if subprocess.call(args=cmd_line, executable=cipd_client): | 86 if subprocess.call(args=cmd_line, executable=cipd_client): |
| 66 raise TestException('Failed to install %s, see logs' % package) | 87 raise TestException('Failed to install %s, see logs' % package) |
| 67 | 88 |
| 68 print_title(get_docstring(test_script) or 'Running tests...') | 89 print_title(get_docstring(test_script) or 'Running tests...') |
| 69 cmd_line = ['python', test_script] | 90 cmd_line = ['python', test_script] |
| 70 print '%s in %s' % (' '.join(cmd_line), work_dir) | 91 print '%s in %s' % (' '.join(cmd_line), work_dir) |
| 71 env = os.environ.copy() | 92 env = os.environ.copy() |
| 72 env.pop('PYTHONPATH', None) | 93 env.pop('PYTHONPATH', None) |
| 73 ret = subprocess.call( | 94 ret = subprocess.call( |
| 74 args=cmd_line, executable=sys.executable, env=env, cwd=work_dir) | 95 args=cmd_line, executable=sys.executable, env=env, cwd=work_dir) |
| 75 if ret: | 96 if ret: |
| 76 raise TestException('Non zero exit code (%d)' % ret) | 97 raise TestException('Non zero exit code (%d)' % ret) |
| 77 | 98 |
| 78 | 99 |
| 79 def run( | 100 def run( |
| 80 cipd_client, | |
| 81 package_out_dir, | 101 package_out_dir, |
| 82 package_tests_dir, | 102 package_tests_dir, |
| 83 work_dir, | 103 work_dir, |
| 84 packages): | 104 packages): |
| 85 """Deployes build *.cipd package locally and runs tests against them. | 105 """Deployes build *.cipd package locally and runs tests against them. |
| 86 | 106 |
| 87 Used to verify the packaged code works when installed as CIPD package, it is | 107 Used to verify the packaged code works when installed as CIPD package, it is |
| 88 important for infra_python package that has non-trivial structure. | 108 important for infra_python package that has non-trivial structure. |
| 89 | 109 |
| 90 Args: | 110 Args: |
| 91 cipd_client: path to cipd client executable. | |
| 92 package_out_dir: where to search for built packages. | 111 package_out_dir: where to search for built packages. |
| 93 work_dir: where to install/update packages into. | 112 work_dir: where to install/update packages into. |
| 94 packages: names of *.cipd files in package_out_dir or [] for all. | 113 packages: names of *.cipd files in package_out_dir or [] for all. |
| 95 | 114 |
| 96 Returns: | 115 Returns: |
| 97 0 on success, 1 or error. | 116 0 on success, 1 or error. |
| 98 """ | 117 """ |
| 99 # Discover what to test. | 118 # Discover what to test. |
| 100 paths = [] | 119 paths = [] |
| 101 if not packages: | 120 if not packages: |
| 102 paths = glob.glob(os.path.join(package_out_dir, '*.cipd')) | 121 # Enumerate all known tests in tests/*.py and filter them based on |
|
Vadim Sh.
2016/06/25 03:51:04
this method no longer works, since package_out_dir
| |
| 122 # availability of corresponding *.cipd package in package_out_dir. It will | |
| 123 # skip any cross-compiled packages, since they have additional '+<platform>' | |
| 124 # suffix in the package file name. | |
| 125 for test in os.listdir(package_tests_dir): | |
| 126 if not test.endswith('.py'): | |
| 127 continue | |
| 128 pkg_file = os.path.join( | |
| 129 package_out_dir, os.path.splitext(test)[0] + '.cipd') | |
| 130 if os.path.exists(pkg_file): | |
| 131 paths.append(pkg_file) | |
| 103 else: | 132 else: |
| 104 for name in packages: | 133 for name in packages: |
| 105 abs_path = os.path.join(package_out_dir, name) | 134 abs_path = os.path.join(package_out_dir, name) |
| 106 if not os.path.isfile(abs_path): | 135 if not os.path.isfile(abs_path): |
| 107 raise TestException('No such package file: %s' % name) | 136 raise TestException('No such package file: %s' % name) |
| 108 paths.append(abs_path) | 137 paths.append(abs_path) |
| 109 paths = sorted(paths) | 138 paths = sorted(paths) |
| 110 if not paths: | 139 if not paths: |
| 111 print 'Nothing to test.' | 140 print 'Nothing to test.' |
| 112 return 0 | 141 return 0 |
| 113 | 142 |
| 114 # Run all tests sequentially. There're like 2 of them tops. | 143 cipd_client = find_cipd_client(package_out_dir) |
| 144 if not cipd_client: | |
| 145 return 1 | |
| 146 | |
| 147 # Run all tests sequentially. Most of the are extra fast. | |
| 115 nuke_temp = False | 148 nuke_temp = False |
| 116 if not work_dir: | 149 if not work_dir: |
| 117 work_dir = tempfile.mkdtemp(suffix='cipd_test') | 150 work_dir = tempfile.mkdtemp(suffix='cipd_test') |
| 118 nuke_temp = True | 151 nuke_temp = True |
| 119 work_dir = os.path.abspath(work_dir) | 152 work_dir = os.path.abspath(work_dir) |
| 120 try: | 153 try: |
| 121 fail = False | 154 fail = False |
| 122 for path in paths: | 155 for path in paths: |
| 123 name = os.path.splitext(os.path.basename(path))[0] | 156 name = os.path.splitext(os.path.basename(path))[0] |
| 124 test_script = os.path.join(package_tests_dir, '%s.py' % name) | 157 test_script = os.path.join(package_tests_dir, '%s.py' % name) |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 142 finally: | 175 finally: |
| 143 if nuke_temp: | 176 if nuke_temp: |
| 144 try: | 177 try: |
| 145 shutil.rmtree(work_dir, ignore_errors=True) | 178 shutil.rmtree(work_dir, ignore_errors=True) |
| 146 except OSError as exc: | 179 except OSError as exc: |
| 147 print >> sys.stderr, 'Failed to delete %s: %s' % (work_dir, exc) | 180 print >> sys.stderr, 'Failed to delete %s: %s' % (work_dir, exc) |
| 148 | 181 |
| 149 | 182 |
| 150 def main( | 183 def main( |
| 151 args, | 184 args, |
| 152 go_workspace=os.path.join(ROOT, 'go'), | |
| 153 package_out_dir=os.path.join(ROOT, 'build', 'out'), | 185 package_out_dir=os.path.join(ROOT, 'build', 'out'), |
| 154 package_tests_dir=os.path.join(ROOT, 'build', 'tests')): | 186 package_tests_dir=os.path.join(ROOT, 'build', 'tests')): |
| 155 parser = argparse.ArgumentParser(description='Tests infra CIPD packages') | 187 parser = argparse.ArgumentParser(description='Tests infra CIPD packages') |
| 156 parser.add_argument( | 188 parser.add_argument( |
| 157 'packages', metavar='NAME', type=str, nargs='*', | 189 'packages', metavar='NAME', type=str, nargs='*', |
| 158 help='name of a build package file in build/out/* to deploy and test') | 190 help='name of a built package file in build/out/* to deploy and test') |
| 159 parser.add_argument( | 191 parser.add_argument( |
| 160 '--work-dir', metavar='DIR', dest='work_dir', | 192 '--work-dir', metavar='DIR', dest='work_dir', |
| 161 help='directory to deploy packages into (temporary dir by default)') | 193 help='directory to deploy packages into (temporary dir by default)') |
| 162 args = parser.parse_args(args) | 194 args = parser.parse_args(args) |
| 163 return run( | 195 return run( |
| 164 os.path.join(go_workspace, 'bin', 'cipd' + EXE_SUFFIX), | |
| 165 package_out_dir, | 196 package_out_dir, |
| 166 package_tests_dir, | 197 package_tests_dir, |
| 167 args.work_dir, | 198 args.work_dir, |
| 168 [n + '.cipd' if not n.endswith('.cipd') else n for n in args.packages]) | 199 [n + '.cipd' if not n.endswith('.cipd') else n for n in args.packages]) |
| 169 | 200 |
| 170 | 201 |
| 171 if __name__ == '__main__': | 202 if __name__ == '__main__': |
| 172 sys.exit(main(sys.argv[1:])) | 203 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |