Index: bin/ctest.py |
diff --git a/bin/ctest.py b/bin/ctest.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..78210b6308c018df885571569f9eda7c16c27c3f |
--- /dev/null |
+++ b/bin/ctest.py |
@@ -0,0 +1,195 @@ |
+#!/usr/bin/python |
+# |
+# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Wrapper for tests that are run on builders.""" |
+ |
+import fileinput |
+import optparse |
+import os |
+import sys |
+import urllib |
+ |
+sys.path.append(os.path.join(os.path.dirname(__file__), '../lib')) |
+from cros_build_lib import Info, RunCommand, ReinterpretPathForChroot |
+ |
+_IMAGE_TO_EXTRACT = 'chromiumos_test_image.bin' |
+ |
+ |
+def ModifyBootDesc(download_folder, redirect_file=None): |
+ """Modifies the boot description of a downloaded image to work with path. |
+ |
+ The default boot.desc from another system is specific to the directory |
+ it was created in. This modifies the boot description to be compatiable |
+ with the download folder. |
+ |
+ Args: |
+ download_folder: Absoulte path to the download folder. |
+ redirect_file: For testing. Where to copy new boot desc. |
+ """ |
+ boot_desc_path = os.path.join(download_folder, 'boot.desc') |
+ in_chroot_folder = ReinterpretPathForChroot(download_folder) |
+ |
+ for line in fileinput.input(boot_desc_path, inplace=1): |
+ # Has to be done here to get changes to sys.stdout from fileinput.input. |
+ if not redirect_file: |
+ redirect_file = sys.stdout |
+ split_line = line.split('=') |
+ if len(split_line) > 1: |
+ var_part = split_line[0] |
+ potential_path = split_line[1].replace('"', '').strip() |
+ |
+ if potential_path.startswith('/home') and not 'output_dir' in var_part: |
+ new_path = os.path.join(in_chroot_folder, |
+ os.path.basename(potential_path)) |
+ new_line = '%s="%s"' % (var_part, new_path) |
+ Info('Replacing line %s with %s' % (line, new_line)) |
+ redirect_file.write('%s\n' % new_line) |
+ continue |
+ elif 'output_dir' in var_part: |
+ # Special case for output_dir. |
+ new_line = '%s="%s"' % (var_part, in_chroot_folder) |
+ Info('Replacing line %s with %s' % (line, new_line)) |
+ redirect_file.write('%s\n' % new_line) |
+ continue |
+ |
+ # Line does not need to be modified. |
+ redirect_file.write(line) |
+ |
+ fileinput.close() |
+ |
+ |
+def GetLatestZipUrl(board, channel, latest_url_base, zip_server_base): |
+ """Returns the url of the latest image zip for the given arguments. |
+ |
+ Args: |
+ board: board for the image zip. |
+ channel: channel for the image zip. |
+ latest_url_base: base url for latest links. |
+ zip_server_base: base url for zipped images. |
+ """ |
+ # Grab the latest image info. |
+ latest_file_url = os.path.join(latest_url_base, channel, |
+ 'LATEST-%s' % board) |
+ latest_image_file = urllib.urlopen(latest_file_url) |
+ latest_image = latest_image_file.read() |
+ latest_image_file.close() |
+ |
+ # Convert bin.gz into zip. |
+ latest_image = latest_image.replace('.bin.gz', '.zip') |
+ version = latest_image.split('-')[1] |
+ zip_base = os.path.join(zip_server_base, channel, board) |
+ return os.path.join(zip_base, version, latest_image) |
+ |
+ |
+def GrabZipAndExtractImage(zip_url, download_folder, image_name) : |
+ """Downloads the zip and extracts the given image. |
+ |
+ Doesn't re-download if matching version found already in download folder. |
+ Args: |
+ zip_url - url for the image. |
+ download_folder - download folder to store zip file and extracted images. |
+ image_name - name of the image to extract from the zip file. |
+ """ |
+ zip_path = os.path.join(download_folder, 'image.zip') |
+ versioned_url_path = os.path.join(download_folder, 'download_url') |
+ found_cached = False |
+ |
+ if os.path.exists(versioned_url_path): |
+ fh = open(versioned_url_path) |
+ version_url = fh.read() |
+ fh.close() |
+ |
+ if version_url == zip_url and os.path.exists(os.path.join(download_folder, |
+ image_name)): |
+ Info('Using cached %s' % image_name) |
+ found_cached = True |
+ |
+ if not found_cached: |
+ Info('Downloading %s' % zip_url) |
+ RunCommand(['rm', '-rf', download_folder], print_cmd=False) |
+ os.mkdir(download_folder) |
+ urllib.urlretrieve(zip_url, zip_path) |
+ |
+ # Using unzip because python implemented unzip in native python so |
+ # extraction is really slow. |
+ Info('Unzipping image %s' % image_name) |
+ RunCommand(['unzip', '-d', download_folder, zip_path], |
+ print_cmd=False, error_message='Failed to download %s' % zip_url) |
+ |
+ ModifyBootDesc(download_folder) |
+ |
+ # Put url in version file so we don't have to do this every time. |
+ fh = open(versioned_url_path, 'w+') |
+ fh.write(zip_url) |
+ fh.close() |
+ |
+ |
+def RunAUTestHarness(board, channel, latest_url_base, zip_server_base): |
+ """Runs the auto update test harness. |
+ |
+ The auto update test harness encapsulates testing the auto-update mechanism |
+ for the latest image against the latest official image from the channel. This |
+ also tests images with suite_Smoke (built-in as part of its verification |
+ process). |
+ |
+ Args: |
+ board: the board for the latest image. |
+ channel: the channel to run the au test harness against. |
+ latest_url_base: base url for getting latest links. |
+ zip_server_base: base url for zipped images. |
+ """ |
+ crosutils_root = os.path.join(os.path.dirname(__file__), '..') |
+ download_folder = os.path.abspath('latest_download') |
+ zip_url = GetLatestZipUrl(board, channel, latest_url_base, zip_server_base) |
+ GrabZipAndExtractImage(zip_url, download_folder, _IMAGE_TO_EXTRACT) |
+ |
+ # Tests go here. |
+ latest_image = RunCommand(['./get_latest_image.sh', '--board=%s' % board], |
+ cwd=crosutils_root, redirect_stdout=True, |
+ print_cmd=True) |
+ |
+ RunCommand(['bin/cros_au_test_harness', |
+ '--base_image=%s' % os.path.join(download_folder, |
+ _IMAGE_TO_EXTRACT), |
+ '--target_image=%s' % latest_image, |
+ '--board=%s' % board], cwd=crosutils_root) |
+ |
+ |
+def main(): |
+ parser = optparse.OptionParser() |
+ parser.add_option('-b', '--board', |
+ help='board for the image to compare against.') |
+ parser.add_option('-c', '--channel', |
+ help='channel for the image to compare against.') |
+ parser.add_option('-l', '--latestbase', |
+ help='Base url for latest links.') |
+ parser.add_option('-z', '--zipbase', |
+ help='Base url for hosted images.') |
+ # Set the usage to include flags. |
+ parser.set_usage(parser.format_help()) |
+ (options, args) = parser.parse_args() |
+ |
+ if args: |
+ parser.error('Extra args found %s.' % args) |
+ |
+ if not options.board: |
+ parser.error('Need board for image to compare against.') |
+ |
+ if not options.channel: |
+ parser.error('Need channel for image to compare against.') |
+ |
+ if not options.latestbase: |
+ parser.error('Need latest url base to get images.') |
+ |
+ if not options.zipbase: |
+ parser.error('Need zip url base to get images.') |
+ |
+ RunAUTestHarness(options.board, options.channel, options.latestbase, |
+ options.zipbase) |
+ |
+ |
+if __name__ == '__main__': |
+ main() |