summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam <adam.coldrick@codethink.co.uk>2014-11-26 13:25:22 +0000
committerAdam Coldrick <adam.coldrick@codethink.co.uk>2014-12-09 14:02:00 +0000
commit2fa8d0a172b97529768413c0f774536a21d9d57c (patch)
tree5b68cbe8ea2588516e7f34ffda39a8d37e2b215a
parent252e02463263f128ba1b64d151765580563e625d (diff)
downloadsystem-tests-2fa8d0a172b97529768413c0f774536a21d9d57c.tar.gz
Add initial test plugins
-rw-r--r--mason/__init__.py2
-rw-r--r--mason/tests/__init__.py8
-rw-r--r--mason/tests/artifact_upload.py118
-rw-r--r--mason/tests/build.py115
-rw-r--r--mason/tests/build_test.py148
5 files changed, 391 insertions, 0 deletions
diff --git a/mason/__init__.py b/mason/__init__.py
new file mode 100644
index 0000000..237344b
--- /dev/null
+++ b/mason/__init__.py
@@ -0,0 +1,2 @@
+import tests
+import util
diff --git a/mason/tests/__init__.py b/mason/tests/__init__.py
new file mode 100644
index 0000000..b5b98a6
--- /dev/null
+++ b/mason/tests/__init__.py
@@ -0,0 +1,8 @@
+# builds the systems in `cluster-morphology`
+import build
+
+# uploads build-artifacts to the cache on upstream-trove
+import artifact_upload
+
+# test plugins
+import build_test
diff --git a/mason/tests/artifact_upload.py b/mason/tests/artifact_upload.py
new file mode 100644
index 0000000..21d1093
--- /dev/null
+++ b/mason/tests/artifact_upload.py
@@ -0,0 +1,118 @@
+# Copyright 2014 Codethink Ltd
+
+import cliapp
+import json
+import logging
+import os
+import urlparse
+
+from turbo_hipster.lib import common
+from turbo_hipster.lib import models
+
+
+#TODO: Less different instances of this would be nice
+class MorphologyHelper(object):
+
+ def __init__(self, path):
+ self.defs_repo = morphlib.gitdir.GitDirectory(path)
+ self.loader = morphlib.morphloader.MorphologyLoader()
+ self.finder = morphlib.morphologyfinder.MorphologyFinder(self.defs_repo)
+
+ def load_morphology(self, path):
+ text = self.finder.read_morphology(path)
+ return self.loader.load_from_string(text)
+
+ @classmethod
+ def iterate_systems(cls, systems_list):
+ for system in systems_list:
+ yield morphlib.util.sanitise_morphology_path(system['morph'])
+ if 'subsystems' in system:
+ for subsystem in cls.iterate_systems(system['subsystems']):
+ yield subsystem
+
+ def iterate_cluster_deployments(cls, cluster_morph):
+ for system in cluster_morph['systems']:
+ path = morphlib.util.sanitise_morphology_path(system['morph'])
+ defaults = system.get('deploy-defaults', {})
+ for name, options in system['deploy'].iteritems():
+ config = dict(defaults)
+ config.update(options)
+ yield path, name, config
+
+ def load_cluster_systems(self, cluster_morph):
+ for system_path in set(self.iterate_systems(cluster_morph['systems'])):
+ system_morph = self.load_morphology(system_path)
+ yield system_path, system_morph
+
+
+#TODO: Deployment
+
+
+class Runner(models.Task):
+
+ """This thread handles running the build-deploy-build test,
+ which is used to ensure that Baserock can build Baserock."""
+
+ log = logging.getLogger("task_plugins.build_deploy_test.task.Runner")
+
+ def __init__(self, worker_server, plugin_config, job_name):
+ super(Runner, self).__init__(worker_server, plugin_config, job_name)
+
+ self.total_steps = 5
+ print self.job_arguments
+
+ def do_job_steps(self):
+ self.log.info('Step 1: Creating a workspace')
+ self._create_workspace()
+
+ self.log.info('Step 2: Deploy and test the systems')
+ self._deploy_and_test_systems()
+
+ self.log.info('Step 3: Clean up')
+ self._clean_up()
+
+ def _do_git_config(self):
+ cliapp.runcmd(['git', 'config', 'user.name', 'Mason Test Runner'])
+ cliapp.runcmd(['git', 'config', 'user.email', 'mason@test.runner'])
+
+ @common.task_step
+ def _create_workspace(self):
+ self.commit = self.job_arguments['ZUUL_COMMIT']
+ self.project = self.job_arguments['ZUUL_PROJECT']
+ self.ref = self.job_arguments['ZUUL_REF']
+ self.workspace = '/root/mason-workspace'
+ self.zuul_url = self.job_arguments['ZUUL_URL']
+
+ url = urlparse.urlparse(self.zuul_url)
+ self.defs_checkout = os.path.join(self.workspace,
+ self.commit,
+ url.hostname,
+ '8080',
+ self.project)
+
+ self._do_git_config()
+ cliapp.runcmd(['morph', 'init', self.workspace])
+
+ repo = 'http://%s:8080/%s' % (url.hostname, self.project)
+ cliapp.runcmd(['morph', 'checkout', repo, self.commit], cwd=self.workspace)
+
+ @common.task_step
+ def _test_systems(self):
+ infrastructure = \
+ self.plugin_config['config']['test-infrastructure-type']
+ cmd = ['scripts/release-test']
+ args = ['--deployment-host',
+ self.plugin_config['config']['deployment-host'],
+ '--trove-host', self.plugin_config['config']['trove-host'],
+ '--trove-id', self.plugin_config['config']['trove-id'],
+ '--test-ref', self.commit
+ ]
+ if infrastructure == 'openstack':
+ cmd = ['/usr/lib/mason/mason-test-os']
+ args += ['--net-id',
+ self.plugin_config['config']['openstack-network-id']]
+ args += [self.plugin_config['config']['cluster-morphology']]
+
+ @common.task_step
+ def _clean_up(self):
+ cliapp.runcmd(['rm', '-rf', self.workspace])
diff --git a/mason/tests/build.py b/mason/tests/build.py
new file mode 100644
index 0000000..d347eb9
--- /dev/null
+++ b/mason/tests/build.py
@@ -0,0 +1,115 @@
+# Copyright 2014 Codethink Ltd
+
+import cliapp
+import json
+import logging
+import morphlib
+import os
+import urlparse
+
+import mason
+
+
+class Build(object):
+
+ """A single build instance."""
+
+ def __init__(self, name, controller):
+ self.system_name = name
+ self.controller = controller
+ self.command = [
+ 'morph', 'build', self.system_name]
+
+ def start(self):
+ self.process = subprocess.Popen(self.command)
+
+ def completed(self):
+ return (self.process.poll() is not None)
+
+
+class Runner(mason.util.JobRunner):
+
+ """This thread handles running the build-deploy-build test,
+ which is used to ensure that Baserock can build Baserock."""
+
+ log = logging.getLogger("mason.tests.build.Runner")
+
+ def __init__(self, worker_server, plugin_config, job_name):
+ super(Runner, self).__init__(worker_server, plugin_config, job_name)
+
+ self.total_steps = 3
+
+ def do_job_steps(self):
+ self.log.info('Step 1: Creating a workspace')
+ self._create_workspace()
+
+ self.log.info('Step 2: Building the systems')
+ self._build_systems()
+
+ #TODO: provide logs
+ self.log.info('Step 3: Clean up')
+ self._clean_up()
+
+ def _do_git_config(self):
+ cliapp.runcmd(['git', 'config', 'user.name', 'Mason Test Runner'])
+ cliapp.runcmd(['git', 'config', 'user.email', 'mason@test.runner'])
+
+ def _parse_controllers(self, conf):
+ controllers = {}
+ for arch, addr in (item.split(':') for item in conf['controllers']):
+ controllers[arch] = addr
+ return controllers
+
+ def _prepare_builds(self, conf):
+ cluster = self.morph_helper.load_morphology(conf['cluster-morphology'])
+ systems = set(self.morph_helper.iterate_systems(cluster['systems']))
+ controllers = self._parse_controllers(conf)
+ builds = []
+ for system_name in systems:
+ system = self.morph_helper.load_morphology(system_name)
+ if system['arch'] in controllers:
+ builds.append(Build(system_name, controllers['arch']))
+ return builds
+
+ def _create_workspace(self):
+ self.commit = self.job_arguments['ZUUL_COMMIT']
+ self.project = self.job_arguments['ZUUL_PROJECT']
+ self.ref = self.job_arguments['ZUUL_REF']
+ self.workspace = '/root/mason-workspace'
+ self.zuul_url = self.job_arguments['ZUUL_URL']
+
+ url = urlparse.urlparse(self.zuul_url)
+ self.defs_checkout = os.path.join(self.workspace,
+ self.commit,
+ url.hostname,
+ '8080',
+ self.project)
+ self.morph_helper = mason.util.MorphologyHelper(self.defs_checkout)
+
+ self._do_git_config()
+ cliapp.runcmd(['morph', 'init', self.workspace])
+
+ repo = 'http://%s:8080/%s' % (url.hostname, self.project)
+ cliapp.runcmd(['morph', 'checkout', repo, self.commit],
+ cwd=self.workspace)
+
+ def _build_systems(self):
+ builds = self._prepare_builds(self.plugin_config['config'])
+ os.chdir(self.defs_checkout)
+ for build in builds:
+ build.start()
+
+ while not all(build.completed() for build in builds):
+ time.sleep(1)
+
+ fail = False
+ for build in builds:
+ if build.process.returncode != 0:
+ fail = True
+ sys.stderr.write(
+ 'Building failed for %s\n' % build.system_name)
+ if fail:
+ raise cliapp.AppException('Building of systems failed.')
+
+ def _clean_up(self):
+ cliapp.runcmd(['rm', '-rf', self.workspace])
diff --git a/mason/tests/build_test.py b/mason/tests/build_test.py
new file mode 100644
index 0000000..11cc30e
--- /dev/null
+++ b/mason/tests/build_test.py
@@ -0,0 +1,148 @@
+# Copyright 2014 Codethink Ltd
+
+import cliapp
+import json
+import logging
+import os
+import urlparse
+
+import mason
+
+
+class Runner(mason.util.JobRunner):
+
+ """This thread handles running the build test, which is used to ensure
+ that Baserock can build Baserock."""
+
+ log = logging.getLogger("mason.tests.build_test.Runner")
+
+ def __init__(self, worker_server, plugin_config, job_name):
+ super(Runner, self).__init__(worker_server, plugin_config, job_name)
+
+ self.total_steps = 3
+
+ def do_job_steps(self):
+ self.log.info('Step 1: Creating a workspace')
+ self._create_workspace()
+
+ self.log.info('Step 2: Deploy and test the systems')
+ self._deploy_and_test_systems()
+
+ self.log.info('Step 3: Clean up')
+ self._clean_up()
+
+ def _do_git_config(self):
+ cliapp.runcmd(['git', 'config', 'user.name', 'Mason Test Runner'])
+ cliapp.runcmd(['git', 'config', 'user.email', 'mason@test.runner'])
+
+ @staticmethod
+ def _run_tests(instance, system_path, system_morph,
+ (trove_host, trove_id, build_ref_prefix),
+ systems):
+ instance.wait_until_online()
+
+ tests = []
+ def baserock_build_test(instance):
+ instance.runcmd(['git', 'config', '--global', 'user.name',
+ 'Test Instance of %s' % instance.deployment.name])
+ instance.runcmd(['git', 'config', '--global', 'user.email',
+ 'ci-test@%s' % instance.config['HOSTNAME']])
+ instance.runcmd(['mkdir', '-p', '/src/ws', '/src/cache',
+ '/src/tmp'])
+ def morph_cmd(*args, **kwargs):
+ # TODO: decide whether to use cached artifacts or not by
+ # adding --artifact-cache-server= --cache-server=
+ argv = ['morph', '--log=/src/morph.log', '--cachedir=/src/cache',
+ '--tempdir=/src/tmp', '--log-max=100M',
+ '--trove-host', trove_host, '--trove-id', trove_id,
+ '--build-ref-prefix', build_ref_prefix]
+ argv.extend(args)
+ instance.runcmd(argv, **kwargs)
+
+ repo = self.morph_helper.sb.root_repository_url
+ ref = self.morph_helper.defs_repo.HEAD
+ sha1 = self.morph_helper.defs_repo.resolve_ref_to_commit(ref)
+ morph_cmd('init', '/src/ws')
+ chdir = '/src/ws'
+
+ morph_cmd('checkout', repo, ref, chdir=chdir)
+ # TODO: Add a morph subcommand that gives the path to the root repository.
+ repo_path = os.path.relpath(
+ self.morph_helper.sb.get_git_directory_name(repo),
+ self.morph_helper.sb.root_directory)
+ chdir = os.path.join(chdir, ref, repo_path)
+
+ instance.runcmd(['git', 'reset', '--hard', sha1], chdir=chdir)
+ print 'Building test systems for {sys}'.format(sys=system_path)
+ for to_build_path, to_build_morph in systems.iteritems():
+ if to_build_morph['arch'] == system_morph['arch']:
+ print 'Test building {path}'.format(path=to_build_path)
+ morph_cmd('build', to_build_path, chdir=chdir,
+ stdin=None, stdout=None, stderr=None)
+ print 'Finished Building test systems'
+
+ # TODO: Match the systems with a regex in config?
+ if 'devel' in system_path:
+ tests.append(baserock_build_test)
+
+ for test in tests:
+ test(instance)
+
+ def _create_workspace(self):
+ self.commit = self.job_arguments['ZUUL_COMMIT']
+ self.project = self.job_arguments['ZUUL_PROJECT']
+ self.ref = self.job_arguments['ZUUL_REF']
+ self.workspace = '/root/mason-workspace'
+ self.zuul_url = self.job_arguments['ZUUL_URL']
+
+ url = urlparse.urlparse(self.zuul_url)
+ self.defs_checkout = os.path.join(self.workspace,
+ self.commit,
+ url.hostname,
+ '8080',
+ self.project)
+ self.morph_helper = baserock_tests.MorphologyHelper(
+ self.defs_checkout)
+
+ self._do_git_config()
+ cliapp.runcmd(['morph', 'init', self.workspace])
+
+ repo = 'http://%s:8080/%s' % (url.hostname, self.project)
+ cliapp.runcmd(['morph', 'checkout', repo, self.commit],
+ cwd=self.workspace)
+
+ def _deploy_and_test_systems(self):
+ config = self.plugin_config['config']
+ infrastructure = config['test-infrastructure-type']
+ build_test_config = (config['trove-host'],
+ config['trove-id'],
+ config['build-ref-prefix'])
+ cluster = self.morph_helper.load_morphology(
+ config['cluster-morphology'])
+ systems = dict(morph_helper.load_cluster_systems(cluster))
+
+ for system_path, deployment_name, deployment_config in \
+ self.morph_helper.iterate_cluster_deployments(cluster):
+
+ system = systems[system_path]
+ # We can only test systems in KVM that have a BSP
+ if not any('bsp' in si['morph'] for si in system['strata']):
+ continue
+
+ # We can only test systems in KVM that we have a host for
+ if system['arch'] not in deployment_hosts:
+ continue
+
+ host = deployment_hosts[system['arch']]
+ deployment = mason.util.Deployment(cluster, deployment_name,
+ deployment_config, host)
+
+ instance = deployment.deploy()
+ try:
+ self._run_tests(instance, system_path, system,
+ build_test_config, systems)
+ finally:
+ instance.delete()
+
+ def _clean_up(self):
+ cliapp.runcmd(['rm', '-rf', self.workspace])