| Index: bin/cros_au_test_harness.py
|
| diff --git a/bin/cros_au_test_harness.py b/bin/cros_au_test_harness.py
|
| index 67c0485ba08ea58e74a81a726eed19ff22ac7639..2c2f8f8218f28b129d0d02db5e82f22ad1468a19 100755
|
| --- a/bin/cros_au_test_harness.py
|
| +++ b/bin/cros_au_test_harness.py
|
| @@ -15,8 +15,10 @@
|
| import optparse
|
| import os
|
| import re
|
| +import shutil
|
| import subprocess
|
| import sys
|
| +import tempfile
|
| import threading
|
| import time
|
| import unittest
|
| @@ -53,11 +55,74 @@ class AUTest(object):
|
| self.crosutils = os.path.join(os.path.dirname(__file__), '..')
|
| self.crosutilsbin = os.path.join(os.path.dirname(__file__))
|
| self.download_folder = os.path.join(self.crosutils, 'latest_download')
|
| + self.vm_image_path = None
|
| if not os.path.exists(self.download_folder):
|
| os.makedirs(self.download_folder)
|
|
|
| # -------- Helper functions ---------
|
|
|
| + def _PrepareRealBase(self, image_path):
|
| + self.PerformUpdate(image_path)
|
| +
|
| + def _PrepareVMBase(self, image_path):
|
| + # VM Constants.
|
| + FULL_VDISK_SIZE = 6072
|
| + FULL_STATEFULFS_SIZE = 3074
|
| + # Needed for VM delta updates. We need to use the qemu image rather
|
| + # than the base image on a first update. By tracking the first_update
|
| + # we can set src_image to the qemu form of the base image when
|
| + # performing generating the delta payload.
|
| + self._first_update = True
|
| + self.vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
|
| + image_path)
|
| + if not os.path.exists(self.vm_image_path):
|
| + Info('Creating %s' % self.vm_image_path)
|
| + RunCommand(['%s/image_to_vm.sh' % self.crosutils,
|
| + '--full',
|
| + '--from=%s' % ReinterpretPathForChroot(
|
| + os.path.dirname(image_path)),
|
| + '--vdisk_size=%s' % FULL_VDISK_SIZE,
|
| + '--statefulfs_size=%s' % FULL_STATEFULFS_SIZE,
|
| + '--board=%s' % self.board,
|
| + '--test_image'], enter_chroot=True)
|
| +
|
| + Info('Using %s as base' % self.vm_image_path)
|
| + self.assertTrue(os.path.exists(self.vm_image_path))
|
| +
|
| + def AppendUpdateFlags(self, cmd, image_path, src_image_path, proxy_port,
|
| + private_key_path):
|
| + """Appends common args to an update cmd defined by an array.
|
| +
|
| + Modifies cmd in places by appending appropriate items given args.
|
| + """
|
| + if proxy_port: cmd.append('--proxy_port=%s' % proxy_port)
|
| +
|
| + # Get pregenerated update if we have one.
|
| + update_id = _GenerateUpdateId(target=image_path, src=src_image_path,
|
| + key=private_key_path)
|
| + cache_path = dev_server_cache[update_id]
|
| + if cache_path:
|
| + update_url = DevServerWrapper.GetDevServerURL(proxy_port, cache_path)
|
| + cmd.append('--update_url=%s' % update_url)
|
| + else:
|
| + cmd.append('--image=%s' % image_path)
|
| + if src_image_path: cmd.append('--src_image=%s' % src_image_path)
|
| +
|
| + def RunUpdateCmd(self, cmd):
|
| + """Runs the given update cmd given verbose options.
|
| +
|
| + Raises an UpdateException if the update fails.
|
| + """
|
| + if self.verbose:
|
| + try:
|
| + RunCommand(cmd)
|
| + except Exception, e:
|
| + raise UpdateException(1, e.message)
|
| + else:
|
| + (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
|
| + if code != 0:
|
| + raise UpdateException(code, stdout)
|
| +
|
| def GetStatefulChangeFlag(self, stateful_change):
|
| """Returns the flag to pass to image_to_vm for the stateful change."""
|
| stateful_change_flag = ''
|
| @@ -101,7 +166,7 @@ class AUTest(object):
|
| return percent_passed
|
|
|
| def PerformUpdate(self, image_path, src_image_path='', stateful_change='old',
|
| - proxy_port=None):
|
| + proxy_port=None, private_key_path=None):
|
| """Performs an update using _UpdateImage and reports any error.
|
|
|
| Subclasses should not override this method but override _UpdateImage
|
| @@ -121,10 +186,14 @@ class AUTest(object):
|
| Raises an UpdateException if _UpdateImage returns an error.
|
| """
|
| try:
|
| - if not self.use_delta_updates:
|
| - src_image_path = ''
|
| + if not self.use_delta_updates: src_image_path = ''
|
| + if private_key_path:
|
| + key_to_use = private_key_path
|
| + else:
|
| + key_to_use = self.private_key
|
|
|
| - self._UpdateImage(image_path, src_image_path, stateful_change, proxy_port)
|
| + self._UpdateImage(image_path, src_image_path, stateful_change, proxy_port,
|
| + key_to_use)
|
| except UpdateException as err:
|
| # If the update fails, print it out
|
| Warning(err.stdout)
|
| @@ -178,6 +247,9 @@ class AUTest(object):
|
| cls.base_image_path = options.base_image
|
| cls.target_image_path = options.target_image
|
| cls.use_delta_updates = options.delta
|
| + cls.board = options.board
|
| + cls.private_key = options.private_key
|
| + cls.clean = options.clean
|
| if options.quick_test:
|
| cls.verify_suite = 'build_RootFilesystemSize'
|
| else:
|
| @@ -199,7 +271,7 @@ class AUTest(object):
|
| pass
|
|
|
| def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
| - proxy_port=None):
|
| + proxy_port=None, private_key_path=None):
|
| """Implementation of an actual update.
|
|
|
| See PerformUpdate for description of args. Subclasses must override this
|
| @@ -410,32 +482,20 @@ class RealAUTest(unittest.TestCase, AUTest):
|
|
|
| def PrepareBase(self, image_path):
|
| """Auto-update to base image to prepare for test."""
|
| - self.PerformUpdate(image_path)
|
| + _PrepareRealBase(image_path)
|
|
|
| def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
| - proxy_port=None):
|
| + proxy_port=None, private_key_path=None):
|
| """Updates a remote image using image_to_live.sh."""
|
| stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
| cmd = ['%s/image_to_live.sh' % self.crosutils,
|
| - '--image=%s' % image_path,
|
| '--remote=%s' % self.remote,
|
| stateful_change_flag,
|
| '--verify',
|
| - '--src_image=%s' % src_image_path
|
| ]
|
| -
|
| - if proxy_port:
|
| - cmd.append('--proxy_port=%s' % proxy_port)
|
| -
|
| - if self.verbose:
|
| - try:
|
| - RunCommand(cmd)
|
| - except Exception, e:
|
| - raise UpdateException(1, e.message)
|
| - else:
|
| - (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
|
| - if code != 0:
|
| - raise UpdateException(code, stdout)
|
| + self.AppendUpdateFlags(cmd, image_path, src_image_path, proxy_port,
|
| + private_key_path)
|
| + self.RunUpdateCmd(cmd)
|
|
|
| def _UpdateUsingPayload(self, update_path, stateful_change='old',
|
| proxy_port=None):
|
| @@ -447,19 +507,8 @@ class RealAUTest(unittest.TestCase, AUTest):
|
| stateful_change_flag,
|
| '--verify',
|
| ]
|
| -
|
| - if proxy_port:
|
| - cmd.append('--proxy_port=%s' % proxy_port)
|
| -
|
| - if self.verbose:
|
| - try:
|
| - RunCommand(cmd)
|
| - except Exception, e:
|
| - raise UpdateException(1, e.message)
|
| - else:
|
| - (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
|
| - if code != 0:
|
| - raise UpdateException(code, stdout)
|
| + if proxy_port: cmd.append('--proxy_port=%s' % proxy_port)
|
| + self.RunUpdateCmd(cmd)
|
|
|
| def VerifyImage(self, percent_required_to_pass):
|
| """Verifies an image using run_remote_tests.sh with verification suite."""
|
| @@ -474,10 +523,6 @@ class RealAUTest(unittest.TestCase, AUTest):
|
| class VirtualAUTest(unittest.TestCase, AUTest):
|
| """Test harness for updating virtual machines."""
|
|
|
| - # VM Constants.
|
| - _FULL_VDISK_SIZE = 6072
|
| - _FULL_STATEFULFS_SIZE = 3074
|
| -
|
| # Class variables used to acquire individual VM variables per test.
|
| _vm_lock = threading.Lock()
|
| _next_port = 9222
|
| @@ -501,7 +546,6 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
| def setUp(self):
|
| """Unit test overriden method. Is called before every test."""
|
| AUTest.setUp(self)
|
| - self.vm_image_path = None
|
| self._AcquireUniquePortAndPidFile()
|
| self._KillExistingVM(self._kvm_pid_file)
|
|
|
| @@ -512,85 +556,37 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
| def ProcessOptions(cls, parser, options):
|
| """Processes vm-specific options."""
|
| AUTest.ProcessOptions(parser, options)
|
| - cls.board = options.board
|
|
|
| # Communicate flags to tests.
|
| cls.graphics_flag = ''
|
| if options.no_graphics: cls.graphics_flag = '--no_graphics'
|
| -
|
| - if not cls.board:
|
| - parser.error('Need board to convert base image to vm.')
|
| + if not cls.board: parser.error('Need board to convert base image to vm.')
|
|
|
| def PrepareBase(self, image_path):
|
| """Creates an update-able VM based on base image."""
|
| - # Needed for VM delta updates. We need to use the qemu image rather
|
| - # than the base image on a first update. By tracking the first_update
|
| - # we can set src_image to the qemu form of the base image when
|
| - # performing generating the delta payload.
|
| - self._first_update = True
|
| - self.vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
|
| - image_path)
|
| - if not os.path.exists(self.vm_image_path):
|
| - Info('Creating %s' % vm_image_path)
|
| - RunCommand(['%s/image_to_vm.sh' % self.crosutils,
|
| - '--full',
|
| - '--from=%s' % ReinterpretPathForChroot(
|
| - os.path.dirname(image_path)),
|
| - '--vdisk_size=%s' % self._FULL_VDISK_SIZE,
|
| - '--statefulfs_size=%s' % self._FULL_STATEFULFS_SIZE,
|
| - '--board=%s' % self.board,
|
| - '--test_image'], enter_chroot=True)
|
| -
|
| - Info('Using %s as base' % self.vm_image_path)
|
| - self.assertTrue(os.path.exists(self.vm_image_path))
|
| + self._PrepareVMBase(image_path)
|
|
|
| def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
| - proxy_port=''):
|
| + proxy_port='', private_key_path=None):
|
| """Updates VM image with image_path."""
|
| stateful_change_flag = self.GetStatefulChangeFlag(stateful_change)
|
| if src_image_path and self._first_update:
|
| src_image_path = self.vm_image_path
|
| self._first_update = False
|
|
|
| - # Check image payload cache first.
|
| - update_id = _GenerateUpdateId(target=image_path, src=src_image_path)
|
| - cache_path = dev_server_cache[update_id]
|
| - if cache_path:
|
| - Info('Using cache %s' % cache_path)
|
| - update_url = DevServerWrapper.GetDevServerURL(proxy_port, cache_path)
|
| - cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
| - '--vm_image_path=%s' % self.vm_image_path,
|
| - '--snapshot',
|
| - self.graphics_flag,
|
| - '--persist',
|
| - '--kvm_pid=%s' % self._kvm_pid_file,
|
| - '--ssh_port=%s' % self._ssh_port,
|
| - stateful_change_flag,
|
| - '--update_url=%s' % update_url,
|
| - ]
|
| - else:
|
| - cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
| - '--update_image_path=%s' % image_path,
|
| - '--vm_image_path=%s' % self.vm_image_path,
|
| - '--snapshot',
|
| - self.graphics_flag,
|
| - '--persist',
|
| - '--kvm_pid=%s' % self._kvm_pid_file,
|
| - '--ssh_port=%s' % self._ssh_port,
|
| - stateful_change_flag,
|
| - '--src_image=%s' % src_image_path,
|
| - '--proxy_port=%s' % proxy_port
|
| - ]
|
| + cmd = ['%s/cros_run_vm_update' % self.crosutilsbin,
|
| + '--vm_image_path=%s' % self.vm_image_path,
|
| + '--snapshot',
|
| + self.graphics_flag,
|
| + '--persist',
|
| + '--kvm_pid=%s' % self._kvm_pid_file,
|
| + '--ssh_port=%s' % self._ssh_port,
|
| + stateful_change_flag,
|
| + ]
|
|
|
| - if self.verbose:
|
| - try:
|
| - RunCommand(cmd)
|
| - except Exception, e:
|
| - raise UpdateException(1, e.message)
|
| - else:
|
| - (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
|
| - if code != 0:
|
| - raise UpdateException(code, stdout)
|
| + self.AppendUpdateFlags(cmd, image_path, src_image_path, proxy_port,
|
| + private_key_path)
|
| + self.RunUpdateCmd(cmd)
|
|
|
| def _UpdateUsingPayload(self, update_path, stateful_change='old',
|
| proxy_port=None):
|
| @@ -606,19 +602,8 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
| '--ssh_port=%s' % self._ssh_port,
|
| stateful_change_flag,
|
| ]
|
| -
|
| - if proxy_port:
|
| - cmd.append('--proxy_port=%s' % proxy_port)
|
| -
|
| - if self.verbose:
|
| - try:
|
| - RunCommand(cmd)
|
| - except Exception, e:
|
| - raise UpdateException(1, e.message)
|
| - else:
|
| - (code, stdout, stderr) = RunCommandCaptureOutput(cmd)
|
| - if code != 0:
|
| - raise UpdateException(code, stdout)
|
| + if proxy_port: cmd.append('--proxy_port=%s' % proxy_port)
|
| + self.RunUpdateCmd(cmd)
|
|
|
| def VerifyImage(self, percent_required_to_pass):
|
| """Runs vm smoke suite to verify image."""
|
| @@ -642,8 +627,12 @@ class VirtualAUTest(unittest.TestCase, AUTest):
|
| return self.AssertEnoughTestsPassed(self, output, percent_required_to_pass)
|
|
|
|
|
| -class GenerateVirtualAUDeltasTest(VirtualAUTest):
|
| - """Class the overrides VirtualAUTest and stores deltas we will generate."""
|
| +class PregenerateAUDeltas(unittest.TestCase, AUTest):
|
| + """Magical class that emulates an AUTest to store deltas we will generate.
|
| +
|
| + This class emulates an AUTest such that when it runs as a TestCase it runs
|
| + through the exact up
|
| + """
|
| delta_list = {}
|
|
|
| def setUp(self):
|
| @@ -652,16 +641,29 @@ class GenerateVirtualAUDeltasTest(VirtualAUTest):
|
| def tearDown(self):
|
| pass
|
|
|
| + @classmethod
|
| + def ProcessOptions(cls, parser, options):
|
| + AUTest.ProcessOptions(parser, options)
|
| + cls.au_type = options.type
|
| +
|
| + def PrepareBase(self, image_path):
|
| + if self.au_type == 'vm':
|
| + self._PrepareVMBase(image_path)
|
| + else:
|
| + self._PrepareRealBase(image_path)
|
| +
|
| def _UpdateImage(self, image_path, src_image_path='', stateful_change='old',
|
| - proxy_port=None):
|
| - if src_image_path and self._first_update:
|
| + proxy_port=None, private_key_path=None):
|
| + if self.au_type == 'vm' and src_image_path and self._first_update:
|
| src_image_path = self.vm_image_path
|
| self._first_update = False
|
|
|
| + # Generate a value that combines delta with private key path.
|
| + val = '%s+%s' % (src_image_path, private_key_path)
|
| if not self.delta_list.has_key(image_path):
|
| - self.delta_list[image_path] = set([src_image_path])
|
| + self.delta_list[image_path] = set([val])
|
| else:
|
| - self.delta_list[image_path].add(src_image_path)
|
| + self.delta_list[image_path].add(val)
|
|
|
| def AttemptUpdateWithPayloadExpectedFailure(self, payload, expected_msg):
|
| pass
|
| @@ -756,15 +758,16 @@ class DevServerWrapper(threading.Thread):
|
| return url
|
|
|
|
|
| -def _GenerateUpdateId(target, src):
|
| +def _GenerateUpdateId(target, src, key):
|
| """Returns a simple representation id of target and src paths."""
|
| - if src:
|
| - return '%s->%s' % (target, src)
|
| - else:
|
| - return target
|
| + update_id = target
|
| + if src: update_id = '->'.join([update_id, src])
|
| + if key: update_id = '+'.join([update_id, key])
|
| + return update_id
|
|
|
|
|
| -def _RunParallelJobs(number_of_sumultaneous_jobs, jobs, jobs_args, print_status):
|
| +def _RunParallelJobs(number_of_sumultaneous_jobs, jobs, jobs_args,
|
| + print_status):
|
|
|
| """Runs set number of specified jobs in parallel.
|
|
|
| @@ -834,40 +837,47 @@ def _PregenerateUpdates(parser, options):
|
| Raises:
|
| UpdateException if we fail to generate an update.
|
| """
|
| - def _GenerateVMUpdate(target, src):
|
| + def _GenerateVMUpdate(target, src, private_key_path):
|
| """Generates an update using the devserver."""
|
| - target = ReinterpretPathForChroot(target)
|
| - if src:
|
| - src = ReinterpretPathForChroot(src)
|
| -
|
| - return RunCommandCaptureOutput(['./enter_chroot.sh',
|
| - '--nogit_config',
|
| - '--',
|
| - 'sudo',
|
| - './start_devserver',
|
| - '--pregenerate_update',
|
| - '--exit',
|
| - '--image=%s' % target,
|
| - '--src_image=%s' % src,
|
| - '--for_vm',
|
| - ], combine_stdout_stderr=True,
|
| - print_cmd=False)
|
| + command = ['./enter_chroot.sh',
|
| + '--nogit_config',
|
| + '--',
|
| + 'sudo',
|
| + './start_devserver',
|
| + '--pregenerate_update',
|
| + '--exit',
|
| + ]
|
| + # Add actual args to command.
|
| + command.append('--image=%s' % ReinterpretPathForChroot(target))
|
| + if src: command.append('--src_image=%s' % ReinterpretPathForChroot(src))
|
| + if options.type == 'vm': command.append('--for_vm')
|
| + if private_key_path:
|
| + command.append('--private_key=%s' %
|
| + ReinterpretPathForChroot(private_key_path))
|
| +
|
| + return RunCommandCaptureOutput(command, combine_stdout_stderr=True,
|
| + print_cmd=True)
|
|
|
| # Get the list of deltas by mocking out update method in test class.
|
| - test_suite = _PrepareTestSuite(parser, options, GenerateVirtualAUDeltasTest)
|
| + test_suite = _PrepareTestSuite(parser, options, PregenerateAUDeltas)
|
| test_result = unittest.TextTestRunner(verbosity=0).run(test_suite)
|
| + if not test_result.wasSuccessful():
|
| + raise UpdateException(1, 'Error finding updates to generate.')
|
|
|
| Info('The following delta updates are required.')
|
| update_ids = []
|
| jobs = []
|
| args = []
|
| - for target, srcs in GenerateVirtualAUDeltasTest.delta_list.items():
|
| - for src in srcs:
|
| - update_id = _GenerateUpdateId(target=target, src=src)
|
| + for target, srcs in PregenerateAUDeltas.delta_list.items():
|
| + for src_key in srcs:
|
| + (src, key) = src_key.split('+')
|
| + # TODO(sosa): Add private key as part of caching name once devserver can
|
| + # handle it its own cache.
|
| + update_id = _GenerateUpdateId(target=target, src=src, key=key)
|
| print >> sys.stderr, 'AU: %s' % update_id
|
| update_ids.append(update_id)
|
| jobs.append(_GenerateVMUpdate)
|
| - args.append((target, src))
|
| + args.append((target, src, key))
|
|
|
| raw_results = _RunParallelJobs(options.jobs, jobs, args, print_status=True)
|
| results = []
|
| @@ -919,12 +929,74 @@ def _RunTestsInParallel(parser, options, test_class):
|
| Die('Test harness was not successful')
|
|
|
|
|
| +def InsertPublicKeyIntoImage(image_path, key_path):
|
| + """Inserts public key into image @ static update_engine location."""
|
| + from_dir = os.path.dirname(image_path)
|
| + image = os.path.basename(image_path)
|
| + crosutils_dir = os.path.abspath(__file__).rsplit('/', 2)[0]
|
| + target_key_path = 'usr/share/update_engine/update-payload-key.pub.pem'
|
| +
|
| + # Temporary directories for this function.
|
| + rootfs_dir = tempfile.mkdtemp(suffix='rootfs', prefix='tmp')
|
| + stateful_dir = tempfile.mkdtemp(suffix='stateful', prefix='tmp')
|
| +
|
| + Info('Copying %s into %s' % (key_path, image_path))
|
| + try:
|
| + RunCommand(['./mount_gpt_image.sh',
|
| + '--from=%s' % from_dir,
|
| + '--image=%s' % image,
|
| + '--rootfs_mountpt=%s' % rootfs_dir,
|
| + '--stateful_mountpt=%s' % stateful_dir,
|
| + ], print_cmd=False, redirect_stdout=True,
|
| + redirect_stderr=True, cwd=crosutils_dir)
|
| + path = os.path.join(rootfs_dir, target_key_path)
|
| + dir_path = os.path.dirname(path)
|
| + RunCommand(['sudo', 'mkdir', '--parents', dir_path], print_cmd=False)
|
| + RunCommand(['sudo', 'cp', '--force', '-p', key_path, path],
|
| + print_cmd=False)
|
| + finally:
|
| + # Unmount best effort regardless.
|
| + RunCommand(['./mount_gpt_image.sh',
|
| + '--unmount',
|
| + '--rootfs_mountpt=%s' % rootfs_dir,
|
| + '--stateful_mountpt=%s' % stateful_dir,
|
| + ], print_cmd=False, redirect_stdout=True, redirect_stderr=True,
|
| + cwd=crosutils_dir)
|
| + # Clean up our directories.
|
| + os.rmdir(rootfs_dir)
|
| + os.rmdir(stateful_dir)
|
| +
|
| + RunCommand(['bin/cros_make_image_bootable', from_dir, image, ],
|
| + print_cmd=False, redirect_stdout=True, redirect_stderr=True,
|
| + enter_chroot=True, cwd=crosutils_dir)
|
| +
|
| +
|
| +def CleanPreviousWork(options):
|
| + """Cleans up previous work from the devserver cache and local image cache."""
|
| + Info('Cleaning up previous work.')
|
| + # Wipe devserver cache.
|
| + RunCommandCaptureOutput(
|
| + ['sudo', './start_devserver', '--clear_cache', '--exit', ],
|
| + enter_chroot=True, print_cmd=False, combine_stdout_stderr=True)
|
| +
|
| + # Clean previous vm images if they exist.
|
| + if options.type == 'vm':
|
| + target_vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
|
| + options.target_image)
|
| + base_vm_image_path = '%s/chromiumos_qemu_image.bin' % os.path.dirname(
|
| + options.base_image)
|
| + if os.path.exists(target_vm_image_path): os.remove(target_vm_image_path)
|
| + if os.path.exists(base_vm_image_path): os.remove(base_vm_image_path)
|
| +
|
| +
|
| def main():
|
| parser = optparse.OptionParser()
|
| parser.add_option('-b', '--base_image',
|
| help='path to the base image.')
|
| parser.add_option('-r', '--board',
|
| help='board for the images.')
|
| + parser.add_option('--clean', default=False, dest='clean', action='store_true',
|
| + help='Clean all previous state')
|
| parser.add_option('--no_delta', action='store_false', default=True,
|
| dest='delta',
|
| help='Disable using delta updates.')
|
| @@ -932,6 +1004,10 @@ def main():
|
| help='Disable graphics for the vm test.')
|
| parser.add_option('-j', '--jobs', default=8, type=int,
|
| help='Number of simultaneous jobs')
|
| + parser.add_option('--public_key', default=None,
|
| + help='Public key to use on images and updates.')
|
| + parser.add_option('--private_key', default=None,
|
| + help='Private key to use on images and updates.')
|
| parser.add_option('-q', '--quick_test', default=False, action='store_true',
|
| help='Use a basic test to verify image.')
|
| parser.add_option('-m', '--remote',
|
| @@ -948,31 +1024,52 @@ def main():
|
| 'possible.')
|
| (options, leftover_args) = parser.parse_args()
|
|
|
| - if leftover_args:
|
| - parser.error('Found extra options we do not support: %s' % leftover_args)
|
| + if leftover_args: parser.error('Found unsupported flags: %s' % leftover_args)
|
| +
|
| + assert options.target_image and os.path.exists(options.target_image), \
|
| + 'Target image path does not exist'
|
| + if not options.base_image:
|
| + Info('Base image not specified. Using target image as base image.')
|
| + options.base_image = options.target_image
|
| +
|
| + # Sanity checks on keys and insert them onto the image. The caches must be
|
| + # cleaned so we know that the vm images and payloads match the possibly new
|
| + # key.
|
| + if options.private_key or options.public_key:
|
| + error_msg = ('Could not find %s key. Both private and public keys must be '
|
| + 'specified if either is specified.')
|
| + assert options.private_key and os.path.exists(options.private_key), \
|
| + error_msg % 'private'
|
| + assert options.public_key and os.path.exists(options.public_key), \
|
| + error_msg % 'public'
|
| + InsertPublicKeyIntoImage(options.target_image, options.public_key)
|
| + InsertPublicKeyIntoImage(options.base_image, options.public_key)
|
| + options.clean = True
|
| +
|
| + # Clean up previous work if requested.
|
| + if options.clean: CleanPreviousWork(options)
|
|
|
| # Figure out the test_class.
|
| if options.type == 'vm': test_class = VirtualAUTest
|
| elif options.type == 'real': test_class = RealAUTest
|
| else: parser.error('Could not parse harness type %s.' % options.type)
|
|
|
| - # TODO(sosa): Caching doesn't really make sense on non-vm images (yet).
|
| + # Generate cache of updates to use during test harness.
|
| global dev_server_cache
|
| - if options.type == 'vm' and options.jobs > 1:
|
| - dev_server_cache = _PregenerateUpdates(parser, options)
|
| - my_server = DevServerWrapper()
|
| - my_server.start()
|
| - try:
|
| + dev_server_cache = _PregenerateUpdates(parser, options)
|
| + my_server = DevServerWrapper()
|
| + my_server.start()
|
| + try:
|
| + if options.type == 'vm':
|
| _RunTestsInParallel(parser, options, test_class)
|
| - finally:
|
| - my_server.Stop()
|
| -
|
| - else:
|
| - dev_server_cache = None
|
| - test_suite = _PrepareTestSuite(parser, options, test_class)
|
| - test_result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
| - if not test_result.wasSuccessful():
|
| - Die('Test harness was not successful.')
|
| + else:
|
| + # TODO(sosa) - Take in a machine pool for a real test.
|
| + # Can't run in parallel with only one remote device.
|
| + test_suite = _PrepareTestSuite(parser, options, test_class)
|
| + test_result = unittest.TextTestRunner(verbosity=2).run(test_suite)
|
| + if not test_result.wasSuccessful(): Die('Test harness failed.')
|
| + finally:
|
| + my_server.Stop()
|
|
|
|
|
| if __name__ == '__main__':
|
|
|