[beisner,r=james-page] auto normalize amulet test definitions and amulet make targets; charm-helper sync.

This commit is contained in:
james.page@ubuntu.com 2015-04-17 16:03:30 +01:00
commit cf7719934a
16 changed files with 125 additions and 15 deletions

View File

@ -1 +1 @@
}q(U collectorqUcoverage v3.7.1qUlinesq}qUF/home/jamespage/src/charms/next-resync/ceph-osd/unit_tests/__init__.pyq]qKasu.
}q(U collectorqUcoverage v3.7.1qUlinesq}q(UF/home/jamespage/src/charms/next-resync/ceph-osd/unit_tests/__init__.pyq]qKaUQ/home/jamespage/src/charms/landing-beisner-resync/ceph-osd/unit_tests/__init__.pyq]q Kauu.

View File

@ -14,8 +14,7 @@ test:
# coreycb note: The -v should only be temporary until Amulet sends
# raise_status() messages to stderr:
# https://bugs.launchpad.net/amulet/+bug/1320357
@juju test -v -p AMULET_HTTP_PROXY --timeout 900 \
00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse
@juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700
bin/charm_helpers_sync.py:
@mkdir -p bin

View File

@ -20,11 +20,13 @@
# Authors:
# Charm Helpers Developers <juju@lists.ubuntu.com>
from __future__ import print_function
import os
import json
import yaml
import subprocess
import sys
import errno
from subprocess import CalledProcessError
import six
@ -87,7 +89,18 @@ def log(message, level=None):
if not isinstance(message, six.string_types):
message = repr(message)
command += [message]
subprocess.call(command)
# Missing juju-log should not cause failures in unit tests
# Send log output to stderr
try:
subprocess.call(command)
except OSError as e:
if e.errno == errno.ENOENT:
if level:
message = "{}: {}".format(level, message)
message = "juju-log: {}".format(message)
print(message, file=sys.stderr)
else:
raise
class Serializable(UserDict):
@ -566,3 +579,29 @@ class Hooks(object):
def charm_dir():
"""Return the root directory of the current charm"""
return os.environ.get('CHARM_DIR')
@cached
def action_get(key=None):
"""Gets the value of an action parameter, or all key/value param pairs"""
cmd = ['action-get']
if key is not None:
cmd.append(key)
cmd.append('--format=json')
action_data = json.loads(subprocess.check_output(cmd).decode('UTF-8'))
return action_data
def action_set(values):
"""Sets the values to be returned after the action finishes"""
cmd = ['action-set']
for k, v in list(values.items()):
cmd.append('{}={}'.format(k, v))
subprocess.check_call(cmd)
def action_fail(message):
"""Sets the action status to failed and sets the error message.
The results set by action_set are preserved."""
subprocess.check_call(['action-fail', message])

View File

@ -339,12 +339,16 @@ def lsb_release():
def pwgen(length=None):
"""Generate a random pasword."""
if length is None:
# A random length is ok to use a weak PRNG
length = random.choice(range(35, 45))
alphanumeric_chars = [
l for l in (string.ascii_letters + string.digits)
if l not in 'l0QD1vAEIOUaeiou']
# Use a crypto-friendly PRNG (e.g. /dev/urandom) for making the
# actual password
random_generator = random.SystemRandom()
random_chars = [
random.choice(alphanumeric_chars) for _ in range(length)]
random_generator.choice(alphanumeric_chars) for _ in range(length)]
return(''.join(random_chars))

View File

@ -139,7 +139,7 @@ class MysqlRelation(RelationContext):
def __init__(self, *args, **kwargs):
self.required_keys = ['host', 'user', 'password', 'database']
super(HttpRelation).__init__(self, *args, **kwargs)
RelationContext.__init__(self, *args, **kwargs)
class HttpRelation(RelationContext):
@ -154,7 +154,7 @@ class HttpRelation(RelationContext):
def __init__(self, *args, **kwargs):
self.required_keys = ['host', 'port']
super(HttpRelation).__init__(self, *args, **kwargs)
RelationContext.__init__(self, *args, **kwargs)
def provide_data(self):
return {

View File

@ -33,9 +33,9 @@ def bool_from_string(value):
value = value.strip().lower()
if value in ['y', 'yes', 'true', 't']:
if value in ['y', 'yes', 'true', 't', 'on']:
return True
elif value in ['n', 'no', 'false', 'f']:
elif value in ['n', 'no', 'false', 'f', 'off']:
return False
msg = "Unable to interpret string value '%s' as boolean" % (value)

View File

@ -443,7 +443,7 @@ class HookData(object):
data = hookenv.execution_environment()
self.conf = conf_delta = self.kv.delta(data['conf'], 'config')
self.rels = rels_delta = self.kv.delta(data['rels'], 'rels')
self.kv.set('env', data['env'])
self.kv.set('env', dict(data['env']))
self.kv.set('unit', data['unit'])
self.kv.set('relid', data.get('relid'))
return conf_delta, rels_delta

11
tests/016-basic-trusty-juno Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/python
"""Amulet tests on a basic ceph-osd deployment on trusty-juno."""
from basic_deployment import CephOsdBasicDeployment
if __name__ == '__main__':
deployment = CephOsdBasicDeployment(series='trusty',
openstack='cloud:trusty-juno',
source='cloud:trusty-updates/juno')
deployment.run_tests()

View File

@ -0,0 +1,11 @@
#!/usr/bin/python
"""Amulet tests on a basic ceph-osd deployment on trusty-kilo."""
from basic_deployment import CephOsdBasicDeployment
if __name__ == '__main__':
deployment = CephOsdBasicDeployment(series='trusty',
openstack='cloud:trusty-kilo',
source='cloud:trusty-updates/kilo')
deployment.run_tests()

9
tests/018-basic-utopic-juno Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic ceph-osd deployment on utopic-juno."""
from basic_deployment import CephOsdBasicDeployment
if __name__ == '__main__':
deployment = CephOsdBasicDeployment(series='utopic')
deployment.run_tests()

View File

@ -0,0 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic ceph-osd deployment on vivid-kilo."""
from basic_deployment import CephOsdBasicDeployment
if __name__ == '__main__':
deployment = CephOsdBasicDeployment(series='vivid')
deployment.run_tests()

View File

@ -11,7 +11,7 @@ from charmhelpers.contrib.openstack.amulet.utils import ( # noqa
)
# Use DEBUG to turn on debug logging
u = OpenStackAmuletUtils(ERROR)
u = OpenStackAmuletUtils(DEBUG)
class CephOsdBasicDeployment(OpenStackAmuletDeployment):

View File

@ -118,6 +118,9 @@ class AmuletUtils(object):
longs, or can be a function that evaluate a variable and returns a
bool.
"""
self.log.debug('actual: {}'.format(repr(actual)))
self.log.debug('expected: {}'.format(repr(expected)))
for k, v in six.iteritems(expected):
if k in actual:
if (isinstance(v, six.string_types) or
@ -134,7 +137,6 @@ class AmuletUtils(object):
def validate_relation_data(self, sentry_unit, relation, expected):
"""Validate actual relation data based on expected relation data."""
actual = sentry_unit.relation(relation[0], relation[1])
self.log.debug('actual: {}'.format(repr(actual)))
return self._validate_dict_data(expected, actual)
def _validate_list_data(self, expected, actual):

View File

@ -15,6 +15,7 @@
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
import six
from collections import OrderedDict
from charmhelpers.contrib.amulet.deployment import (
AmuletDeployment
)
@ -43,7 +44,7 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Determine if the local branch being tested is derived from its
stable or next (dev) branch, and based on this, use the corresonding
stable or next branches for the other_services."""
base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
base_charms = ['mysql', 'mongodb']
if self.stable:
for svc in other_services:
@ -100,12 +101,37 @@ class OpenStackAmuletDeployment(AmuletDeployment):
"""
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
self.precise_havana, self.precise_icehouse,
self.trusty_icehouse) = range(6)
self.trusty_icehouse, self.trusty_juno, self.trusty_kilo,
self.utopic_juno, self.vivid_kilo) = range(10)
releases = {
('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom,
('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
('precise', 'cloud:precise-havana'): self.precise_havana,
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse}
('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo}
return releases[(self.series, self.openstack)]
def _get_openstack_release_string(self):
"""Get openstack release string.
Return a string representing the openstack release.
"""
releases = OrderedDict([
('precise', 'essex'),
('quantal', 'folsom'),
('raring', 'grizzly'),
('saucy', 'havana'),
('trusty', 'icehouse'),
('utopic', 'juno'),
('vivid', 'kilo'),
])
if self.openstack:
os_origin = self.openstack.split(':')[1]
return os_origin.split('%s-' % self.series)[1].split('/')[0]
else:
return releases[self.series]