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

Side by Side Diff: bin/ctest.py

Issue 6717011: Remove au_test_harness code and change symlinks to point to new location (Closed) Base URL: http://git.chromium.org/git/crosutils.git@master
Patch Set: Created 9 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « bin/ctest ('k') | bin/ctest_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """Wrapper for tests that are run on builders."""
8
9 import fileinput
10 import optparse
11 import os
12 import re
13 import sys
14 import traceback
15 import urllib
16 import HTMLParser
17
18 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib'))
19 from cros_build_lib import Info
20 from cros_build_lib import ReinterpretPathForChroot
21 from cros_build_lib import RunCommand
22 from cros_build_lib import Warning
23
24 _IMAGE_TO_EXTRACT = 'chromiumos_test_image.bin'
25 _NEW_STYLE_VERSION = '0.9.131.0'
26
27 class HTMLDirectoryParser(HTMLParser.HTMLParser):
28 """HTMLParser for parsing the default apache file index."""
29
30 def __init__(self, regex):
31 HTMLParser.HTMLParser.__init__(self)
32 self.regex_object = re.compile(regex)
33 self.link_list = []
34
35 def handle_starttag(self, tag, attrs):
36 """Overrides from HTMLParser and is called at the start of every tag.
37
38 This implementation grabs attributes from links (i.e. <a ... > </a>
39 and adds the target from href=<target> if the <target> matches the
40 regex given at the start.
41 """
42 if not tag.lower() == 'a':
43 return
44
45 for attr in attrs:
46 if not attr[0].lower() == 'href':
47 continue
48
49 match = self.regex_object.match(attr[1])
50 if match:
51 self.link_list.append(match.group(0).rstrip('/'))
52
53
54 def ModifyBootDesc(download_folder, redirect_file=None):
55 """Modifies the boot description of a downloaded image to work with path.
56
57 The default boot.desc from another system is specific to the directory
58 it was created in. This modifies the boot description to be compatiable
59 with the download folder.
60
61 Args:
62 download_folder: Absoulte path to the download folder.
63 redirect_file: For testing. Where to copy new boot desc.
64 """
65 boot_desc_path = os.path.join(download_folder, 'boot.desc')
66 in_chroot_folder = ReinterpretPathForChroot(download_folder)
67
68 for line in fileinput.input(boot_desc_path, inplace=1):
69 # Has to be done here to get changes to sys.stdout from fileinput.input.
70 if not redirect_file:
71 redirect_file = sys.stdout
72 split_line = line.split('=')
73 if len(split_line) > 1:
74 var_part = split_line[0]
75 potential_path = split_line[1].replace('"', '').strip()
76
77 if potential_path.startswith('/home') and not 'output_dir' in var_part:
78 new_path = os.path.join(in_chroot_folder,
79 os.path.basename(potential_path))
80 new_line = '%s="%s"' % (var_part, new_path)
81 Info('Replacing line %s with %s' % (line, new_line))
82 redirect_file.write('%s\n' % new_line)
83 continue
84 elif 'output_dir' in var_part:
85 # Special case for output_dir.
86 new_line = '%s="%s"' % (var_part, in_chroot_folder)
87 Info('Replacing line %s with %s' % (line, new_line))
88 redirect_file.write('%s\n' % new_line)
89 continue
90
91 # Line does not need to be modified.
92 redirect_file.write(line)
93
94 fileinput.close()
95
96
97 def _GreaterVersion(version_a, version_b):
98 """Returns the higher version number of two version number strings."""
99 version_regex = re.compile('.*(\d+)\.(\d+)\.(\d+)\.(\d+).*')
100 version_a_tokens = version_regex.match(version_a).groups()
101 version_b_tokens = version_regex.match(version_b).groups()
102 for i in range(4):
103 (a, b) = (int(version_a_tokens[i]), int(version_b_tokens[i]))
104 if a != b:
105 if a > b: return version_a
106 return version_b
107 return version_a
108
109
110 def GetLatestLinkFromPage(url, regex):
111 """Returns the latest link from the given url that matches regex.
112
113 Args:
114 url: Url to download and parse.
115 regex: Regular expression to match links against.
116 """
117 url_file = urllib.urlopen(url)
118 url_html = url_file.read()
119
120 url_file.close()
121
122 # Parses links with versions embedded.
123 url_parser = HTMLDirectoryParser(regex=regex)
124 url_parser.feed(url_html)
125 return reduce(_GreaterVersion, url_parser.link_list)
126
127
128 def GetNewestLinkFromZipBase(board, channel, zip_server_base):
129 """Returns the url to the newest image from the zip server.
130
131 Args:
132 board: board for the image zip.
133 channel: channel for the image zip.
134 zip_server_base: base url for zipped images.
135 """
136 zip_base = os.path.join(zip_server_base, channel, board)
137 latest_version = GetLatestLinkFromPage(zip_base, '\d+\.\d+\.\d+\.\d+/')
138
139 zip_dir = os.path.join(zip_base, latest_version)
140 zip_name = GetLatestLinkFromPage(zip_dir,
141 'ChromeOS-\d+\.\d+\.\d+\.\d+-.*\.zip')
142 return os.path.join(zip_dir, zip_name)
143
144
145 def GetLatestZipUrl(board, channel, latest_url_base, zip_server_base):
146 """Returns the url of the latest image zip for the given arguments.
147
148 Args:
149 board: board for the image zip.
150 channel: channel for the image zip.
151 latest_url_base: base url for latest links.
152 zip_server_base: base url for zipped images.
153 """
154 if latest_url_base:
155 try:
156 # Grab the latest image info.
157 latest_file_url = os.path.join(latest_url_base, channel,
158 'LATEST-%s' % board)
159 latest_image_file = urllib.urlopen(latest_file_url)
160 latest_image = latest_image_file.read()
161 latest_image_file.close()
162 # Convert bin.gz into zip.
163 latest_image = latest_image.replace('.bin.gz', '.zip')
164 version = latest_image.split('-')[1]
165 zip_base = os.path.join(zip_server_base, channel, board)
166 return os.path.join(zip_base, version, latest_image)
167 except IOError:
168 Warning(('Could not use latest link provided, defaulting to parsing'
169 ' latest from zip url base.'))
170
171 try:
172 return GetNewestLinkFromZipBase(board, channel, zip_server_base)
173 except:
174 Warning('Failed to get url from standard zip base. Trying rc.')
175 return GetNewestLinkFromZipBase(board + '-rc', channel, zip_server_base)
176
177
178 def GrabZipAndExtractImage(zip_url, download_folder, image_name) :
179 """Downloads the zip and extracts the given image.
180
181 Doesn't re-download if matching version found already in download folder.
182 Args:
183 zip_url - url for the image.
184 download_folder - download folder to store zip file and extracted images.
185 image_name - name of the image to extract from the zip file.
186 """
187 zip_path = os.path.join(download_folder, 'image.zip')
188 versioned_url_path = os.path.join(download_folder, 'download_url')
189 found_cached = False
190
191 if os.path.exists(versioned_url_path):
192 fh = open(versioned_url_path)
193 version_url = fh.read()
194 fh.close()
195
196 if version_url == zip_url and os.path.exists(os.path.join(download_folder,
197 image_name)):
198 Info('Using cached %s' % image_name)
199 found_cached = True
200
201 if not found_cached:
202 Info('Downloading %s' % zip_url)
203 RunCommand(['rm', '-rf', download_folder], print_cmd=False)
204 os.mkdir(download_folder)
205 urllib.urlretrieve(zip_url, zip_path)
206
207 # Using unzip because python implemented unzip in native python so
208 # extraction is really slow.
209 Info('Unzipping image %s' % image_name)
210 RunCommand(['unzip', '-d', download_folder, zip_path],
211 print_cmd=False, error_message='Failed to download %s' % zip_url)
212
213 ModifyBootDesc(download_folder)
214
215 # Put url in version file so we don't have to do this every time.
216 fh = open(versioned_url_path, 'w+')
217 fh.write(zip_url)
218 fh.close()
219
220 version = zip_url.split('/')[-2]
221 if not _GreaterVersion(version, _NEW_STYLE_VERSION) == version:
222 # If the version isn't ready for new style, touch file to use old style.
223 old_style_touch_path = os.path.join(download_folder, '.use_e1000')
224 fh = open(old_style_touch_path, 'w+')
225 fh.close()
226
227
228 def RunAUTestHarness(board, channel, latest_url_base, zip_server_base,
229 no_graphics, type, remote, clean, test_results_root):
230 """Runs the auto update test harness.
231
232 The auto update test harness encapsulates testing the auto-update mechanism
233 for the latest image against the latest official image from the channel. This
234 also tests images with suite_Smoke (built-in as part of its verification
235 process).
236
237 Args:
238 board: the board for the latest image.
239 channel: the channel to run the au test harness against.
240 latest_url_base: base url for getting latest links.
241 zip_server_base: base url for zipped images.
242 no_graphics: boolean - If True, disable graphics during vm test.
243 type: which test harness to run. Possible values: real, vm.
244 remote: ip address for real test harness run.
245 clean: Clean the state of test harness before running.
246 test_results_root: Root directory to store au_test_harness results.
247 """
248 crosutils_root = os.path.join(os.path.dirname(__file__), '..')
249 download_folder = os.path.abspath('latest_download')
250 zip_url = GetLatestZipUrl(board, channel, latest_url_base, zip_server_base)
251 GrabZipAndExtractImage(zip_url, download_folder, _IMAGE_TO_EXTRACT)
252
253 # Tests go here.
254 latest_image = RunCommand(['./get_latest_image.sh', '--board=%s' % board],
255 cwd=crosutils_root, redirect_stdout=True,
256 print_cmd=True).strip()
257
258 update_engine_path = os.path.join(crosutils_root, '..', 'platform',
259 'update_engine')
260
261 cmd = ['bin/cros_au_test_harness',
262 '--base_image=%s' % os.path.join(download_folder,
263 _IMAGE_TO_EXTRACT),
264 '--target_image=%s' % os.path.join(latest_image,
265 _IMAGE_TO_EXTRACT),
266 '--board=%s' % board,
267 '--type=%s' % type,
268 '--remote=%s' % remote,
269 '--private_key=%s' % os.path.join(update_engine_path,
270 'unittest_key.pem'),
271 '--public_key=%s' % os.path.join(update_engine_path,
272 'unittest_key.pub.pem'),
273 ]
274 if test_results_root: cmd.append('--test_results_root=%s' % test_results_root)
275 if no_graphics: cmd.append('--no_graphics')
276 if clean: cmd.append('--clean')
277
278 RunCommand(cmd, cwd=crosutils_root)
279
280
281 def main():
282 parser = optparse.OptionParser()
283 parser.add_option('-b', '--board',
284 help='board for the image to compare against.')
285 parser.add_option('-c', '--channel',
286 help='channel for the image to compare against.')
287 parser.add_option('--cache', default=False, action='store_true',
288 help='Cache payloads')
289 parser.add_option('-l', '--latestbase',
290 help='Base url for latest links.')
291 parser.add_option('-z', '--zipbase',
292 help='Base url for hosted images.')
293 parser.add_option('--no_graphics', action='store_true', default=False,
294 help='Disable graphics for the vm test.')
295 parser.add_option('--test_results_root', default=None,
296 help='Root directory to store test results. Should '
297 'be defined relative to chroot root.')
298 parser.add_option('--type', default='vm',
299 help='type of test to run: [vm, real]. Default: vm.')
300 parser.add_option('--remote', default='0.0.0.0',
301 help='For real tests, ip address of the target machine.')
302
303 # Set the usage to include flags.
304 parser.set_usage(parser.format_help())
305 (options, args) = parser.parse_args()
306
307 if args: parser.error('Extra args found %s.' % args)
308 if not options.board: parser.error('Need board for image to compare against.')
309 if not options.channel: parser.error('Need channel e.g. dev-channel.')
310 if not options.zipbase: parser.error('Need zip url base to get images.')
311
312 RunAUTestHarness(options.board, options.channel, options.latestbase,
313 options.zipbase, options.no_graphics, options.type,
314 options.remote, not options.cache,
315 options.test_results_root)
316
317
318 if __name__ == '__main__':
319 main()
320
OLDNEW
« no previous file with comments | « bin/ctest ('k') | bin/ctest_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698