launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #10107
[Merge] lp:~bac/lpsetup/lxc-integration into lp:lpsetup
Brad Crittenden has proposed merging lp:~bac/lpsetup/lxc-integration into lp:lpsetup.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~bac/lpsetup/lxc-integration/+merge/115804
Add lxc-based integration test.
Discovered a problem with the handling of some command-line options
(working_dir and code_dir) which required some rejiggering. They were
deleted in favor of specifying the repository and checkout-name
separately.
Refactored the test non-lxc.py in order to share code and structure
with lxc.py.
Fun with bzrlib. In retrospect the win over just shelling out to
'bzr' was miniscule.
--
https://code.launchpad.net/~bac/lpsetup/lxc-integration/+merge/115804
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bac/lpsetup/lxc-integration into lp:lpsetup.
=== modified file 'README.rst'
--- README.rst 2012-07-11 16:33:16 +0000
+++ README.rst 2012-07-19 18:30:30 +0000
@@ -59,11 +59,15 @@
Integration tests can be found in lpsetup/tests/integration. They
require the "ubuntu" juju charm which, at the time of this writing, is
not available in the charm store. Check it out into the local juju
-charm repository from lp:~charmers/charms/precise/ubuntu/trunk.
+charm repository from lp:~charmers/charms/precise/ubuntu/trunk. The
+test expects your Juju repository to be at ~/juju-charms
The integration tests use a juju environment named "lpsetup-testing" so
you must create an appropriately configured juju environment with that
-name before running the tests.
+name before running the tests in ~/.juju/environments.yaml.
+
+The tests bootstrap the environment for you and fail if it is already
+running.
You may also want to add this to your SSH .config file to suppress the
many yes/no prompts:
=== modified file 'commands.rst'
--- commands.rst 2012-07-10 19:06:12 +0000
+++ commands.rst 2012-07-19 18:30:30 +0000
@@ -51,13 +51,13 @@
Completely sets up an LXC environment with Launchpad using the sandbox
development model:
-~/launchpad
+~/launchpad/lp-branches
bzr repository with --no-trees option.
-~/launchpad/devel
+~/launchpad/lp-branches/devel
branch with no trees of trunk.
-~/launchpad/sandbox
+~/launchpad/lp-branches/sandbox
lightweight checkout with a tree of ../devel.
-~/launchpad/bug-xyz
+~/launchpad/lp-branches/bug-xyz
branch with no trees of trunk where bug work is done via switching
inside sandbox.
=== modified file 'lpsetup/handlers.py'
--- lpsetup/handlers.py 2012-07-16 16:43:34 +0000
+++ lpsetup/handlers.py 2012-07-19 18:30:30 +0000
@@ -6,6 +6,7 @@
__metaclass__ = type
__all__ = [
+ 'handle_code_dir',
'handle_directories',
'handle_lpuser_as_username',
'handle_lpuser_from_lplogin',
@@ -221,13 +222,13 @@
def handle_directories(namespace):
- """Handle repository, code_dir, and dependencies directories.
+ """Handle repository and dependencies directories.
- The ~ construction is automatically expanded.
- The validation fails for directories not residing inside the home.
- The validation fails if the directory contains spaces.
"""
- for attr in ('repository', 'code_dir', 'dependencies_dir'):
+ for attr in ('repository', 'dependencies_dir'):
directory = getattr(namespace, attr, None)
if directory is None:
continue
@@ -285,11 +286,6 @@
return os.path.abspath(os.path.expanduser(path))
-def handle_working_dir(namespace):
- """Handle path to the working directory."""
- namespace.working_dir = normalize_path(namespace.working_dir)
-
-
def handle_branch_and_checkout(namespace):
"""Handle branch and checkout names.
@@ -303,6 +299,7 @@
- branch_name
- checkout_name
+ - repository
This handler does not modify the namespace.
"""
@@ -318,3 +315,12 @@
raise ValidationError(
'branch and checkout: can not use the same name ({0}).'.format(
checkout_name))
+
+
+def handle_code_dir(namespace):
+ """Handle the computed value for `code_dir`.
+
+ It must be invoked after handle_directories.
+ """
+ namespace.code_dir = os.path.join(
+ namespace.repository, namespace.checkout_name)
=== modified file 'lpsetup/settings.py'
--- lpsetup/settings.py 2012-07-17 17:55:38 +0000
+++ lpsetup/settings.py 2012-07-19 18:30:30 +0000
@@ -3,8 +3,6 @@
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Global settings and defaults for lpsetup."""
-import os.path
-
APT_REPOSITORIES = (
'deb http://archive.ubuntu.com/ubuntu {distro} multiverse',
@@ -56,7 +54,6 @@
LP_BRANCH_NAME = 'devel'
LP_CHECKOUT_NAME = 'sandbox'
LP_REPOSITORY_DIR = '~/launchpad/lp-branches'
-LP_CODE_DIR = os.path.join(LP_REPOSITORY_DIR, LP_CHECKOUT_NAME)
LP_PACKAGES = [
# "launchpad-database-dependencies-9.1" can be removed once 8.x is
# no longer an option in "launchpad-developer-dependencies.
=== modified file 'lpsetup/subcommands/finish_inithost.py'
--- lpsetup/subcommands/finish_inithost.py 2012-07-16 08:17:05 +0000
+++ lpsetup/subcommands/finish_inithost.py 2012-07-19 18:30:30 +0000
@@ -29,10 +29,15 @@
from lpsetup import argparser
from lpsetup.handlers import (
+ handle_code_dir,
handle_directories,
handle_user,
)
-from lpsetup.settings import LP_CODE_DIR
+from lpsetup.settings import (
+ LP_CHECKOUT_NAME,
+ LP_REPOSITORY_DIR,
+ )
+
from lpsetup.utils import call
@@ -75,22 +80,24 @@
handlers = (
handle_user,
handle_directories,
+ handle_code_dir,
)
- @staticmethod
- def add_common_arguments(parser):
- parser.add_argument(
- '-c', '--code-dir', default=LP_CODE_DIR,
- help='The directory of the Launchpad code checkout. '
- 'The directory must reside under the home directory of the '
- 'given user (see -u argument). '
- '[DEFAULT={0}]'.format(LP_CODE_DIR))
-
def add_arguments(self, parser):
super(SubCommand, self).add_arguments(parser)
- self.add_common_arguments(parser)
parser.add_argument(
'-u', '--user',
help='The name of the system user. '
'The current user is used if this script is not run as '
'root and this argument is omitted.')
+ parser.add_argument(
+ '--checkout-name', default=LP_CHECKOUT_NAME,
+ help='Create a checkout with the given name. '
+ 'Ignored if --no-checkout is specified. '
+ 'Defaults to {0}.'.format(LP_CHECKOUT_NAME))
+ parser.add_argument(
+ '-r', '--repository', default=LP_REPOSITORY_DIR,
+ help='The directory of the Launchpad repository to be created. '
+ 'The directory must reside under the home directory of the '
+ 'given user (see -u argument). '
+ '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR))
=== modified file 'lpsetup/subcommands/initrepo.py'
--- lpsetup/subcommands/initrepo.py 2012-07-16 10:09:48 +0000
+++ lpsetup/subcommands/initrepo.py 2012-07-19 18:30:30 +0000
@@ -49,27 +49,39 @@
is_lightweight = not no_checkout
no_trees = '--no-trees' if is_lightweight else None
# Initialize the repository.
- try:
- call('bzr', 'init-repo', '--quiet', repository, no_trees)
- except subprocess.CalledProcessError as err:
- msg = 'Error: unable to initialize the repository: '
- raise exceptions.ExecutionError(msg + err.output)
+
+ # Skip creating the repository if it already exists. There is the
+ # risk that it is not made with the same `no_trees` option as
+ # specified here.
+ if not os.path.exists(os.path.join(repository, '.bzr')):
+ try:
+ call('bzr', 'init-repo', '--quiet', repository, no_trees)
+ except subprocess.CalledProcessError as err:
+ msg = 'Error: unable to initialize the repository: '
+ raise exceptions.ExecutionError(msg + err.output)
# Set up the codebase.
branch_dir = os.path.join(repository, branch_name)
# Retrieve the branch.
+ if os.path.exists(branch_dir):
+ # The branch already exists, so we pull to refresh it rather than
+ # creating it.
+ cmd = ['bzr', 'pull', '--overwrite', '-d', branch_dir, source]
+ else:
+ cmd = ['bzr', 'branch', source, branch_dir]
try:
- call('bzr', 'branch', source, branch_dir)
+ call(*cmd)
except subprocess.CalledProcessError as err:
msg = 'Error: unable to branch source: '
raise exceptions.ExecutionError(msg + err.output)
if is_lightweight:
checkout_dir = os.path.join(repository, checkout_name)
- # Create a lightweight checkout.
- try:
- call('bzr', 'co', '--lightweight', branch_dir, checkout_dir)
- except subprocess.CalledProcessError as err:
- msg = 'Error: unable to create the lightweight checkout: '
- raise exceptions.ExecutionError(msg + err.output)
+ # Create a lightweight checkout if it doesn't exist.
+ if not os.path.exists(checkout_dir):
+ try:
+ call('bzr', 'co', '--lightweight', branch_dir, checkout_dir)
+ except subprocess.CalledProcessError as err:
+ msg = 'Error: unable to create the lightweight checkout: '
+ raise exceptions.ExecutionError(msg + err.output)
def setup_bzr_locations(
=== modified file 'lpsetup/subcommands/install_lxc.py'
--- lpsetup/subcommands/install_lxc.py 2012-07-13 14:51:08 +0000
+++ lpsetup/subcommands/install_lxc.py 2012-07-19 18:30:30 +0000
@@ -13,6 +13,7 @@
import os
from lpsetup.handlers import (
+ handle_code_dir,
handle_directories,
handle_source,
)
@@ -21,7 +22,6 @@
SCRIPTS,
)
from lpsetup.subcommands import (
- finish_inithost,
initlxc,
initrepo,
update,
@@ -69,11 +69,9 @@
def cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=None):
- print "args = ", args
cmd = this_command(home_dir, args)
if as_user is not None:
cmd = "su {} -c '{}'".format(as_user, cmd)
- print "CMD = ", cmd
ssh(lxc_name, cmd, key=ssh_key_path)
@@ -91,18 +89,20 @@
def update_in_lxc(lxc_name, ssh_key_path, home_dir, user, external_path,
use_http, checkout_name, repository):
- working_dir = os.path.join(repository, checkout_name)
args = [
- 'update', '--external-path', external_path, '-W', working_dir,
+ 'update', '--external-path', external_path,
+ '-r', repository, '--checkout-name', checkout_name,
]
if use_http:
args.append('--use-http')
cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args, as_user=user)
-def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user, code_dir):
+def finish_inithost_in_lxc(lxc_name, ssh_key_path, home_dir, user,
+ repository, checkout_name):
args = [
- 'finish-init-host', '--user', user, '--code-dir', code_dir,
+ 'finish-init-host', '--user', user, '--repository', repository,
+ '--checkout-name', checkout_name,
]
cmd_in_lxc(lxc_name, ssh_key_path, home_dir, args)
@@ -121,14 +121,18 @@
(update_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir', 'user',
'external_path', 'use_http', 'checkout_name', 'repository'),
(finish_inithost_in_lxc, 'lxc_name', 'ssh_key_path', 'home_dir',
- 'user', 'code_dir'),
+ 'user', 'repository', 'checkout_name'),
)
help = __doc__
def get_handlers(self, namespace):
handlers = super(SubCommand, self).get_handlers(namespace)
- return handlers + (handle_directories, handle_source)
+ return handlers + (
+ handle_directories,
+ handle_code_dir,
+ handle_source,
+ )
def call_create_scripts(self, namespace, step, args):
"""Run the `create_scripts` step only if the related flag is set."""
@@ -140,7 +144,6 @@
# Inherit arguments from subcommands we depend upon.
initrepo.SubCommand.add_common_arguments(parser)
update.SubCommand.add_common_arguments(parser)
- finish_inithost.SubCommand.add_common_arguments(parser)
# Add parallel testing related arguments.
parser.add_argument(
'-C', '--create-scripts', action='store_true',
=== modified file 'lpsetup/subcommands/update.py'
--- lpsetup/subcommands/update.py 2012-07-13 15:55:40 +0000
+++ lpsetup/subcommands/update.py 2012-07-19 18:30:30 +0000
@@ -19,48 +19,49 @@
from lpsetup import argparser
from lpsetup import handlers
from lpsetup.settings import (
- LP_CODE_DIR,
+ LP_CHECKOUT_NAME,
+ LP_REPOSITORY_DIR,
LP_SOURCE_DEPS,
)
-def initialize_directories(working_dir, external_path):
+def initialize_directories(code_dir, external_path):
"""Initialize the eggs, yui, and sourcecode directories.
Create them if necessary.
"""
for dir_ in ['eggs', 'yui', 'sourcecode']:
- mkdirs(os.path.join(working_dir, external_path, dir_))
-
-
-def update_dependencies(working_dir, external_path, use_http):
+ mkdirs(os.path.join(code_dir, external_path, dir_))
+
+
+def update_dependencies(code_dir, external_path, use_http):
"""Update the external dependencies."""
use_http_param = '--use-http' if use_http else None
- cmd = os.path.join(working_dir, 'utilities', 'update-sourcecode')
+ cmd = os.path.join(code_dir, 'utilities', 'update-sourcecode')
abs_external_path = os.path.abspath(
- os.path.join(working_dir, external_path))
+ os.path.join(code_dir, external_path))
source_path = os.path.join(abs_external_path, 'sourcecode')
run(cmd, use_http_param, source_path)
# Update the download cache.
- download_cache = os.path.join(working_dir, 'download-cache')
+ download_cache = os.path.join(code_dir, 'download-cache')
if os.path.exists(download_cache):
run('bzr', 'up', download_cache)
else:
run('bzr', 'co', '-v', '--lightweight', LP_SOURCE_DEPS, download_cache)
# Link to the external sourcecode.
- if abs_external_path != working_dir:
+ if abs_external_path != code_dir:
cmd = os.path.join(
- working_dir, 'utilities', 'link-external-sourcecode')
+ code_dir, 'utilities', 'link-external-sourcecode')
run(cmd,
- '--target', working_dir,
+ '--target', code_dir,
'--parent', external_path)
-def update_tree(working_dir):
- """Update the tree at working_dir with the latest LP code."""
- with cd(working_dir):
+def update_tree(code_dir):
+ """Update the tree at code_dir with the latest LP code."""
+ with cd(code_dir):
run('bzr', 'pull')
@@ -71,14 +72,16 @@
"""
steps = (
- (initialize_directories, 'working_dir', 'external_path'),
- (update_dependencies, 'working_dir', 'external_path', 'use_http'),
- (update_tree, 'working_dir'),
+ (initialize_directories, 'code_dir', 'external_path'),
+ (update_dependencies, 'code_dir', 'external_path', 'use_http'),
+ (update_tree, 'code_dir'),
)
help = __doc__
handlers = (
# Normalize paths and default to cwd if none exists.
- handlers.handle_working_dir,
+ handlers.handle_user,
+ handlers.handle_directories,
+ handlers.handle_code_dir,
)
@staticmethod
@@ -97,6 +100,13 @@
help='Force bzr to use http to get the sourcecode '
'branches rather than using bzr+ssh.')
parser.add_argument(
- '-W', '--working-dir', default=LP_CODE_DIR,
- help='Path to branch to update. '
- '[DEFAULT={0}]'.format(LP_CODE_DIR))
+ '--checkout-name', default=LP_CHECKOUT_NAME,
+ help='Create a checkout with the given name. '
+ 'Ignored if --no-checkout is specified. '
+ 'Defaults to {0}.'.format(LP_CHECKOUT_NAME))
+ parser.add_argument(
+ '-r', '--repository', default=LP_REPOSITORY_DIR,
+ help='The directory of the Launchpad repository to be created. '
+ 'The directory must reside under the home directory of the '
+ 'given user (see -u argument). '
+ '[DEFAULT={0}]'.format(LP_REPOSITORY_DIR))
=== added file 'lpsetup/tests/integration/common.py'
--- lpsetup/tests/integration/common.py 1970-01-01 00:00:00 +0000
+++ lpsetup/tests/integration/common.py 2012-07-19 18:30:30 +0000
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Common resources for integration tests."""
+
+__metaclass__ = type
+__all__ = [
+ 'IntegrationTestBase',
+ ]
+
+import argparse
+
+
+class IntegrationTestBase:
+
+ banner_width = 70
+ test_type = None
+
+ def __init__(self):
+ self.parser = argparse.ArgumentParser()
+ self.parser.add_argument('--no-tear-down', action='store_true',
+ default=False,
+ help='Do not run the tear down method for debugging.')
+ self.args = self.parser.parse_args()
+
+ def banner(self, msg, width=banner_width):
+ print '*' * width
+ print '* ' + msg.ljust(width - 4) + ' *'
+ print '*' * width
+
+ def set_up(self):
+ self.banner(
+ 'Setting up the test environment for {}.'.format(self.test_type))
+
+ def tear_down(self):
+ self.banner('Cleaning up.')
+
+ def check_environment(self):
+ self.banner('Checking test environment.')
+
+ def do_test(self):
+ self.banner('Running integration tests for {}.'.format(self.test_type))
+
+ def run(self):
+ self.check_environment()
+ try:
+ self.set_up()
+ try:
+ self.do_test()
+ except Exception as err:
+ self.banner('Test failed. Sorry.')
+ print err
+ return 1
+ else:
+ self.banner('Test succeeded.')
+ return 0
+ finally:
+ if not self.args.no_tear_down:
+ self.tear_down()
=== added file 'lpsetup/tests/integration/lxc.py'
--- lpsetup/tests/integration/lxc.py 1970-01-01 00:00:00 +0000
+++ lpsetup/tests/integration/lxc.py 2012-07-19 18:30:30 +0000
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# Copyright 2012 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""A simple, end-to-end integration test."""
+
+from bzrlib.branch import Branch
+from bzrlib.errors import NotBranchError
+from bzrlib.missing import find_unmerged
+from bzrlib.status import show_tree_status
+from bzrlib.workingtree import WorkingTree
+from StringIO import StringIO
+import sys
+
+from shelltoolbox import (
+ run,
+ )
+from subprocess import (
+ check_call,
+ )
+
+from common import IntegrationTestBase
+
+
+LXC_NAME = 'lpsetup-testing'
+
+
+class LXCIntegrationTest(IntegrationTestBase):
+
+ test_type = 'LXC container'
+ repo = '~/launchpad-testing/lp-branches'
+
+ def get_branch(self, dir='.'):
+ branch, _ = Branch.open_containing(dir)
+ return branch
+
+ def get_push_location(self, branch=None):
+ if branch is None:
+ branch = self.get_branch()
+ return branch.get_push_location()
+
+ def check_environment(self):
+ """Be sure the test environment doesn't exist."""
+ # We want to be really sure we do not clobber an existing LXC
+ # container, therefore we make sure one doesn't exist before
+ # proceeding.
+ super(LXCIntegrationTest, self).check_environment()
+ cmd = 'sudo lxc-info -n {}'.format(LXC_NAME)
+ results = run(*cmd.split())
+ if results.split()[1] == 'RUNNING':
+ # The container should not be active.
+ raise RuntimeError(
+ "An LXC container named '{}' is unexpectedly "
+ "running.".format(LXC_NAME))
+ # Ensure the local branch has been pushed.
+ # For some reason 'bzr missing' cannot use a 'lp:' URL. http or
+ # bzr+ssh URLs work.
+ self.branch = self.get_branch()
+ self.push_location = self.get_push_location(self.branch)
+ if self.push_location.startswith('lp:'):
+ raise RuntimeError(
+ "Push location must use http or bzr+ssh "
+ "protocol: {}".format(self.push_location))
+ # Ensure the branch has been pushed and has no missing revisions.
+ try:
+ push_branch = self.get_branch(self.push_location)
+ except NotBranchError:
+ raise RuntimeError(
+ 'The branch has never been pushed to Launchpad.')
+ tree, _ = WorkingTree.open_containing_paths(None)
+ stream = StringIO()
+ show_tree_status(tree, to_file=stream)
+ if stream.getvalue():
+ raise RuntimeError(
+ 'The tree has uncommitted changes. Check them in '
+ 'and push to Launchpad.')
+ near, far = find_unmerged(self.branch, push_branch)
+ if near or far:
+ raise RuntimeError('The local branch and the pushed version '
+ 'have diverged.')
+
+ def set_up(self):
+ """Set up the LXC container environment."""
+ super(LXCIntegrationTest, self).set_up()
+ cmd = 'sudo python setup.py install'
+ check_call(cmd.split())
+
+ def do_test(self):
+ """Run an end-to-end integration tests of the non-LXC lpsetup story."""
+ super(LXCIntegrationTest, self).do_test()
+ cmd = 'lp-setup install-lxc -B {} -r {} {}'.format(
+ self.push_location, self.repo, LXC_NAME)
+ check_call(cmd.split())
+
+ def tear_down(self):
+ super(LXCIntegrationTest, self).tear_down()
+
+ def lxc_cmd(cmd_name):
+ cmd = 'sudo {} -n {}'.format(cmd_name, LXC_NAME)
+ check_call(cmd.split())
+
+ try:
+ lxc_cmd('lxc-stop')
+ lxc_cmd('lxc-destroy')
+ except:
+ pass
+
+
+if __name__ == '__main__':
+ sys.exit(LXCIntegrationTest().run())
=== modified file 'lpsetup/tests/integration/non-lxc.py'
--- lpsetup/tests/integration/non-lxc.py 2012-07-10 19:58:56 +0000
+++ lpsetup/tests/integration/non-lxc.py 2012-07-19 18:30:30 +0000
@@ -14,96 +14,79 @@
PIPE,
)
-
-def banner(s):
- width = 70
- print '*' * width
- print '* ' + s.ljust(width - 4) + ' *'
- print '*' * width
-
-
-def on_remote(args):
- if type(args) == str:
- args = args.split()
-
- check_call('juju ssh 1 -o StrictHostKeyChecking=no'
- ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'.split()
- + list(args))
-
-
-def check_environment():
- """Be sure the test environment doesn't exist."""
- banner('Checking test environment.')
- # We want to be really sure we do not clobber an already-existing juju
- # environment. Therefore we make sure one doesn't exist before
- # bootstrapping.
- code = os.system('juju status -e lpsetup-testing')
- if code == 0:
- # The "juju status" should have failed.
- raise RuntimeError('A juju environment unexpectedly exists.')
-
-
-def set_up():
- """Set up a juju-managed instance to run the tests on."""
- banner('Setting up the test environment.')
- check_call('juju bootstrap -e lpsetup-testing'.split())
- # XXX The "ubuntu" charm is broken, so it has to be loaded from the local
- # repository. Get it from lp:~charmers/charms/precise/ubuntu/trunk.
- check_call('juju deploy local:ubuntu --repository ~/juju-charms'
- ' -e lpsetup-testing --constraints instance-type=m1.large'.split())
-
- start_time = time.time()
- while time.time() - start_time < 600:
- process = Popen('juju status -e lpsetup-testing'.split(), stdout=PIPE)
- stdout, stderr = process.communicate()
- if 'instance-state: running' in stdout:
- break
- else:
- raise RuntimeError('starting the instance took too long')
-
- # Even though the instance-state is "running", it's still not ready, so
- # wait a little while before continuing.
- time.sleep(30)
-
- on_remote('sudo apt-add-repository --yes ppa:yellow/ppa')
- on_remote('sudo apt-get update')
- on_remote('sudo apt-get install python-shelltoolbox')
- check_call('juju scp -o StrictHostKeyChecking=no'
- ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'
- ' -r . 1:lpsetup'.split())
-
-
-def do_test():
- """Run an end-to-end integration tests of the non-LXC lpsetup story."""
- banner('Running (non-LXC) integration test.')
- # Since the most common scenario is to have bzr whoami setup, we do that
- # instead of providing the arguments directly to lpsetup.
- on_remote(('bzr', 'whoami', '"Not A Real Person <no@xxxxxxxxxxx>"'))
- on_remote('cd lpsetup; ./lp-setup init-host'.split())
-
-
-def tear_down():
- banner('Cleaning up.')
- code = os.system('echo y | juju destroy-environment -e lpsetup-testing')
- if code != 0:
- raise RuntimeError('Destroying the test juju environment failed.')
-
-
-def main():
- check_environment()
- try:
- set_up()
- try:
- do_test()
- except:
- banner('Test failed. Sorry.')
- return 1
+from common import IntegrationTestBase
+
+
+class NonLXCIntegrationTest(IntegrationTestBase):
+
+ test_type = 'non-LXC target'
+
+ def on_remote(self, args):
+ if type(args) == str:
+ args = args.split()
+
+ check_call('juju ssh 1 -o StrictHostKeyChecking=no'
+ ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'.split()
+ + list(args))
+
+ def check_environment(self):
+ """Be sure the test environment doesn't exist."""
+ # We want to be really sure we do not clobber an already-existing juju
+ # environment. Therefore we make sure one doesn't exist before
+ # bootstrapping.
+ super(NonLXCIntegrationTest, self).check_environment()
+ code = os.system('juju status -e lpsetup-testing')
+ if code == 0:
+ # The "juju status" should have failed.
+ raise RuntimeError('A juju environment unexpectedly exists.')
+
+ def set_up(self):
+ """Set up a juju-managed instance to run the tests on."""
+ super(NonLXCIntegrationTest, self).set_up()
+ check_call('juju bootstrap -e lpsetup-testing'.split())
+ # XXX The "ubuntu" charm is broken, so it has to be loaded from the
+ # local repository. Get it from
+ # lp:~charmers/charms/precise/ubuntu/trunk.
+ check_call('juju deploy local:ubuntu --repository ~/juju-charms'
+ ' -e lpsetup-testing --constraints instance-type=m1.large'.split())
+
+ start_time = time.time()
+ while time.time() - start_time < 600:
+ process = Popen(
+ 'juju status -e lpsetup-testing'.split(), stdout=PIPE)
+ stdout, stderr = process.communicate()
+ if 'instance-state: running' in stdout:
+ break
else:
- banner('Test succeeded.')
- return 0
- finally:
- tear_down()
+ raise RuntimeError('starting the instance took too long')
+
+ # Even though the instance-state is "running", it's still not ready, so
+ # wait a little while before continuing.
+ time.sleep(30)
+
+ self.on_remote('sudo apt-add-repository --yes ppa:yellow/ppa')
+ self.on_remote('sudo apt-get update')
+ self.on_remote('sudo apt-get install python-shelltoolbox')
+ check_call('juju scp -o StrictHostKeyChecking=no'
+ ' -o UserKnownHostsFile=/dev/null -e lpsetup-testing'
+ ' -r . 1:lpsetup'.split())
+
+ def do_test(self):
+ """Run an end-to-end integration tests of the non-LXC lpsetup story."""
+ # Since the most common scenario is to have bzr whoami setup, we do
+ # that instead of providing the arguments directly to lpsetup.
+ super(NonLXCIntegrationTest, self).do_test()
+ self.on_remote(
+ ('bzr', 'whoami', '"Not A Real Person <no@xxxxxxxxxxx>"'))
+ self.on_remote('cd lpsetup; ./lp-setup init-host'.split())
+
+ def tear_down(self):
+ super(NonLXCIntegrationTest, self).tear_down()
+ code = os.system(
+ 'echo y | juju destroy-environment -e lpsetup-testing')
+ if code != 0:
+ raise RuntimeError('Destroying the test juju environment failed.')
if __name__ == '__main__':
- sys.exit(main())
+ sys.exit(NonLXCIntegrationTest().run())
=== modified file 'lpsetup/tests/subcommands/test_finish_inithost.py'
--- lpsetup/tests/subcommands/test_finish_inithost.py 2012-07-12 18:23:37 +0000
+++ lpsetup/tests/subcommands/test_finish_inithost.py 2012-07-19 18:30:30 +0000
@@ -19,9 +19,10 @@
def get_arguments():
- code_dir = '~/' + get_random_string()
+ repo = '~/' + get_random_string()
+ checkout = get_random_string()
user = get_random_string()
- return ('-c', code_dir, '-u', user)
+ return ('-r', repo, '--checkout-name', checkout, '-u', user)
class FinishInitHostTest(StepsBasedSubCommandTestMixin, unittest.TestCase):
@@ -31,6 +32,7 @@
expected_handlers = (
handlers.handle_user,
handlers.handle_directories,
+ handlers.handle_code_dir,
)
@property
=== modified file 'lpsetup/tests/subcommands/test_install_lxc.py'
--- lpsetup/tests/subcommands/test_install_lxc.py 2012-07-12 22:12:09 +0000
+++ lpsetup/tests/subcommands/test_install_lxc.py 2012-07-19 18:30:30 +0000
@@ -34,7 +34,8 @@
finish_inithost_in_lxc_step = (
install_lxc.finish_inithost_in_lxc, [
- 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'code_dir',
+ 'lxc_name', 'ssh_key_path', 'home_dir', 'user', 'repository',
+ 'checkout_name',
])
@@ -52,6 +53,7 @@
expected_arguments = get_arguments()
expected_handlers = test_initlxc.InitLxcTest.expected_handlers + (
handlers.handle_directories,
+ handlers.handle_code_dir,
handlers.handle_source,
)
expected_steps = test_initlxc.InitLxcTest.expected_steps + (
=== modified file 'lpsetup/tests/subcommands/test_update.py'
--- lpsetup/tests/subcommands/test_update.py 2012-07-13 15:55:40 +0000
+++ lpsetup/tests/subcommands/test_update.py 2012-07-19 18:30:30 +0000
@@ -18,15 +18,15 @@
return (
'--external-path', get_random_string(),
'--use-http',
- '-e', '../devel',
- '-W', '~/' + get_random_string(),
+ '--repository', get_random_string(),
+ '--checkout-name', get_random_string(),
)
init_dir_step = (
- update.initialize_directories, ['working_dir', 'external_path'])
+ update.initialize_directories, ['code_dir', 'external_path'])
update_dep_step = (
- update.update_dependencies, ['working_dir', 'external_path', 'use_http'])
-update_tree_step = (update.update_tree, ['working_dir'])
+ update.update_dependencies, ['code_dir', 'external_path', 'use_http'])
+update_tree_step = (update.update_tree, ['code_dir'])
class UpdateTest(StepsBasedSubCommandTestMixin, unittest.TestCase):
@@ -35,7 +35,9 @@
sub_command_class = update.SubCommand
expected_arguments = get_arguments()
expected_handlers = (
- handlers.handle_working_dir,
+ handlers.handle_user,
+ handlers.handle_directories,
+ handlers.handle_code_dir,
)
expected_steps = (
init_dir_step,
=== modified file 'pre-commit.sh'
--- pre-commit.sh 2012-07-11 15:50:01 +0000
+++ pre-commit.sh 2012-07-19 18:30:30 +0000
@@ -1,4 +1,4 @@
#!/bin/bash
-pyfiles=`find . -name "*.py" | grep -v distribute_setup.py`
-pocketlint $pyfiles && pep8 $pyfiles && nosetests
+pyfiles=`find . -name build -prune -o -name "*.py" | grep -v distribute_setup.py`
+pocketlint $pyfiles && pep8 --exclude=build $pyfiles && nosetests
Follow ups