Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(481)

Side by Side Diff: build/test_packages.py

Issue 2095173002: Teach build.py to cross-compile go-based packages. (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: prebuild stdlib Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/packages/luci_machine_tokend.yaml ('k') | go/bootstrap.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 os 16 import os
17 import re 17 import re
18 import shutil 18 import shutil
19 import subprocess 19 import subprocess
20 import sys 20 import sys
21 import tempfile 21 import tempfile
22 22
23 23
24 # Root of infra.git repository. 24 # Root of infra.git repository.
25 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 25 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
(...skipping 19 matching lines...) Expand all
45 def get_docstring(test_script): 45 def get_docstring(test_script):
46 """Hacky way to grab a first line of a module docstring using regexps.""" 46 """Hacky way to grab a first line of a module docstring using regexps."""
47 with open(test_script, 'rt') as f: 47 with open(test_script, 'rt') as f:
48 text = f.read() 48 text = f.read()
49 m = re.match(r'^.*"""(.*?)"""', text, re.DOTALL) 49 m = re.match(r'^.*"""(.*?)"""', text, re.DOTALL)
50 if not m: 50 if not m:
51 return None 51 return None
52 return m.group(1).strip().splitlines()[0] 52 return m.group(1).strip().splitlines()[0]
53 53
54 54
55 def find_cipd_client(out_dir):
56 """Returns path to cipd client built by build.py.
57
58 See build_cipd_client in build.py. It puts cipd client into
59 '<out_dir>/.cipd_client/cipd_<digest>' and there's only one such file there.
60
61 Prints error message and returns None if the file cannot be found.
62 """
63 out_dir = os.path.join(out_dir, '.cipd_client')
64 files = [f for f in os.listdir(out_dir) if f.startswith('cipd_')]
65 if not files:
66 print >> sys.stderr, 'Cannot find CIPD client in %s' % out_dir
67 return None
68 if len(files) != 1:
69 print >> sys.stderr, (
70 'There should be only one cipd client binary in %s, found %s' %
71 (out_dir, files))
72 return None
73 cipd_client = os.path.join(out_dir, files[0])
74 if not os.access(cipd_client, os.X_OK):
75 print >> sys.stderr, 'CIPD client at %s is not runnable'
76 return None
77 return cipd_client
78
79
55 def run_test(cipd_client, package, work_dir, test_script): 80 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.""" 81 """Extracts a package to a dir and runs test_script with cwd == work_dir."""
57 print_title('Deploying %s' % os.path.basename(package)) 82 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] 83 cmd_line = ['cipd', 'pkg-deploy', '-root', work_dir, package]
64 print ' '.join(cmd_line) 84 print ' '.join(cmd_line)
65 if subprocess.call(args=cmd_line, executable=cipd_client): 85 if subprocess.call(args=cmd_line, executable=cipd_client):
66 raise TestException('Failed to install %s, see logs' % package) 86 raise TestException('Failed to install %s, see logs' % package)
67 87
68 print_title(get_docstring(test_script) or 'Running tests...') 88 print_title(get_docstring(test_script) or 'Running tests...')
69 cmd_line = ['python', test_script] 89 cmd_line = ['python', test_script]
70 print '%s in %s' % (' '.join(cmd_line), work_dir) 90 print '%s in %s' % (' '.join(cmd_line), work_dir)
71 env = os.environ.copy() 91 env = os.environ.copy()
72 env.pop('PYTHONPATH', None) 92 env.pop('PYTHONPATH', None)
73 ret = subprocess.call( 93 ret = subprocess.call(
74 args=cmd_line, executable=sys.executable, env=env, cwd=work_dir) 94 args=cmd_line, executable=sys.executable, env=env, cwd=work_dir)
75 if ret: 95 if ret:
76 raise TestException('Non zero exit code (%d)' % ret) 96 raise TestException('Non zero exit code (%d)' % ret)
77 97
78 98
79 def run( 99 def run(
80 cipd_client,
81 package_out_dir, 100 package_out_dir,
82 package_tests_dir, 101 package_tests_dir,
83 work_dir, 102 work_dir,
84 packages): 103 packages):
85 """Deployes build *.cipd package locally and runs tests against them. 104 """Deployes build *.cipd package locally and runs tests against them.
86 105
87 Used to verify the packaged code works when installed as CIPD package, it is 106 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. 107 important for infra_python package that has non-trivial structure.
89 108
90 Args: 109 Args:
91 cipd_client: path to cipd client executable.
92 package_out_dir: where to search for built packages. 110 package_out_dir: where to search for built packages.
93 work_dir: where to install/update packages into. 111 work_dir: where to install/update packages into.
94 packages: names of *.cipd files in package_out_dir or [] for all. 112 packages: names of *.cipd files in package_out_dir or [] for all.
95 113
96 Returns: 114 Returns:
97 0 on success, 1 or error. 115 0 on success, 1 or error.
98 """ 116 """
99 # Discover what to test. 117 # Discover what to test.
100 paths = [] 118 paths = []
101 if not packages: 119 if not packages:
102 paths = glob.glob(os.path.join(package_out_dir, '*.cipd')) 120 # Enumerate all known tests in tests/*.py and filter them based on
121 # availability of corresponding *.cipd package in package_out_dir. It will
122 # skip any cross-compiled packages, since they have additional '+<platform>'
123 # suffix in the package file name.
124 for test in os.listdir(package_tests_dir):
125 if not test.endswith('.py'):
126 continue
127 pkg_file = os.path.join(
128 package_out_dir, os.path.splitext(test)[0] + '.cipd')
129 if os.path.exists(pkg_file):
130 paths.append(pkg_file)
103 else: 131 else:
104 for name in packages: 132 for name in packages:
105 abs_path = os.path.join(package_out_dir, name) 133 abs_path = os.path.join(package_out_dir, name)
106 if not os.path.isfile(abs_path): 134 if not os.path.isfile(abs_path):
107 raise TestException('No such package file: %s' % name) 135 raise TestException('No such package file: %s' % name)
108 paths.append(abs_path) 136 paths.append(abs_path)
109 paths = sorted(paths) 137 paths = sorted(paths)
110 if not paths: 138 if not paths:
111 print 'Nothing to test.' 139 print 'Nothing to test.'
112 return 0 140 return 0
113 141
114 # Run all tests sequentially. There're like 2 of them tops. 142 cipd_client = find_cipd_client(package_out_dir)
143 if not cipd_client:
144 return 1
145
146 # Run all tests sequentially. Most of the are extra fast.
115 nuke_temp = False 147 nuke_temp = False
116 if not work_dir: 148 if not work_dir:
117 work_dir = tempfile.mkdtemp(suffix='cipd_test') 149 work_dir = tempfile.mkdtemp(suffix='cipd_test')
118 nuke_temp = True 150 nuke_temp = True
119 work_dir = os.path.abspath(work_dir) 151 work_dir = os.path.abspath(work_dir)
120 try: 152 try:
121 fail = False 153 fail = False
122 for path in paths: 154 for path in paths:
123 name = os.path.splitext(os.path.basename(path))[0] 155 name = os.path.splitext(os.path.basename(path))[0]
124 test_script = os.path.join(package_tests_dir, '%s.py' % name) 156 test_script = os.path.join(package_tests_dir, '%s.py' % name)
(...skipping 17 matching lines...) Expand all
142 finally: 174 finally:
143 if nuke_temp: 175 if nuke_temp:
144 try: 176 try:
145 shutil.rmtree(work_dir, ignore_errors=True) 177 shutil.rmtree(work_dir, ignore_errors=True)
146 except OSError as exc: 178 except OSError as exc:
147 print >> sys.stderr, 'Failed to delete %s: %s' % (work_dir, exc) 179 print >> sys.stderr, 'Failed to delete %s: %s' % (work_dir, exc)
148 180
149 181
150 def main( 182 def main(
151 args, 183 args,
152 go_workspace=os.path.join(ROOT, 'go'),
153 package_out_dir=os.path.join(ROOT, 'build', 'out'), 184 package_out_dir=os.path.join(ROOT, 'build', 'out'),
154 package_tests_dir=os.path.join(ROOT, 'build', 'tests')): 185 package_tests_dir=os.path.join(ROOT, 'build', 'tests')):
155 parser = argparse.ArgumentParser(description='Tests infra CIPD packages') 186 parser = argparse.ArgumentParser(description='Tests infra CIPD packages')
156 parser.add_argument( 187 parser.add_argument(
157 'packages', metavar='NAME', type=str, nargs='*', 188 'packages', metavar='NAME', type=str, nargs='*',
158 help='name of a build package file in build/out/* to deploy and test') 189 help='name of a built package file in build/out/* to deploy and test')
159 parser.add_argument( 190 parser.add_argument(
160 '--work-dir', metavar='DIR', dest='work_dir', 191 '--work-dir', metavar='DIR', dest='work_dir',
161 help='directory to deploy packages into (temporary dir by default)') 192 help='directory to deploy packages into (temporary dir by default)')
162 args = parser.parse_args(args) 193 args = parser.parse_args(args)
163 return run( 194 return run(
164 os.path.join(go_workspace, 'bin', 'cipd' + EXE_SUFFIX),
165 package_out_dir, 195 package_out_dir,
166 package_tests_dir, 196 package_tests_dir,
167 args.work_dir, 197 args.work_dir,
168 [n + '.cipd' if not n.endswith('.cipd') else n for n in args.packages]) 198 [n + '.cipd' if not n.endswith('.cipd') else n for n in args.packages])
169 199
170 200
171 if __name__ == '__main__': 201 if __name__ == '__main__':
172 sys.exit(main(sys.argv[1:])) 202 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « build/packages/luci_machine_tokend.yaml ('k') | go/bootstrap.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698