| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 # | 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 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 | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """Wrapper for tests that are run on builders.""" | 7 """Wrapper for tests that are run on builders.""" |
| 8 | 8 |
| 9 import fileinput | 9 import fileinput |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import re | 12 import re |
| 13 import sys | 13 import sys |
| 14 import traceback | 14 import traceback |
| 15 import urllib | 15 import urllib |
| 16 import HTMLParser | 16 import HTMLParser |
| 17 | 17 |
| 18 sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) | 18 import constants |
| 19 from cros_build_lib import Info | 19 sys.path.append(constants.SOURCE_ROOT) |
| 20 from cros_build_lib import ReinterpretPathForChroot | 20 import chromite.lib.cros_build_lib as cros_lib |
| 21 from cros_build_lib import RunCommand | |
| 22 from cros_build_lib import Warning | |
| 23 | 21 |
| 24 _IMAGE_TO_EXTRACT = 'chromiumos_test_image.bin' | 22 _IMAGE_TO_EXTRACT = 'chromiumos_test_image.bin' |
| 25 _NEW_STYLE_VERSION = '0.9.131.0' | 23 _NEW_STYLE_VERSION = '0.9.131.0' |
| 26 | 24 |
| 27 class HTMLDirectoryParser(HTMLParser.HTMLParser): | 25 class HTMLDirectoryParser(HTMLParser.HTMLParser): |
| 28 """HTMLParser for parsing the default apache file index.""" | 26 """HTMLParser for parsing the default apache file index.""" |
| 29 | 27 |
| 30 def __init__(self, regex): | 28 def __init__(self, regex): |
| 31 HTMLParser.HTMLParser.__init__(self) | 29 HTMLParser.HTMLParser.__init__(self) |
| 32 self.regex_object = re.compile(regex) | 30 self.regex_object = re.compile(regex) |
| (...skipping 23 matching lines...) Expand all Loading... |
| 56 | 54 |
| 57 The default boot.desc from another system is specific to the directory | 55 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 | 56 it was created in. This modifies the boot description to be compatiable |
| 59 with the download folder. | 57 with the download folder. |
| 60 | 58 |
| 61 Args: | 59 Args: |
| 62 download_folder: Absoulte path to the download folder. | 60 download_folder: Absoulte path to the download folder. |
| 63 redirect_file: For testing. Where to copy new boot desc. | 61 redirect_file: For testing. Where to copy new boot desc. |
| 64 """ | 62 """ |
| 65 boot_desc_path = os.path.join(download_folder, 'boot.desc') | 63 boot_desc_path = os.path.join(download_folder, 'boot.desc') |
| 66 in_chroot_folder = ReinterpretPathForChroot(download_folder) | 64 in_chroot_folder = cros_lib.ReinterpretPathForChroot(download_folder) |
| 67 | 65 |
| 68 for line in fileinput.input(boot_desc_path, inplace=1): | 66 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. | 67 # Has to be done here to get changes to sys.stdout from fileinput.input. |
| 70 if not redirect_file: | 68 if not redirect_file: |
| 71 redirect_file = sys.stdout | 69 redirect_file = sys.stdout |
| 72 split_line = line.split('=') | 70 split_line = line.split('=') |
| 73 if len(split_line) > 1: | 71 if len(split_line) > 1: |
| 74 var_part = split_line[0] | 72 var_part = split_line[0] |
| 75 potential_path = split_line[1].replace('"', '').strip() | 73 potential_path = split_line[1].replace('"', '').strip() |
| 76 | 74 |
| 77 if potential_path.startswith('/home') and not 'output_dir' in var_part: | 75 if potential_path.startswith('/home') and not 'output_dir' in var_part: |
| 78 new_path = os.path.join(in_chroot_folder, | 76 new_path = os.path.join(in_chroot_folder, |
| 79 os.path.basename(potential_path)) | 77 os.path.basename(potential_path)) |
| 80 new_line = '%s="%s"' % (var_part, new_path) | 78 new_line = '%s="%s"' % (var_part, new_path) |
| 81 Info('Replacing line %s with %s' % (line, new_line)) | 79 cros_lib.Info('Replacing line %s with %s' % (line, new_line)) |
| 82 redirect_file.write('%s\n' % new_line) | 80 redirect_file.write('%s\n' % new_line) |
| 83 continue | 81 continue |
| 84 elif 'output_dir' in var_part: | 82 elif 'output_dir' in var_part: |
| 85 # Special case for output_dir. | 83 # Special case for output_dir. |
| 86 new_line = '%s="%s"' % (var_part, in_chroot_folder) | 84 new_line = '%s="%s"' % (var_part, in_chroot_folder) |
| 87 Info('Replacing line %s with %s' % (line, new_line)) | 85 cros_lib.Info('Replacing line %s with %s' % (line, new_line)) |
| 88 redirect_file.write('%s\n' % new_line) | 86 redirect_file.write('%s\n' % new_line) |
| 89 continue | 87 continue |
| 90 | 88 |
| 91 # Line does not need to be modified. | 89 # Line does not need to be modified. |
| 92 redirect_file.write(line) | 90 redirect_file.write(line) |
| 93 | 91 |
| 94 fileinput.close() | 92 fileinput.close() |
| 95 | 93 |
| 96 | 94 |
| 97 def _GreaterVersion(version_a, version_b): | 95 def _GreaterVersion(version_a, version_b): |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 """ | 133 """ |
| 136 zip_base = os.path.join(zip_server_base, channel, board) | 134 zip_base = os.path.join(zip_server_base, channel, board) |
| 137 latest_version = GetLatestLinkFromPage(zip_base, '\d+\.\d+\.\d+\.\d+/') | 135 latest_version = GetLatestLinkFromPage(zip_base, '\d+\.\d+\.\d+\.\d+/') |
| 138 | 136 |
| 139 zip_dir = os.path.join(zip_base, latest_version) | 137 zip_dir = os.path.join(zip_base, latest_version) |
| 140 zip_name = GetLatestLinkFromPage(zip_dir, | 138 zip_name = GetLatestLinkFromPage(zip_dir, |
| 141 'ChromeOS-\d+\.\d+\.\d+\.\d+-.*\.zip') | 139 'ChromeOS-\d+\.\d+\.\d+\.\d+-.*\.zip') |
| 142 return os.path.join(zip_dir, zip_name) | 140 return os.path.join(zip_dir, zip_name) |
| 143 | 141 |
| 144 | 142 |
| 145 def GetLatestZipUrl(board, channel, latest_url_base, zip_server_base): | 143 def GetLatestZipUrl(board, channel, zip_server_base): |
| 146 """Returns the url of the latest image zip for the given arguments. | 144 """Returns the url of the latest image zip for the given arguments. |
| 147 | 145 |
| 146 If the latest does not exist, tries to find the rc equivalent. |
| 147 |
| 148 Args: | 148 Args: |
| 149 board: board for the image zip. | 149 board: board for the image zip. |
| 150 channel: channel 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. | 151 zip_server_base: base url for zipped images. |
| 153 """ | 152 """ |
| 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: | 153 try: |
| 172 return GetNewestLinkFromZipBase(board, channel, zip_server_base) | 154 return GetNewestLinkFromZipBase(board, channel, zip_server_base) |
| 173 except: | 155 except: |
| 174 Warning('Failed to get url from standard zip base. Trying rc.') | 156 cros_lib.Warning('Failed to get url from standard zip base. Trying rc.') |
| 175 return GetNewestLinkFromZipBase(board + '-rc', channel, zip_server_base) | 157 return GetNewestLinkFromZipBase(board + '-rc', channel, zip_server_base) |
| 176 | 158 |
| 177 | 159 |
| 178 def GrabZipAndExtractImage(zip_url, download_folder, image_name) : | 160 def GrabZipAndExtractImage(zip_url, download_folder, image_name) : |
| 179 """Downloads the zip and extracts the given image. | 161 """Downloads the zip and extracts the given image. |
| 180 | 162 |
| 181 Doesn't re-download if matching version found already in download folder. | 163 Doesn't re-download if matching version found already in download folder. |
| 182 Args: | 164 Args: |
| 183 zip_url - url for the image. | 165 zip_url - url for the image. |
| 184 download_folder - download folder to store zip file and extracted images. | 166 download_folder - download folder to store zip file and extracted images. |
| 185 image_name - name of the image to extract from the zip file. | 167 image_name - name of the image to extract from the zip file. |
| 186 """ | 168 """ |
| 187 zip_path = os.path.join(download_folder, 'image.zip') | 169 zip_path = os.path.join(download_folder, 'image.zip') |
| 188 versioned_url_path = os.path.join(download_folder, 'download_url') | 170 versioned_url_path = os.path.join(download_folder, 'download_url') |
| 189 found_cached = False | 171 found_cached = False |
| 190 | 172 |
| 191 if os.path.exists(versioned_url_path): | 173 if os.path.exists(versioned_url_path): |
| 192 fh = open(versioned_url_path) | 174 fh = open(versioned_url_path) |
| 193 version_url = fh.read() | 175 version_url = fh.read() |
| 194 fh.close() | 176 fh.close() |
| 195 | 177 |
| 196 if version_url == zip_url and os.path.exists(os.path.join(download_folder, | 178 if version_url == zip_url and os.path.exists(os.path.join(download_folder, |
| 197 image_name)): | 179 image_name)): |
| 198 Info('Using cached %s' % image_name) | 180 cros_lib.Info('Using cached %s' % image_name) |
| 199 found_cached = True | 181 found_cached = True |
| 200 | 182 |
| 201 if not found_cached: | 183 if not found_cached: |
| 202 Info('Downloading %s' % zip_url) | 184 cros_lib.Info('Downloading %s' % zip_url) |
| 203 RunCommand(['rm', '-rf', download_folder], print_cmd=False) | 185 cros_lib.RunCommand(['rm', '-rf', download_folder], print_cmd=False) |
| 204 os.mkdir(download_folder) | 186 os.mkdir(download_folder) |
| 205 urllib.urlretrieve(zip_url, zip_path) | 187 urllib.urlretrieve(zip_url, zip_path) |
| 206 | 188 |
| 207 # Using unzip because python implemented unzip in native python so | 189 # Using unzip because python implemented unzip in native python so |
| 208 # extraction is really slow. | 190 # extraction is really slow. |
| 209 Info('Unzipping image %s' % image_name) | 191 cros_lib.Info('Unzipping image %s' % image_name) |
| 210 RunCommand(['unzip', '-d', download_folder, zip_path], | 192 cros_lib.RunCommand(['unzip', '-d', download_folder, zip_path], |
| 211 print_cmd=False, error_message='Failed to download %s' % zip_url) | 193 print_cmd=False, error_message='Failed to download %s' % zip_url) |
| 212 | 194 |
| 213 ModifyBootDesc(download_folder) | 195 ModifyBootDesc(download_folder) |
| 214 | 196 |
| 215 # Put url in version file so we don't have to do this every time. | 197 # Put url in version file so we don't have to do this every time. |
| 216 fh = open(versioned_url_path, 'w+') | 198 fh = open(versioned_url_path, 'w+') |
| 217 fh.write(zip_url) | 199 fh.write(zip_url) |
| 218 fh.close() | 200 fh.close() |
| 219 | 201 |
| 220 version = zip_url.split('/')[-2] | 202 version = zip_url.split('/')[-2] |
| 221 if not _GreaterVersion(version, _NEW_STYLE_VERSION) == version: | 203 if not _GreaterVersion(version, _NEW_STYLE_VERSION) == version: |
| 222 # If the version isn't ready for new style, touch file to use old style. | 204 # 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') | 205 old_style_touch_path = os.path.join(download_folder, '.use_e1000') |
| 224 fh = open(old_style_touch_path, 'w+') | 206 fh = open(old_style_touch_path, 'w+') |
| 225 fh.close() | 207 fh.close() |
| 226 | 208 |
| 227 | 209 |
| 228 def RunAUTestHarness(board, channel, latest_url_base, zip_server_base, | 210 def RunAUTestHarness(board, channel, zip_server_base, |
| 229 no_graphics, type, remote, clean, test_results_root): | 211 no_graphics, type, remote, clean, test_results_root): |
| 230 """Runs the auto update test harness. | 212 """Runs the auto update test harness. |
| 231 | 213 |
| 232 The auto update test harness encapsulates testing the auto-update mechanism | 214 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 | 215 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 | 216 also tests images with suite_Smoke (built-in as part of its verification |
| 235 process). | 217 process). |
| 236 | 218 |
| 237 Args: | 219 Args: |
| 238 board: the board for the latest image. | 220 board: the board for the latest image. |
| 239 channel: the channel to run the au test harness against. | 221 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. | 222 zip_server_base: base url for zipped images. |
| 242 no_graphics: boolean - If True, disable graphics during vm test. | 223 no_graphics: boolean - If True, disable graphics during vm test. |
| 243 type: which test harness to run. Possible values: real, vm. | 224 type: which test harness to run. Possible values: real, vm. |
| 244 remote: ip address for real test harness run. | 225 remote: ip address for real test harness run. |
| 245 clean: Clean the state of test harness before running. | 226 clean: Clean the state of test harness before running. |
| 246 test_results_root: Root directory to store au_test_harness results. | 227 test_results_root: Root directory to store au_test_harness results. |
| 247 """ | 228 """ |
| 248 crosutils_root = os.path.join(os.path.dirname(__file__), '..') | 229 crosutils_root = os.path.join(constants.SOURCE_ROOT, 'src', 'scripts') |
| 249 download_folder = os.path.abspath('latest_download') | 230 download_folder = os.path.abspath('latest_download') |
| 250 zip_url = GetLatestZipUrl(board, channel, latest_url_base, zip_server_base) | 231 zip_url = GetLatestZipUrl(board, channel, zip_server_base) |
| 251 GrabZipAndExtractImage(zip_url, download_folder, _IMAGE_TO_EXTRACT) | 232 GrabZipAndExtractImage(zip_url, download_folder, _IMAGE_TO_EXTRACT) |
| 252 | 233 |
| 253 # Tests go here. | 234 # Tests go here. |
| 254 latest_image = RunCommand(['./get_latest_image.sh', '--board=%s' % board], | 235 return_object = cros_lib.RunCommand( |
| 255 cwd=crosutils_root, redirect_stdout=True, | 236 ['./get_latest_image.sh', '--board=%s' % board], cwd=crosutils_root, |
| 256 print_cmd=True).strip() | 237 redirect_stdout=True, print_cmd=True) |
| 238 |
| 239 latest_image = return_object.output.strip() |
| 257 | 240 |
| 258 update_engine_path = os.path.join(crosutils_root, '..', 'platform', | 241 update_engine_path = os.path.join(crosutils_root, '..', 'platform', |
| 259 'update_engine') | 242 'update_engine') |
| 260 | 243 |
| 261 cmd = ['bin/cros_au_test_harness', | 244 cmd = ['bin/cros_au_test_harness', |
| 262 '--base_image=%s' % os.path.join(download_folder, | 245 '--base_image=%s' % os.path.join(download_folder, |
| 263 _IMAGE_TO_EXTRACT), | 246 _IMAGE_TO_EXTRACT), |
| 264 '--target_image=%s' % os.path.join(latest_image, | 247 '--target_image=%s' % os.path.join(latest_image, |
| 265 _IMAGE_TO_EXTRACT), | 248 _IMAGE_TO_EXTRACT), |
| 266 '--board=%s' % board, | 249 '--board=%s' % board, |
| 267 '--type=%s' % type, | 250 '--type=%s' % type, |
| 268 '--remote=%s' % remote, | 251 '--remote=%s' % remote, |
| 269 '--private_key=%s' % os.path.join(update_engine_path, | 252 '--private_key=%s' % os.path.join(update_engine_path, |
| 270 'unittest_key.pem'), | 253 'unittest_key.pem'), |
| 271 '--public_key=%s' % os.path.join(update_engine_path, | 254 '--public_key=%s' % os.path.join(update_engine_path, |
| 272 'unittest_key.pub.pem'), | 255 'unittest_key.pub.pem'), |
| 273 ] | 256 ] |
| 274 if test_results_root: cmd.append('--test_results_root=%s' % test_results_root) | 257 if test_results_root: cmd.append('--test_results_root=%s' % test_results_root) |
| 275 if no_graphics: cmd.append('--no_graphics') | 258 if no_graphics: cmd.append('--no_graphics') |
| 276 if clean: cmd.append('--clean') | 259 if clean: cmd.append('--clean') |
| 277 | 260 |
| 278 RunCommand(cmd, cwd=crosutils_root) | 261 cros_lib.RunCommand(cmd, cwd=crosutils_root) |
| 279 | 262 |
| 280 | 263 |
| 281 def main(): | 264 def main(): |
| 282 parser = optparse.OptionParser() | 265 parser = optparse.OptionParser() |
| 283 parser.add_option('-b', '--board', | 266 parser.add_option('-b', '--board', |
| 284 help='board for the image to compare against.') | 267 help='board for the image to compare against.') |
| 285 parser.add_option('-c', '--channel', | 268 parser.add_option('-c', '--channel', |
| 286 help='channel for the image to compare against.') | 269 help='channel for the image to compare against.') |
| 287 parser.add_option('--cache', default=False, action='store_true', | 270 parser.add_option('--cache', default=False, action='store_true', |
| 288 help='Cache payloads') | 271 help='Cache payloads') |
| 289 parser.add_option('-l', '--latestbase', | |
| 290 help='Base url for latest links.') | |
| 291 parser.add_option('-z', '--zipbase', | 272 parser.add_option('-z', '--zipbase', |
| 292 help='Base url for hosted images.') | 273 help='Base url for hosted images.') |
| 293 parser.add_option('--no_graphics', action='store_true', default=False, | 274 parser.add_option('--no_graphics', action='store_true', default=False, |
| 294 help='Disable graphics for the vm test.') | 275 help='Disable graphics for the vm test.') |
| 295 parser.add_option('--test_results_root', default=None, | 276 parser.add_option('--test_results_root', default=None, |
| 296 help='Root directory to store test results. Should ' | 277 help='Root directory to store test results. Should ' |
| 297 'be defined relative to chroot root.') | 278 'be defined relative to chroot root.') |
| 298 parser.add_option('--type', default='vm', | 279 parser.add_option('--type', default='vm', |
| 299 help='type of test to run: [vm, real]. Default: vm.') | 280 help='type of test to run: [vm, real]. Default: vm.') |
| 300 parser.add_option('--remote', default='0.0.0.0', | 281 parser.add_option('--remote', default='0.0.0.0', |
| 301 help='For real tests, ip address of the target machine.') | 282 help='For real tests, ip address of the target machine.') |
| 302 | 283 |
| 303 # Set the usage to include flags. | 284 # Set the usage to include flags. |
| 304 parser.set_usage(parser.format_help()) | 285 parser.set_usage(parser.format_help()) |
| 305 (options, args) = parser.parse_args() | 286 (options, args) = parser.parse_args() |
| 306 | 287 |
| 307 if args: parser.error('Extra args found %s.' % args) | 288 if args: parser.error('Extra args found %s.' % args) |
| 308 if not options.board: parser.error('Need board for image to compare against.') | 289 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.') | 290 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.') | 291 if not options.zipbase: parser.error('Need zip url base to get images.') |
| 311 | 292 |
| 312 RunAUTestHarness(options.board, options.channel, options.latestbase, | 293 RunAUTestHarness(options.board, options.channel, options.zipbase, |
| 313 options.zipbase, options.no_graphics, options.type, | 294 options.no_graphics, options.type, options.remote, |
| 314 options.remote, not options.cache, | 295 not options.cache, options.test_results_root) |
| 315 options.test_results_root) | |
| 316 | 296 |
| 317 | 297 |
| 318 if __name__ == '__main__': | 298 if __name__ == '__main__': |
| 319 main() | 299 main() |
| 320 | 300 |
| OLD | NEW |