Various tests using datafiles are being moved into the integration test framework (tests_new right now).

The unit test infrastructure will remain for things that are mocked out and testable with out filesystem
side effects, and a few cases of things that might not be quite so much (like inventory) that can still
benefit from heavy access to the API.

See the 'tests_new/integration' directory, this will soon fold into tests_new.
This commit is contained in:
Michael DeHaan 2014-02-20 16:20:05 -05:00
parent 0581746a80
commit fe7d3773ae
42 changed files with 0 additions and 1607 deletions

View file

@ -1,4 +0,0 @@
---
# could test something different here but want people running tests on
# different OS platforms to still have passing tests
testing: default

View file

@ -1,62 +0,0 @@
# (C) 2013, Michael Scherer, <misc@zarb.org>
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
import os
import unittest
import subprocess
# if you change here, also change in the plugin
FILE_DISABLE = '/tmp/ansible_test_disable'
FILE_RUN = '/tmp/ansible_test_finish'
class TestInventory(unittest.TestCase):
def setUp(self):
self.cwd = os.getcwd()
os.chdir(os.path.join(os.path.dirname(__file__), 'test_callbacks'))
def clean_file(self):
if os.path.exists(FILE_RUN):
os.unlink(FILE_RUN)
if os.path.exists(FILE_DISABLE):
os.unlink(FILE_DISABLE)
def tearDown(self):
os.chdir(self.cwd)
def run_ansible_playbook(self):
subprocess.call(('source ../../hacking/env-setup 2>&1 >/dev/null;'
'ansible-playbook -i "127.0.0.1," test_playbook.yml 2>&1 >/dev/null'),
shell=True, executable='/bin/bash')
def test_callback(self):
self.clean_file()
self.run_ansible_playbook()
assert os.path.exists(FILE_RUN)
self.clean_file()
def test_callback_disabled(self):
self.clean_file()
open(FILE_DISABLE, 'w').close()
self.run_ansible_playbook()
assert not os.path.exists(FILE_RUN)
self.clean_file()

View file

@ -1,443 +0,0 @@
# tests are fairly 'live' (but safe to run)
# setup authorized_keys for logged in user such
# that the user can log in as themselves before running tests
import unittest
import getpass
import ansible.playbook
import ansible.utils as utils
import ansible.callbacks as ans_callbacks
import os
import shutil
import ansible.constants as C
EVENTS = []
class TestCallbacks(object):
# using same callbacks class for both runner and playbook
def __init__(self):
pass
def set_playbook(self, playbook):
self.playbook = playbook
def on_no_hosts_remaining(self):
pass
def on_start(self):
EVENTS.append('start')
def on_skipped(self, host, item=None):
EVENTS.append([ 'skipped', [ host ]])
def on_import_for_host(self, host, filename):
EVENTS.append([ 'import', [ host, filename ]])
def on_error(self, host, msg):
EVENTS.append([ 'stderr', [ host, msg ]])
def on_not_import_for_host(self, host, missing_filename):
pass
def on_notify(self, host, handler):
EVENTS.append([ 'notify', [ host, handler ]])
def on_task_start(self, name, is_conditional):
EVENTS.append([ 'task start', [ name, is_conditional ]])
def on_failed(self, host, results, ignore_errors):
EVENTS.append([ 'failed', [ host, results, ignore_errors ]])
def on_ok(self, host, result):
# delete certain info from host_result to make test comparisons easier
host_result = result.copy()
for k in [ 'ansible_job_id', 'results_file', 'md5sum', 'delta', 'start', 'end' ]:
if k in host_result:
del host_result[k]
for k in host_result.keys():
if k.startswith('facter_') or k.startswith('ohai_'):
del host_result[k]
EVENTS.append([ 'ok', [ host, host_result ]])
def on_play_start(self, pattern):
EVENTS.append([ 'play start', [ pattern ]])
def on_async_ok(self, host, res, jid):
EVENTS.append([ 'async ok', [ host ]])
def on_async_poll(self, host, res, jid, clock):
EVENTS.append([ 'async poll', [ host ]])
def on_async_failed(self, host, res, jid):
EVENTS.append([ 'async failed', [ host ]])
def on_unreachable(self, host, msg):
EVENTS.append([ 'failed/dark', [ host, msg ]])
def on_setup(self):
pass
def on_no_hosts(self):
pass
class TestPlaybook(unittest.TestCase):
def setUp(self):
self.user = getpass.getuser()
self.cwd = os.getcwd()
self.test_dir = os.path.join(self.cwd, 'test')
self.stage_dir = self._prepare_stage_dir()
if os.path.exists('/tmp/ansible_test_data_copy.out'):
os.unlink('/tmp/ansible_test_data_copy.out')
if os.path.exists('/tmp/ansible_test_data_template.out'):
os.unlink('/tmp/ansible_test_data_template.out')
if os.path.exists('/tmp/ansible_test_messages.out'):
os.unlink('/tmp/ansible_test_messages.out')
if os.path.exists('/tmp/ansible_test_role_messages.out'):
os.unlink('/tmp/ansible_test_role_messages.out')
def _prepare_stage_dir(self):
stage_path = os.path.join(self.test_dir, 'test_data')
if os.path.exists(stage_path):
shutil.rmtree(stage_path, ignore_errors=False)
assert not os.path.exists(stage_path)
os.makedirs(stage_path)
assert os.path.exists(stage_path)
return stage_path
def _get_test_file(self, filename):
# get a file inside the test input directory
filename = os.path.join(self.test_dir, filename)
assert os.path.exists(filename)
return filename
def _get_stage_file(self, filename):
# get a file inside the test output directory
filename = os.path.join(self.stage_dir, filename)
return filename
def _run(self, test_playbook, host_list='test/ansible_hosts', extra_vars=None):
''' run a module and get the localhost results '''
# This ensures tests are independent of eachother
global EVENTS
ansible.playbook.SETUP_CACHE.clear()
EVENTS = []
self.test_callbacks = TestCallbacks()
self.playbook = ansible.playbook.PlayBook(
playbook = test_playbook,
host_list = host_list,
module_path = 'library/',
forks = 1,
timeout = 5,
remote_user = self.user,
remote_pass = None,
extra_vars = extra_vars,
stats = ans_callbacks.AggregateStats(),
callbacks = self.test_callbacks,
runner_callbacks = self.test_callbacks
)
result = self.playbook.run()
return result
def test_playbook_vars(self):
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'test_playbook_vars', 'playbook.yml'),
host_list='test/test_playbook_vars/hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
playbook.run()
def _test_playbook_undefined_vars(self, playbook, fail_on_undefined):
# save DEFAULT_UNDEFINED_VAR_BEHAVIOR so we can restore it in the end of the test
saved_undefined_var_behavior = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR
C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = fail_on_undefined
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'test_playbook_undefined_vars', playbook),
host_list='test/test_playbook_undefined_vars/hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
actual = playbook.run()
C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = saved_undefined_var_behavior
# if different, this will output to screen
print "**ACTUAL**"
print utils.jsonify(actual, format=True)
expected = {
"localhost": {
"changed": 0,
"failures": 0,
"ok": int(not fail_on_undefined) + 1,
"skipped": 0,
"unreachable": int(fail_on_undefined)
}
}
print "**EXPECTED**"
print utils.jsonify(expected, format=True)
assert utils.jsonify(expected, format=True) == utils.jsonify(actual, format=True)
#def test_playbook_undefined_vars1_ignore(self):
# self._test_playbook_undefined_vars('playbook1.yml', False)
#def test_playbook_undefined_vars1_fail(self):
# self._test_playbook_undefined_vars('playbook1.yml', True)
#def test_playbook_undefined_vars2_ignore(self):
# self._test_playbook_undefined_vars('playbook2.yml', False)
#def test_playbook_undefined_vars2_fail(self):
# self._test_playbook_undefined_vars('playbook2.yml', True)
def test_yaml_hosts_list(self):
# Make sure playbooks support hosts: [host1, host2]
# TODO: Actually run the play on more than one host
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'hosts_list.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
play = ansible.playbook.Play(playbook, playbook.playbook[0], os.getcwd())
assert play.hosts == ';'.join(('host1', 'host2', 'host3'))
def test_playbook_hash_replace(self):
# save default hash behavior so we can restore it in the end of the test
saved_hash_behavior = C.DEFAULT_HASH_BEHAVIOUR
C.DEFAULT_HASH_BEHAVIOUR = "replace"
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'test_hash_behavior', 'playbook.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
playbook.run()
filename = '/tmp/ansible_test_messages.out'
expected_lines = [
"goodbye: Goodbye World!"
]
self._compare_file_output(filename, expected_lines)
filename = '/tmp/ansible_test_role_messages.out'
expected_lines = [
"inside_a_role: Indeed!"
]
self._compare_file_output(filename, expected_lines)
# restore default hash behavior
C.DEFAULT_HASH_BEHAVIOUR = saved_hash_behavior
def test_playbook_hash_merge(self):
# save default hash behavior so we can restore it in the end of the test
saved_hash_behavior = C.DEFAULT_HASH_BEHAVIOUR
C.DEFAULT_HASH_BEHAVIOUR = "merge"
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'test_hash_behavior', 'playbook.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
playbook.run()
filename = '/tmp/ansible_test_messages.out'
expected_lines = [
"goodbye: Goodbye World!",
"hello: Hello World!"
]
self._compare_file_output(filename, expected_lines)
filename = '/tmp/ansible_test_role_messages.out'
expected_lines = [
"goodbye: Goodbye World!",
"hello: Hello World!",
"inside_a_role: Indeed!"
]
self._compare_file_output(filename, expected_lines)
# restore default hash behavior
C.DEFAULT_HASH_BEHAVIOUR = saved_hash_behavior
def test_playbook_ignore_errors(self):
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'playbook-ignore-errors.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
actual = playbook.run()
# if different, this will output to screen
print "**ACTUAL**"
print utils.jsonify(actual, format=True)
expected = {
"localhost": {
"changed": 1,
"failures": 1,
"ok": 1,
"skipped": 0,
"unreachable": 0
}
}
print "**EXPECTED**"
print utils.jsonify(expected, format=True)
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def test_playbook_changed_when(self):
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'playbook-changed_when.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
actual = playbook.run()
# if different, this will output to screen
print "**ACTUAL**"
print utils.jsonify(actual, format=True)
expected = {
"localhost": {
"changed": 3,
"failures": 0,
"ok": 6,
"skipped": 0,
"unreachable": 0
}
}
print "**EXPECTED**"
print utils.jsonify(expected, format=True)
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def test_playbook_failed_when(self):
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'playbook-failed_when.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks
)
actual = playbook.run()
# if different, this will output to screen
print "**ACTUAL**"
print utils.jsonify(actual, format=True)
expected = {
"localhost": {
"changed": 2,
"failures": 1,
"ok": 2,
"skipped": 0,
"unreachable": 0
}
}
print "**EXPECTED**"
print utils.jsonify(expected, format=True)
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def test_playbook_always_run(self):
test_callbacks = TestCallbacks()
playbook = ansible.playbook.PlayBook(
playbook=os.path.join(self.test_dir, 'playbook-always-run.yml'),
host_list='test/ansible_hosts',
stats=ans_callbacks.AggregateStats(),
callbacks=test_callbacks,
runner_callbacks=test_callbacks,
check=True
)
actual = playbook.run()
# if different, this will output to screen
print "**ACTUAL**"
print utils.jsonify(actual, format=True)
expected = {
"localhost": {
"changed": 4,
"failures": 0,
"ok": 4,
"skipped": 8,
"unreachable": 0
}
}
print "**EXPECTED**"
print utils.jsonify(expected, format=True)
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
#def test_playbook_logging_non_ascii(self):
# pb = 'test/playbook-logging-non-ascii.yml'
# actual = self._run(pb)
#
# expected = {
# "localhost": {
# "changed": 3,
# "failures": 0,
# "ok": 3,
# "skipped": 0,
# "unreachable": 0
# }
# }
#
# assert utils.jsonify(expected, format=True) == utils.jsonify(actual, format=True)
# Disabled for now as there are permissions issues that happen if you are not the owner that created files
# in the archive.
# def test_unarchive(self):
# pb = 'test/playbook-unarchive.yml'
# actual = self._run(pb)
#
# expected = {
# "localhost": {
# "changed": 29,
# "failures": 0,
# "ok": 33,
# "skipped": 12,
# "unreachable": 0
# }
# }
#
# assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
def _compare_file_output(self, filename, expected_lines):
actual_lines = []
with open(filename) as f:
actual_lines = [l.strip() for l in f.readlines()]
actual_lines = sorted(actual_lines)
print "**ACTUAL**"
print actual_lines
print "**EXPECTED**"
print expected_lines
assert actual_lines == expected_lines

View file

@ -1,129 +0,0 @@
# tests are fairly 'live' (but safe to run)
# setup authorized_keys for logged in user such
# that the user can log in as themselves before running tests
import unittest
import getpass
import ansible.runner
import os
import shutil
import time
import tempfile
from nose.plugins.skip import SkipTest
def get_binary(name):
for directory in os.environ["PATH"].split(os.pathsep):
path = os.path.join(directory, name)
if os.path.isfile(path) and os.access(path, os.X_OK):
return path
return None
class TestRunner(unittest.TestCase):
def setUp(self):
self.user = getpass.getuser()
self.runner = ansible.runner.Runner(
basedir='test/',
module_name='ping',
module_path='library/',
module_args='',
remote_user=self.user,
remote_pass=None,
host_list='test/ansible_hosts',
timeout=5,
forks=1,
background=0,
pattern='all',
transport='local',
)
self.cwd = os.getcwd()
self.test_dir = os.path.join(self.cwd, 'test')
self.stage_dir = self._prepare_stage_dir()
def _prepare_stage_dir(self):
stage_path = os.path.join(self.test_dir, 'test_data')
if os.path.exists(stage_path):
shutil.rmtree(stage_path, ignore_errors=False)
assert not os.path.exists(stage_path)
os.makedirs(stage_path)
assert os.path.exists(stage_path)
return stage_path
def _get_test_file(self, filename):
# get a file inside the test input directory
filename = os.path.join(self.test_dir, filename)
assert os.path.exists(filename)
return filename
def _get_stage_file(self, filename):
# get a file inside the test output directory
filename = os.path.join(self.stage_dir, filename)
return filename
def _run(self, module_name, module_args, background=0, check_mode=False):
''' run a module and get the localhost results '''
self.runner.module_name = module_name
args = ' '.join(module_args)
self.runner.module_args = args
self.runner.background = background
self.runner.check = check_mode
results = self.runner.run()
# when using nosetests this will only show up on failure
# which is pretty useful
assert "localhost" in results['contacted']
return results['contacted']['localhost']
def test_action_plugins(self):
result = self._run("uncategorized_plugin", [])
assert result.get("msg") == "uncategorized"
result = self._run("categorized_plugin", [])
assert result.get("msg") == "categorized"
def test_ping(self):
result = self._run('ping', [])
assert "ping" in result
def test_async(self):
# test async launch and job status
# of any particular module
result = self._run('command', [get_binary("sleep"), "3"], background=20)
assert 'ansible_job_id' in result
assert 'started' in result
jid = result['ansible_job_id']
# no real chance of this op taking a while, but whatever
time.sleep(5)
# CLI will abstract this (when polling), but this is how it works internally
result = self._run('async_status', ["jid=%s" % jid])
# TODO: would be nice to have tests for supervisory process
# killing job after X seconds
assert 'finished' in result
assert 'failed' not in result
assert 'rc' in result
assert 'stdout' in result
assert result['ansible_job_id'] == jid
def test_assemble(self):
input = self._get_test_file('assemble.d')
output = self._get_stage_file('sample.out')
result = self._run('assemble', [
"src=%s" % input,
"dest=%s" % output,
])
assert os.path.exists(output)
out = file(output).read()
assert out.find("first") != -1
assert out.find("second") != -1
assert out.find("third") != -1
assert result['changed'] is True
assert 'md5sum' in result
assert 'failed' not in result
result = self._run('assemble', [
"src=%s" % input,
"dest=%s" % output,
])
assert result['changed'] is False

View file

@ -16,94 +16,6 @@ sys.setdefaultencoding("utf8")
class TestUtils(unittest.TestCase):
#####################################
### varReplace function tests
def test_varReplace_var_complex_var(self):
vars = {
'x': '$y',
'y': {
'foo': 'result',
},
}
template = '${x.foo}'
res = template2.template(None, template, vars)
assert res == 'result'
#####################################
### template_ds function tests
def test_template_ds_basic(self):
vars = {
'data': {
'var': [
'foo',
'bar',
'baz',
],
'types': [
'str',
u'unicode',
1,
1L,
1.2,
],
'alphas': '$alphas',
},
'alphas': [
'abc',
'def',
'ghi',
],
}
template = '${data.var}'
res = template2.template(None, template, vars)
assert sorted(res) == sorted(vars['data']['var'])
template = '${data.types}'
res = template2.template(None, template, vars)
assert sorted(res) == sorted(vars['data']['types'])
template = '${data.alphas}'
res = template2.template(None, template, vars)
assert sorted(res) == sorted(vars['alphas'])
template = '${data.nonexisting}'
res = template2.template(None, template, vars)
assert res == template
#####################################
### Template function tests
def test_template_basic(self):
vars = {
'who': 'world',
}
res = template2.template_from_file("test", "template-basic", vars)
assert res == 'hello world'
def test_template_whitespace(self):
vars = {
'who': 'world',
}
res = template2.template_from_file("test", "template-whitespace", vars)
assert res == 'hello world\n'
def test_template_unicode(self):
vars = {
'who': u'wórld',
}
res = template2.template_from_file("test", "template-basic", vars)
assert res == u'hello wórld'
#####################################
### check_conditional tests
@ -204,44 +116,3 @@ class TestUtils(unittest.TestCase):
assert (ansible.utils.parse_kv('a=simple b="with space" c="this=that"') ==
{'a': 'simple', 'b': 'with space', 'c': 'this=that'})
#####################################
### plugins
def test_loaders_expanduser_each_dir(self):
# Test that PluginLoader will call expanduser on each path
# when it splits its "config" argument.
home_dir = os.path.expanduser("~")
if home_dir == "~":
raise SkipTest("your platform doesn't expand ~ in paths")
elif not os.path.isdir(home_dir):
raise SkipTest("~ expands to non-directory %r" % (home_dir,))
elif not os.path.isabs(home_dir):
raise SkipTest("~ expands to non-absolute path %r" % (home_dir,))
# Unfortunately we have to create temporary directories in
# your home directory; the directories have to exist for
# PluginLoader to accept them.
abs_dirs, tilde_dirs = [], []
try:
for _ in range(2):
temp_dir = tempfile.mkdtemp(prefix="ansible", dir=home_dir)
abs_dirs.append(temp_dir)
# Convert mkdtemp's absolute path to one starting with "~".
tilde_dir = os.path.join("~", os.path.relpath(temp_dir,
home_dir))
tilde_dirs.append(tilde_dir)
loader = ansible.utils.plugins.PluginLoader(
"",
"",
os.pathsep.join(tilde_dirs),
"something_under_basedir"
)
loader_paths = loader.print_paths().split(os.pathsep)
for abs_dir in abs_dirs:
assert abs_dir in loader_paths, \
"%r not in %r" % (abs_dir, loader_paths)
finally:
for a_dir in abs_dirs:
try:
os.rmdir(a_dir)
except os.error:
pass

View file

@ -1,90 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)
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
hqsRKcw+Z9k=
=sw5O
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -1,2 +0,0 @@
# This is the first comment.
[somegroup]

View file

@ -1,2 +0,0 @@
# This is the second comment.
localhost

View file

@ -1,4 +0,0 @@
# This is the third comment.
[somegroup:vars]
foo=bar
# 無 可 無 非 常 無

View file

@ -1,42 +0,0 @@
-
hosts: all
gather_facts: no
remote_user: root
vars:
color: brown
tasks:
- name: test 1
cron: name="execution test 1" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
tags:
- cron
- name: test 1-1
cron: name="execution test 1" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
tags:
- cron
- name: test 2-1
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" state=absent
tags:
- cron
- name: test 2-2
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" state=absent
tags:
- cron
- name: test 2-3
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate"
tags:
- cron
- name: test 3-1
cron: name="execution test 3" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
tags:
- cron
- name: test 3-2
cron: name="execution test 3" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate
tags:
- cron

View file

@ -1,2 +0,0 @@
---
testing: default

View file

@ -1,748 +0,0 @@
#!/usr/bin/env python
# Copyright 2013 Google Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# This is a custom functional test script for the Google Compute Engine
# ansible modules. In order to run these tests, you must:
# 1) Create a Google Cloud Platform account and enable the Google
# Compute Engine service and billing
# 2) Download, install, and configure 'gcutil'
# see [https://developers.google.com/compute/docs/gcutil/]
# 3) Convert your GCE Service Account private key from PKCS12 to PEM format
# $ openssl pkcs12 -in pkey.pkcs12 -passin pass:notasecret \
# > -nodes -nocerts | openssl rsa -out pkey.pem
# 4) Make sure you have libcloud 0.13.3 or later installed.
# 5) Make sure you have a libcloud 'secrets.py' file in your PYTHONPATH
# 6) Set GCE_PARAMS and GCE_KEYWORD_PARMS in your 'secrets.py' file.
# 7) Set up a simple hosts file
# $ echo 127.0.0.1 > ~/ansible_hosts
# $ echo "export ANSIBLE_HOSTS='~/ansible_hosts'" >> ~/.bashrc
# $ . ~/.bashrc
# 8) Set up your ansible 'hacking' environment
# $ cd ~/ansible
# $ . hacking/env-setup
# $ export ANSIBLE_HOST_KEY_CHECKING=no
# $ ansible all -m ping
# 9) Set your PROJECT variable below
# 10) Run and time the tests and log output, take ~30 minutes to run
# $ time stdbuf -oL python test/gce_tests.py 2>&1 | tee log
#
# Last update: gcutil-1.11.0 and v1beta16
# Set this to your test Project ID
PROJECT="google.com:erjohnso"
# debugging
DEBUG=False # lots of debugging output
VERBOSE=True # on failure, display ansible command and expected/actual result
# location - note that some tests rely on the module's 'default'
# region/zone, which should match the settings below.
REGION="us-central1"
ZONE="%s-a" % REGION
# Peeking is a way to trigger looking at a specified set of resources
# before and/or after a test run. The 'test_cases' data structure below
# has a few tests with 'peek_before' and 'peek_after'. When those keys
# are set and PEEKING_ENABLED is True, then these steps will be executed
# to aid in debugging tests. Normally, this is not needed.
PEEKING_ENABLED=False
# disks
DNAME="aaaaa-ansible-disk"
DNAME2="aaaaa-ansible-disk2"
DNAME6="aaaaa-ansible-inst6"
DNAME7="aaaaa-ansible-inst7"
USE_PD="true"
KERNEL="https://www.googleapis.com/compute/v1beta16/projects/google/global/kernels/gce-no-conn-track-v20130813"
# instances
INAME="aaaaa-ansible-inst"
INAME2="aaaaa-ansible-inst2"
INAME3="aaaaa-ansible-inst3"
INAME4="aaaaa-ansible-inst4"
INAME5="aaaaa-ansible-inst5"
INAME6="aaaaa-ansible-inst6"
INAME7="aaaaa-ansible-inst7"
TYPE="n1-standard-1"
IMAGE="https://www.googleapis.com/compute/v1beta16/projects/debian-cloud/global/images/debian-7-wheezy-v20131014"
NETWORK="default"
SCOPES="https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.full_control"
# networks / firewalls
NETWK1="ansible-network1"
NETWK2="ansible-network2"
NETWK3="ansible-network3"
CIDR1="10.240.16.0/24"
CIDR2="10.240.32.0/24"
CIDR3="10.240.64.0/24"
GW1="10.240.16.1"
GW2="10.240.32.1"
FW1="ansible-fwrule1"
FW2="ansible-fwrule2"
FW3="ansible-fwrule3"
FW4="ansible-fwrule4"
# load-balancer tests
HC1="ansible-hc1"
HC2="ansible-hc2"
HC3="ansible-hc3"
LB1="ansible-lb1"
LB2="ansible-lb2"
from commands import getstatusoutput as run
import sys
test_cases = [
{'id': '01', 'desc': 'Detach / Delete disk tests',
'setup': ['gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME, ZONE)],
'tests': [
{'desc': 'DETACH_ONLY but disk not found [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
},
{'desc': 'DETACH_ONLY but instance not found [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, "missing-instance", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
},
{'desc': 'DETACH_ONLY but neither disk nor instance exists [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", "missing-instance", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DETACH_ONLY but disk is not currently attached [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'DETACH_ONLY disk is attached and should be detached [success]',
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, INAME, DNAME, ZONE),
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
},
{'desc': 'DETACH_ONLY but not instance specified [FAIL]',
'm': 'gce_pd',
'a': 'name=%s zone=%s detach_only=yes state=absent' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must specify an instance name when detaching a disk"}',
},
{'desc': 'DELETE but disk not found [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % ("missing-disk", ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DELETE but disk is attached [FAIL]',
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"The disk resource 'projects/%s/zones/%s/disks/%s' is already being used by 'projects/%s/zones/%s/instances/%s'\"}" % (PROJECT, ZONE, DNAME, PROJECT, ZONE, INAME),
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
},
{'desc': 'DELETE disk [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 15',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10'],
},
{'id': '02', 'desc': 'Create disk but do not attach (e.g. no instance_name param)',
'setup': [],
'tests': [
{'desc': 'CREATE_NO_ATTACH "string" for size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb="foo" zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_NO_ATTACH negative size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=-2 zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_NO_ATTACH size_gb exceeds quota [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=9999 zone=%s' % ("big-disk", ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
},
{'desc': 'CREATE_NO_ATTACH create the disk [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
},
{'desc': 'CREATE_NO_ATTACH but disk already exists [success]',
'm': 'gce_pd',
'a': 'name=%s zone=%s' % (DNAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
},
],
'teardown': ['gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10'],
},
{'id': '03', 'desc': 'Create and attach disk',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, "g1-small", NETWORK, SCOPES, IMAGE, USE_PD),
'gcutil adddisk "%s" --size_gb=2 --zone=%s' % (DNAME, ZONE),
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME2, ZONE),],
'tests': [
{'desc': 'CREATE_AND_ATTACH "string" for size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb="foo" instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_AND_ATTACH negative size_gb [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=-2 instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
},
{'desc': 'CREATE_AND_ATTACH size_gb exceeds quota [FAIL]',
'm': 'gce_pd',
'a': 'name=%s size_gb=9999 instance_name=%s zone=%s' % ("big-disk", INAME, ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
},
{'desc': 'CREATE_AND_ATTACH missing instance [FAIL]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, "missing-instance", ZONE),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Instance %s does not exist in zone %s"}' % ("missing-instance", ZONE),
},
{'desc': 'CREATE_AND_ATTACH disk exists but not attached [success]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH disk exists already attached [success]',
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'CREATE_AND_ATTACH attached RO, attempt RO to 2nd inst [success]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME2, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME2, DNAME, ZONE),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH attached RO, attach RW to self [FAILED no-op]',
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME, INAME, ZONE),
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
},
{'desc': 'CREATE_AND_ATTACH attached RW, attach RW to other [FAIL]',
'setup': ['gcutil attachdisk --disk=%s,mode=READ_WRITE --zone=%s %s' % (DNAME2, ZONE, INAME), 'sleep 10'],
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME2, INAME2, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[RESOURCE_IN_USE] and message: The disk resource 'projects/%s/zones/%s/disks/%s' is already being used in read-write mode\"}" % (PROJECT, ZONE, DNAME2),
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
},
{'desc': 'CREATE_AND_ATTACH attach too many disks to inst [FAIL]',
'setup': ['gcutil adddisk aa-disk-dummy --size_gb=2 --zone=%s' % (ZONE),
'gcutil adddisk aa-disk-dummy2 --size_gb=2 --zone=%s --wait_until_complete' % (ZONE),
'gcutil attachdisk --disk=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
'sleep 5'],
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
'm': 'gce_pd',
'a': 'name=%s instance_name=%s zone=%s' % ("aa-disk-dummy2", INAME, ZONE),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[LIMIT_EXCEEDED] and message: Exceeded limit 'maximum_persistent_disks' on resource 'projects/%s/zones/%s/instances/%s'. Limit: 4\"}" % (PROJECT, ZONE, INAME),
'teardown': ['gcutil detachdisk --device_name=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
'sleep 3',
'gcutil deletedisk -f aa-disk-dummy --zone=%s' % (ZONE),
'sleep 10',
'gcutil deletedisk -f aa-disk-dummy2 --zone=%s' % (ZONE),
'sleep 10'],
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'sleep 15',
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 15',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME2, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME2, ZONE),
'sleep 10'],
},
{'id': '04', 'desc': 'Delete / destroy instances',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME2, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME3, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME4, ZONE, TYPE, IMAGE),
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME5, ZONE, TYPE, IMAGE)],
'tests': [
{'desc': 'DELETE instance, bad zone param [FAIL]',
'm': 'gce',
'a': 'name=missing-inst zone=bogus state=absent',
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "value of zone must be one of: us-central1-a,us-central1-b,us-central2-a,europe-west1-a,europe-west1-b, got: bogus"}',
},
{'desc': 'DELETE non-existent instance, no-op [success]',
'm': 'gce',
'a': 'name=missing-inst zone=%s state=absent' % (ZONE),
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-inst", "state": "absent", "zone": "%s"}' % (ZONE),
},
{'desc': 'DELETE an existing named instance [success]',
'm': 'gce',
'a': 'name=%s zone=%s state=absent' % (INAME, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
},
{'desc': 'DELETE list of instances with a non-existent one [success]',
'm': 'gce',
'a': 'instance_names=%s,missing,%s zone=%s state=absent' % (INAME2,INAME3, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME2, INAME3, ZONE),
},
{'desc': 'DELETE list of instances all pre-exist [success]',
'm': 'gce',
'a': 'instance_names=%s,%s zone=%s state=absent' % (INAME4,INAME5, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME4, INAME5, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
'sleep 10'],
},
{'id': '05', 'desc': 'Create instances',
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME7),
'gcutil addinstance boo --wait_until_running --zone=%s --machine_type=%s --network=%s --disk=%s,mode=READ_WRITE,boot --kernel=%s' % (ZONE,TYPE,NETWORK,DNAME7,KERNEL),
],
'tests': [
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
'm': 'gce',
'a': 'name=foo image=foo',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
},
{'desc': 'CREATE_INSTANCE metadata a list [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\'[\\"foo\\":\\"bar\\",\\"baz\\":1]\'' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE metadata not a dict [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\\"foo\\":\\"bar\\",\\"baz\\":1' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE with metadata form1 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata=\'{"foo":"bar","baz":1}\'' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE with metadata form2 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata={\'foo\':\'bar\',\'baz\':1}' % (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE with metadata form3 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata="foo:bar" '% (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
},
{'desc': 'CREATE_INSTANCE with metadata form4 [FAIL]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s metadata="{\'foo\':\'bar\'}"'% (INAME,ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
},
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
'm': 'gce',
'a': 'instance_names=foo,bar image=foo',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
},
{'desc': 'CREATE_INSTANCE single inst, using defaults [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s' % (INAME),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
},
{'desc': 'CREATE_INSTANCE the same instance again, no-op [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s' % (INAME),
'r': '127.0.0.1 | success >> {"changed": false, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with alt type [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s machine_type=n1-standard-2' % (INAME2),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-2", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.192.227", "public_ip": "173.255.121.233", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME2, ZONE, INAME2, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s persistent_boot_disk=yes' % (INAME3),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME3, ZONE, INAME3, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd, that already exists [success]',
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME6),],
'strip_numbers': True,
'm': 'gce',
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME6, ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME6, ZONE, INAME6, ZONE),
},
{'desc': 'CREATE_INSTANCE instance with root pd attached to other inst [FAIL]',
'm': 'gce',
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME7, ZONE),
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "Unexpected error attempting to create instance %s, error: The disk resource \'projects/%s/zones/%s/disks/%s\' is already being used in read-write mode"}' % (INAME7,PROJECT,ZONE,DNAME7),
},
{'desc': 'CREATE_INSTANCE use *all* the options! [success]',
'strip_numbers': True,
'm': 'gce',
'a': 'instance_names=%s,%s metadata=\'{\\"foo\\":\\"bar\\", \\"baz\\":1}\' tags=t1,t2,t3 zone=%s image=centos-6-v20130731 persistent_boot_disk=yes' % (INAME4,INAME5,ZONE),
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.130.4", "public_ip": "173.255.121.97", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}, {"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.207.226", "public_ip": "173.255.121.85", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}], "instance_names": ["%s", "%s"], "state": "present", "zone": "%s"}' % (INAME4, ZONE, INAME5, ZONE, INAME4, INAME5, ZONE),
},
],
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME6, ZONE),
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME7, ZONE),
'gcutil deleteinstance -f boo --zone=%s' % (ZONE),
'sleep 10',
'gcutil deletedisk -f "%s" --zone=%s' % (INAME3, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME4, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME5, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME6, ZONE),
'gcutil deletedisk -f "%s" --zone=%s' % (INAME7, ZONE),
'sleep 10'],
},
{'id': '06', 'desc': 'Delete / destroy networks and firewall rules',
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
'gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR2, GW2, NETWK2),
'sleep 5',
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK2, FW2),
'sleep 5'],
'tests': [
{'desc': 'DELETE bogus named firewall [success]',
'm': 'gce_net',
'a': 'fwname=missing-fwrule state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "fwname": "missing-fwrule", "state": "absent"}',
},
{'desc': 'DELETE bogus named network [success]',
'm': 'gce_net',
'a': 'name=missing-network state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-network", "state": "absent"}',
},
{'desc': 'DELETE named firewall rule [success]',
'm': 'gce_net',
'a': 'fwname=%s state=absent' % (FW1),
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "state": "absent"}' % (FW1),
'teardown': ['sleep 5'], # pause to give GCE time to delete fwrule
},
{'desc': 'DELETE unused named network [success]',
'm': 'gce_net',
'a': 'name=%s state=absent' % (NETWK1),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (NETWK1),
},
{'desc': 'DELETE named network *and* fwrule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s state=absent' % (NETWK2, FW2),
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "name": "%s", "state": "absent"}' % (FW2, NETWK2),
},
],
'teardown': ['gcutil deletenetwork -f %s' % (NETWK1),
'gcutil deletenetwork -f %s' % (NETWK2),
'sleep 5',
'gcutil deletefirewall -f %s' % (FW1),
'gcutil deletefirewall -f %s' % (FW2)],
},
{'id': '07', 'desc': 'Create networks and firewall rules',
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
'sleep 5',
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
'sleep 5'],
'tests': [
{'desc': 'CREATE network without specifying ipv4_range [FAIL]',
'm': 'gce_net',
'a': 'name=fail',
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Missing required 'ipv4_range' parameter\"}",
},
{'desc': 'CREATE network with specifying bad ipv4_range [FAIL]',
'm': 'gce_net',
'a': 'name=fail ipv4_range=bad_value',
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.IPv4Range': 'bad_value'. Must be a CIDR address range that is contained in the RFC1918 private address blocks: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]\"}",
},
{'desc': 'CREATE existing network, not changed [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s' % (NETWK1, CIDR1),
'r': '127.0.0.1 | success >> {"changed": false, "ipv4_range": "%s", "name": "%s", "state": "present"}' % (CIDR1, NETWK1),
},
{'desc': 'CREATE new network, changed [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s' % (NETWK2, CIDR2),
'r': '127.0.0.1 | success >> {"changed": true, "ipv4_range": "10.240.32.0/24", "name": "%s", "state": "present"}' % (NETWK2),
},
{'desc': 'CREATE new fw rule missing params [FAIL]',
'm': 'gce_net',
'a': 'name=%s fwname=%s' % (NETWK1, FW1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required firewall rule parameter(s)"}',
},
{'desc': 'CREATE new fw rule bad params [FAIL]',
'm': 'gce_net',
'a': 'name=%s fwname=broken allowed=blah src_tags="one,two"' % (NETWK1),
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.allowed[0].IPProtocol': 'blah'. Must be one of [\\\"tcp\\\", \\\"udp\\\", \\\"icmp\\\"] or an IP protocol number between 0 and 255\"}",
},
{'desc': 'CREATE existing fw rule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW1),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": false, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW1, CIDR1, NETWK1),
},
{'desc': 'CREATE new fw rule [success]',
'm': 'gce_net',
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW3),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW3, CIDR1, NETWK1),
},
{'desc': 'CREATE new network *and* fw rule [success]',
'm': 'gce_net',
'a': 'name=%s ipv4_range=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK3, CIDR3, FW4),
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW4, CIDR3, NETWK3),
},
],
'teardown': ['gcutil deletefirewall -f %s' % (FW1),
'gcutil deletefirewall -f %s' % (FW2),
'gcutil deletefirewall -f %s' % (FW3),
'gcutil deletefirewall -f %s' % (FW4),
'sleep 5',
'gcutil deletenetwork -f %s' % (NETWK1),
'gcutil deletenetwork -f %s' % (NETWK2),
'gcutil deletenetwork -f %s' % (NETWK3),
'sleep 5'],
},
{'id': '08', 'desc': 'Create load-balancer resources',
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
],
'tests': [
{'desc': 'Do nothing [FAIL]',
'm': 'gce_lb',
'a': 'httphealthcheck_port=7',
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Nothing to do, please specify a \\\"name\\\" or \\\"httphealthcheck_name\\\" parameter"}',
},
{'desc': 'CREATE_HC create basic http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s' % (HC1),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
},
{'desc': 'CREATE_HC (repeat, no-op) create basic http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s' % (HC1),
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
},
{'desc': 'CREATE_HC create custom http healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port=1234 httphealthcheck_path="/whatup" httphealthcheck_host="foo" httphealthcheck_interval=300' % (HC2),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": "foo", "httphealthcheck_interval": 300, "httphealthcheck_name": "%s", "httphealthcheck_path": "/whatup", "httphealthcheck_port": 1234, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC2),
},
{'desc': 'CREATE_HC create (broken) custom http healthcheck [FAIL]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port="string" httphealthcheck_path=7' % (HC3),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for: Expected a signed integer, got \'string\' (class java.lang.String)"}',
},
{'desc': 'CREATE_LB create lb, missing region [FAIL]',
'm': 'gce_lb',
'a': 'name=%s' % (LB1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required region name"}',
},
{'desc': 'CREATE_LB create lb, bogus region [FAIL]',
'm': 'gce_lb',
'a': 'name=%s region=bogus' % (LB1),
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[404], API error code[None] and message: The resource \'projects/%s/regions/bogus\' was not found"}' % (PROJECT),
},
{'desc': 'CREATE_LB create lb, minimal params [success]',
'strip_numbers': True,
'm': 'gce_lb',
'a': 'name=%s region=%s' % (LB1, REGION),
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.123.245", "httphealthchecks": [], "members": [], "name": "%s", "port_range": "1-65535", "protocol": "tcp", "region": "%s", "state": "present"}' % (LB1, REGION),
},
{'desc': 'CREATE_LB create lb full params [success]',
'strip_numbers': True,
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s httphealthcheck_port=5055 httphealthcheck_path="/howami" name=%s port_range=8000-8888 region=%s members=%s/%s,%s/%s' % (HC3,LB2,REGION,ZONE,INAME,ZONE,INAME2),
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.126.81", "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/howami", "httphealthcheck_port": 5055, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "httphealthchecks": ["%s"], "members": ["%s/%s", "%s/%s"], "name": "%s", "port_range": "8000-8888", "protocol": "tcp", "region": "%s", "state": "present"}' % (HC3,HC3,ZONE,INAME,ZONE,INAME2,LB2,REGION),
},
],
'teardown': [
'gcutil deleteinstance --zone=%s -f %s %s' % (ZONE, INAME, INAME2),
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletehttphealthcheck -f %s %s %s' % (HC1, HC2, HC3),
],
},
{'id': '09', 'desc': 'Destroy load-balancer resources',
'setup': ['gcutil addhttphealthcheck %s' % (HC1),
'sleep 5',
'gcutil addhttphealthcheck %s' % (HC2),
'sleep 5',
'gcutil addtargetpool --health_checks=%s --region=%s %s-tp' % (HC1, REGION, LB1),
'sleep 5',
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB1, REGION, LB1),
'sleep 5',
'gcutil addtargetpool --region=%s %s-tp' % (REGION, LB2),
'sleep 5',
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB2, REGION, LB2),
'sleep 5',
],
'tests': [
{'desc': 'DELETE_LB: delete a non-existent LB [success]',
'm': 'gce_lb',
'a': 'name=missing state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing", "state": "absent"}',
},
{'desc': 'DELETE_LB: delete a non-existent LB+HC [success]',
'm': 'gce_lb',
'a': 'name=missing httphealthcheck_name=alsomissing state=absent',
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_name": "alsomissing", "name": "missing", "state": "absent"}',
},
{'desc': 'DELETE_LB: destroy standalone healthcheck [success]',
'm': 'gce_lb',
'a': 'httphealthcheck_name=%s state=absent' % (HC2),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": null, "state": "absent"}' % (HC2),
},
{'desc': 'DELETE_LB: destroy standalone balancer [success]',
'm': 'gce_lb',
'a': 'name=%s state=absent' % (LB2),
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (LB2),
},
{'desc': 'DELETE_LB: destroy LB+HC [success]',
'm': 'gce_lb',
'a': 'name=%s httphealthcheck_name=%s state=absent' % (LB1, HC1),
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": "%s", "state": "absent"}' % (HC1,LB1),
},
],
'teardown': [
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
'sleep 10',
'gcutil deletehttphealthcheck -f %s %s' % (HC1, HC2),
],
},
]
def main(tests_to_run=[]):
for test in test_cases:
if tests_to_run and test['id'] not in tests_to_run:
continue
print "=> starting/setup '%s:%s'"% (test['id'], test['desc'])
if DEBUG: print "=debug>", test['setup']
for c in test['setup']:
(s,o) = run(c)
test_i = 1
for t in test['tests']:
if DEBUG: print "=>debug>", test_i, t['desc']
# run any test-specific setup commands
if t.has_key('setup'):
for setup in t['setup']:
(status, output) = run(setup)
# run any 'peek_before' commands
if t.has_key('peek_before') and PEEKING_ENABLED:
for setup in t['peek_before']:
(status, output) = run(setup)
# run the ansible test if 'a' exists, otherwise
# an empty 'a' directive allows test to run
# setup/teardown for a subsequent test.
if t['a']:
if DEBUG: print "=>debug>", t['m'], t['a']
acmd = "ansible all -o -m %s -a \"%s\"" % (t['m'],t['a'])
#acmd = "ANSIBLE_KEEP_REMOTE_FILES=1 ansible all -vvv -m %s -a \"%s\"" % (t['m'],t['a'])
(s,o) = run(acmd)
# check expected output
if DEBUG: print "=debug>", o.strip(), "!=", t['r']
print "=> %s.%02d '%s':" % (test['id'], test_i, t['desc']),
if t.has_key('strip_numbers'):
# strip out all numbers so we don't trip over different
# IP addresses
is_good = (o.strip().translate(None, "0123456789") == t['r'].translate(None, "0123456789"))
else:
is_good = (o.strip() == t['r'])
if is_good:
print "PASS"
else:
print "FAIL"
if VERBOSE:
print "=>", acmd
print "=> Expected:", t['r']
print "=> Got:", o.strip()
# run any 'peek_after' commands
if t.has_key('peek_after') and PEEKING_ENABLED:
for setup in t['peek_after']:
(status, output) = run(setup)
# run any test-specific teardown commands
if t.has_key('teardown'):
for td in t['teardown']:
(status, output) = run(td)
test_i += 1
print "=> completing/teardown '%s:%s'" % (test['id'], test['desc'])
if DEBUG: print "=debug>", test['teardown']
for c in test['teardown']:
(s,o) = run(c)
if __name__ == '__main__':
tests_to_run = []
if len(sys.argv) == 2:
if sys.argv[1] in ["--help", "--list"]:
print "usage: %s [id1,id2,...,idN]" % sys.argv[0]
print " * An empty argument list will execute all tests"
print " * Do not need to specify tests in numerical order"
print " * List test categories with --list or --help"
print ""
for test in test_cases:
print "\t%s:%s" % (test['id'], test['desc'])
sys.exit(0)
else:
tests_to_run = sys.argv[1].split(',')
main(tests_to_run)

View file

@ -1,10 +0,0 @@
#jinja2: variable_end_string: @@, variable_start_string: @@
{% raw %}
if this succeeds you should see '{{ ansible_hostname }}' with the hostname on the line above
if this fails you should see '@@ ansible_hostname @@' with the hostname on the line beneath
{% endraw %}
@@ ansible_hostname @@
{{ ansible_hostname }}

View file

@ -1,113 +0,0 @@
# simple test of lookup plugins in with_*
---
- hosts: all
connection: local
vars:
empty_list: []
tasks:
- name: test with_items
action: command true
with_items:
- 1
- 2
- 3
- name: test with_items with empty list
action: command true
with_items: $empty_list
- name: test with_file and FILE
action: command test "$item" = "$FILE(sample.j2)"
with_file: sample.j2
- name: test with_pipe
action: command test "$item" = "$PIPE(cat sample.j2)"
with_pipe: cat sample.j2
- name: test LOOKUP and PIPE
action: command test "$LOOKUP(pipe, cat sample.j2)" = "$PIPE(cat sample.j2)"
- name: test with_sequence, generate
command: touch /tmp/seq-${item}
with_sequence: 0-16/2:%02x
- name: test with_sequence, fenceposts 1
copy: src=/tmp/seq-00 dest=/tmp/seq-10
- name: test with_sequence, fenceposts 2
file: dest=/tmp/seq-${item} state=absent
with_items: [11, 12]
- name: test with_sequence, missing
file: dest=/tmp/seq-${item} state=absent
with_sequence: 0x10/02:%02x
- name: test with_sequence,remove
file: dest=/tmp/seq-${item} state=absent
with_sequence: 0-0x10/02:%02x
- name: ensure test file doesnt exist
# command because file will return differently
action: command rm -f /tmp/ansible-test-with_lines-data
- name: test with_lines
action: shell echo "$item" >> /tmp/ansible-test-with_lines-data
with_lines: cat sample.j2
- name: verify with_lines
action: copy src=sample.j2 dest=/tmp/ansible-test-with_lines-data
- name: cleanup test file
action: file path=/tmp/ansible-test-with_lines-data state=absent
# Test nested loop
- name: test nested loop with more than 3 elements
command: test "{{ item[0] }}, {{ item[1] }}, {{ item[2] }}, {{ item[3] }}" = "red, 1, up, top"
with_nested:
- [ 'red' ]
- [ 1 ]
- [ 'up']
- [ 'top']
# password lookup plugin
- name: ensure test file doesn't exist
# command because file will return differently
action: command rm -f /tmp/ansible-test-with_password
- name: test LOOKUP and PASSWORD with non existing password file
action: command test "$LOOKUP(password, /tmp/ansible-test-with_password)" = "$PASSWORD(/tmp/ansible-test-with_password)"
- name: test LOOKUP and PASSWORD with existing password file
action: command test "$LOOKUP(password, /tmp/ansible-test-with_password)" = "$PASSWORD(/tmp/ansible-test-with_password)"
- name: now test existing password via $item and with_password
action: command test "$PASSWORD(/tmp/ansible-test-with_password)" = "$item"
with_password:
- /tmp/ansible-test-with_password
- name: cleanup test file
action: file path=/tmp/ansible-test-with_password state=absent
- name: now test a password of non-default length (default=20, but here length=8)
action: command test "$PASSWORD(/tmp/ansible-test-with_password length=8)" = "$LOOKUP(password, /tmp/ansible-test-with_password)"
# - name: did we really create a password of length=8?
# action: command test "`expr length $PASSWORD(/tmp/ansible-test-with_password)`" = "8"
- name: cleanup test file, again
action: file path=/tmp/ansible-test-with_password state=absent
# indexed_items lookup plugin
- name: create directory for indexed_items
file: path=/tmp/ansible-test-with_indexed_items-data state=directory
- name: test indexed_items
shell: echo "{{ item.0 }}" > /tmp/ansible-test-with_indexed_items-data/{{ item.1 }}
with_indexed_items:
- a
- b
- c
- name: check indexed_items content
shell: test -f /tmp/ansible-test-with_indexed_items-data/{{ item.1 }} &&
test "{{ item.0 }}" = "$(cat /tmp/ansible-test-with_indexed_items-data/{{ item.1 }})"
with_indexed_items:
- a
- b
- c
- name: cleanup indexed_items test
file: path=/tmp/ansible-test-with_indexed_items-data/{{ item.1 }} state=absent
with_indexed_items:
- a
- b
- c
- name: remove with_indexed_items directory
file: path=/tmp/ansible-test-with_indexed_items-data state=absent

View file

@ -1,48 +0,0 @@
---
- hosts: all
connection: local
gather_facts: False
vars:
var_true: True
var_false: False
var_empty_str: "''"
var_null: ~
tasks:
- action: command echo ping
always_run: yes
- action: command echo pong 1
- action: command echo pong 2
always_run: no
- action: command echo pong 3
always_run: 1 + 1
- action: command echo pong 4
always_run: "''"
- action: command echo pong 5
always_run: False
- action: command echo pong 6
always_run: True
- action: command echo pong 7
always_run: var_true
- action: command echo pong 8
always_run: var_false
- action: command echo pong 9
always_run: var_empty_str
- action: command echo pong 10
always_run: var_null
# this will never run...
- action: command echo pong 11
always_run: yes
when: no

View file

@ -1,25 +0,0 @@
---
- hosts: all
connection: local
gather_facts: False
tasks:
- action: command echo first action
- action: command echo second action
register: var
changed_when: "'X' in var.stdout"
- action: shell exit 2
register: exit
ignore_errors: yes
changed_when: "exit.rc < 1"
- action: command echo third action
changed_when: false
- action: file path=/ state=directory
changed_when: true
- action: command echo {{item}}
register: out
changed_when: "'e' in out.stdout"
with_items:
- hello
- foo
- bye

View file

@ -1,15 +0,0 @@
---
- hosts: all
connection: local
gather_facts: False
tasks:
- action: shell exit 0
register: exit
failed_when: not exit.rc in [0, 1]
- action: shell exit 1
register: exit
failed_when: exit.rc not in [0, 1]
- action: shell exit 2
register: exit
failed_when: exit.rc not in [0, 1]

View file

@ -1,9 +0,0 @@
---
- hosts: all
connection: local
gather_facts: False
tasks:
- action: command false
ignore_errors: true
- action: command false

View file

@ -1,17 +0,0 @@
---
- hosts: localhost
connection: local
gather_facts: False
tasks:
- name: Loggføring fungerer
command: echo "Feilsøking"
always_run: yes
- name: Die Süßigkeit
command: echo "Die Süßigkeit"
always_run: yes
- name: Logging works
command: echo "Debugging"
always_run: yes

View file

@ -1,98 +0,0 @@
---
# run with option -i localhost
# need root permissions
- name: host module testing
hosts: localhost
connection: local
gather_facts: no
sudo: yes
pre_tasks:
- name: backup /etc/hosts
command: cp /etc/hosts /etc/hosts.origin
post_tasks:
- name: restore /etc/hosts
command: cp /etc/hosts.origin /etc/hosts
tasks:
- name: test add a record
host: hostname=foobar ip=192.168.123.1
register: result
failed_when: not result.changed
- name: test error handling only hostname given on present
host: hostname=foobar
register: result
failed_when: result.changed
- name: test error handling only ip given on present
host: ip=192.168.123.1
register: result
failed_when: result.changed
- name: test record exists
host: hostname=foobar ip=192.168.123.1
register: result
failed_when: result.changed
- name: test remove record using hostname
host: hostname=foobar state=absent
register: result
failed_when: not result.changed
- name: test remove not existing record using hostname
host: hostname=foobar state=absent
register: result
failed_when: result.changed
- name: test add a record again
host: hostname=foobar ip=192.168.123.1
register: result
failed_when: not result.changed
- name: test remove record using ip
host: ip=192.168.123.1 state=absent
register: result
failed_when: not result.changed
- name: test remove not existing record using ip
host: ip=192.168.123.1 state=absent
register: result
failed_when: result.changed
- name: test add a record with alias
host: hostname=foobar ip=192.168.123.1 aliases=foobar.com,foobar.net
register: result
failed_when: not result.changed
- name: test add an existing record with alias
host: hostname=foobar ip=192.168.123.1 aliases=foobar.com,foobar.net
register: result
failed_when: result.changed
- name: test add an existing record with changed alias
host: hostname=foobar ip=192.168.123.1 aliases=foobar.net,foobar.com
register: result
failed_when: not result.changed
- name: test remove aliases from existing record
host: hostname=foobar ip=192.168.123.1
register: result
failed_when: not result.changed
- name: test add aliases for existing record
host: hostname=foobar ip=192.168.123.1 aliases=foobar.net,foobar.com
register: result
failed_when: not result.changed
- name: test change ip on existing record
host: hostname=foobar ip=192.168.123.2
register: result
failed_when: not result.changed
- name: test change hostname on existing record
host: hostname=barfoo ip=192.168.123.2
register: result
failed_when: not result.changed

View file

@ -1,133 +0,0 @@
---
# To run me manually, use: -i "localhost,"
- hosts: localhost
connection: local
gather_facts: no
vars:
- testdir: /tmp/ansible-rcopy
- filesdir: test_recursive_copy/files
tasks:
#
# First, regression tests for single-file behavior
#
- name: "src single file, dest file"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/file1
register: res
- command: test -f {{testdir}}/file1
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/file1
register: res
- command: test "{{res.changed}}" = "False"
- name: "src single file, dest dir w/trailing slash"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/
register: res
- command: test -f {{testdir}}/test1
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/
register: res
- command: test "{{res.changed}}" = "False"
- name: "src single file, dest dir wo/trailing slash - doesn't behave in sane way"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}
register: res
- shell: test -f {{testdir}}/test1
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}
register: res
- command: test "{{res.changed}}" = "False"
#
# Now, test recursive behavior
#
- name: "src dir w/trailing slash, dest w/trailing slash"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir/ dest={{testdir}}/
register: res
- command: test -d {{testdir}}/subdir2
- command: test -d {{testdir}}/subdir2/subdir3
- command: test -d {{testdir}}/subdir2/subdir3
- command: test -f {{testdir}}/subdir2/subdir3/test1
- command: test -f {{testdir}}/subdir2/subdir3/test2
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir/ dest={{testdir}}/
register: res
- command: test "{{res.changed}}" = "False"
# Expecting the same behavior
- name: "src dir w/trailing slash, dest wo/trailing slash"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir/ dest={{testdir}}
register: res
- command: test -d {{testdir}}/subdir2
- command: test -d {{testdir}}/subdir2/subdir3
- command: test -d {{testdir}}/subdir2/subdir3
- command: test -f {{testdir}}/subdir2/subdir3/test1
- command: test -f {{testdir}}/subdir2/subdir3/test2
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir/ dest={{testdir}}
register: res
- command: test "{{res.changed}}" = "False"
- name: "src dir wo/trailing slash, dest w/trailing slash"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir dest={{testdir}}/
register: res
- command: test -d {{testdir}}/subdir/subdir2
- command: test -d {{testdir}}/subdir/subdir2/subdir3
- command: test -d {{testdir}}/subdir/subdir2/subdir3
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test1
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test2
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir dest={{testdir}}/
register: res
- command: test "{{res.changed}}" = "False"
# Expecting the same behavior
- name: "src dir wo/trailing slash, dest wo/trailing slash"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir dest={{testdir}}
register: res
- command: test -d {{testdir}}/subdir/subdir2
- command: test -d {{testdir}}/subdir/subdir2/subdir3
- command: test -d {{testdir}}/subdir/subdir2/subdir3
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test1
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test2
- command: test "{{res.changed}}" = "True"
- copy: src={{filesdir}}/subdir dest={{testdir}}
register: res
- command: test "{{res.changed}}" = "False"
- name: "Verifying notify handling for recursive files"
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/subdir dest={{testdir}}
notify:
- files changed
- meta: flush_handlers
- command: test -f {{testdir}}/notify_fired
- command: rm {{testdir}}/notify_fired
- copy: src={{filesdir}}/subdir dest={{testdir}}
notify:
- files changed
- meta: flush_handlers
- command: test ! -f {{testdir}}/notify_fired
handlers:
- name: files changed
command: touch {{testdir}}/notify_fired

View file

@ -1,2 +0,0 @@
---
- include: "{{dir}}/playbook-included.yml variable=foobar"

View file

@ -1,90 +0,0 @@
---
# To run me manually, use: -i "localhost,"
- hosts: localhost
connection: local
gather_facts: no
vars:
- testdir: /tmp/ansible-unarchive
- filesdir: test_unarchive/files
tasks:
- name: "Simple tar unarchive."
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- unarchive: src={{filesdir}}/test.tar dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{filesdir}}/test.tar dest={{testdir}}
register: res
- fail: msg="Resource was not expected to be changed."
when: res|changed
- name: "Simple tar.gz unarchive."
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- unarchive: src={{filesdir}}/test.tar.gz dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{filesdir}}/test.tar.gz dest={{testdir}}
register: res
- fail: msg="Resource was not expected to be changed."
when: res|changed
- name: "Simple zip unarchive."
command: rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- unarchive: src={{filesdir}}/test.zip dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{filesdir}}/test.zip dest={{testdir}}
register: res
- fail: msg="Resource was expected to be changed."
when: not res|changed
- name: "Unarchive a local tar file."
command : rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/test.tar dest={{testdir}}
- unarchive: src={{testdir}}/test.tar dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{testdir}}/test.tar dest={{testdir}}
register: res
- fail: msg="Resource was not expected to be changed."
when: res|changed
- name: "Unarchive a local tar.gz file."
command : rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/test.tar.gz dest={{testdir}}
- unarchive: src={{testdir}}/test.tar.gz dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{testdir}}/test.tar.gz dest={{testdir}}
register: res
- fail: msg="Resource was not expected to be changed."
when: res|changed
- name: "Unarchive a local zip file."
command : rm -rf {{testdir}}
- file: state=directory dest={{testdir}}
- copy: src={{filesdir}}/test.zip dest={{testdir}}
- unarchive: src={{testdir}}/test.zip dest={{testdir}}
register: res
- command: test -f {{testdir}}/foo
- fail: msg="Resource was expected to be changed."
when: not res|changed
- unarchive: src={{testdir}}/test.zip dest={{testdir}}
register: res
- fail: msg="Resource was expected to be changed."
when: not res|changed

View file

@ -1,70 +0,0 @@
# extremely simple test of the most basic of playbook engine/functions
---
- hosts: all
connection: local
# the 'weasels' string should show up in the output
vars:
answer: "Wuh, I think so, Brain, but if we didn't have ears, we'd look like weasels."
port: 5150
# we should have import events for common_vars and CentOS.yml (if run on CentOS)
# sorry, tests are a bit platform specific just for now
vars_files:
- common_vars.yml
- [ '{{facter_operatingsystem.yml}}', 'default_os.yml' ]
tasks:
- name: test basic success command
action: command true
- name: test basic success command 2
action: command true
- name: test basic shell, plus two ways to dereference a variable
action: shell echo {{port}}
- name: test vars_files imports
action: shell echo {{duck}} {{cow}} {{testing}}
# in the command below, the test file should contain a valid template
# and trigger the change handler
- name: test copy
action: copy src=sample.j2 dest=/tmp/ansible_test_data_copy.out
notify:
- on change 1
# there should be various poll events within the range
- name: async poll test
action: shell sleep 5
async: 10
poll: 3
# the following command should be skipped
- name: this should be skipped
action: shell echo 'if you see this, this is wrong'
when: 2 == 3
handlers:
# in the above test example, this should fire ONCE (at the end)
- name: on change 1
action: shell echo 'this should fire once'
# in the above test example, this should fire ONCE (at the end)
- name: on change 2
action: shell echo 'this should fire once also'
# in the above test example, this should NOT FIRE
- name: on change 3
action: shell echo 'if you see this, this is wrong'

View file

@ -1,20 +0,0 @@
---
# Test iterating over lines of stdout stored in a register.
- hosts: localhost
connection: local
vars:
small_file: /etc/resolv.conf
temp_file: /tmp/ansible_result_list.tmp
tasks:
- action: command cat $small_file
register: result
- action: file dest=$temp_file state=absent
- action: shell echo '$item' >> $temp_file
with_items: ${result.stdout_lines}
- action: command diff $small_file $temp_file
- action: file dest=$temp_file state=absent

View file

@ -1,6 +0,0 @@
An ansible is a fictitious machine capable of instantaneous or superluminal
communication. Typically it is depicted as a lunch-box sized object with some
combination of microphone, speaker, keyboard and display. It can send and
receive messages to and from a corresponding device over any distance
whatsoever with no delay. Ansibles occur as plot devices in science fiction
literature.

View file

@ -1,4 +0,0 @@
Are you pondering what I'm pøndering?
I think so Brain, but {{ answer }}

View file

@ -1 +0,0 @@
hello {{ who }}

View file

@ -1 +0,0 @@
hello {{ who }}

View file

@ -1,5 +0,0 @@
localhost
[all:vars]
inventory_var_good="{{ playbook_var_good }}"
inventory_var_bad="{{ playbook_var_bad }}"

View file

@ -1,7 +0,0 @@
- hosts: all
vars:
playbook_var_good: "ok"
playbook_var_bad: "{{ undefined_var }}"
tasks:
- debug: msg="{{ playbook_var_good }}"
- debug: msg="{{ playbook_var_bad }}"

View file

@ -1,7 +0,0 @@
- hosts: all
vars:
playbook_var_good: "ok"
playbook_var_bad: "{{ undefined_var }}"
tasks:
- debug: msg="{{ inventory_var_good }}"
- debug: msg="{{ inventory_var_bad }}"

View file

@ -1,2 +0,0 @@
---
attr2: 2

View file

@ -1,2 +0,0 @@
---
attr1: 1

View file

@ -1,6 +0,0 @@
host1
host2
[group]
host1
host2

View file

@ -1,2 +0,0 @@
---
- hosts: group

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
world