Regression tests for playbooks, logging the events they call via callbacks.

pull/70/head
Michael DeHaan 13 years ago
parent b15c8e9cb1
commit 5371a9e497

@ -49,7 +49,7 @@ class PlaybookCallbacks(object):
def on_failed(self, host, results): def on_failed(self, host, results):
print "failed: [%s] => %s\n" % (host, utils.smjson(results)) print "failed: [%s] => %s\n" % (host, utils.smjson(results))
def on_ok(self, host): def on_ok(self, host, host_result):
print "ok: [%s]\n" % (host) print "ok: [%s]\n" % (host)
def on_play_start(self, pattern): def on_play_start(self, pattern):

@ -83,7 +83,6 @@ class PlayBook(object):
# playbook file can be passed in as a path or # playbook file can be passed in as a path or
# as file contents (to support API usage) # as file contents (to support API usage)
print "DEBUG: playbook=%s" % playbook
self.basedir = os.path.dirname(playbook) self.basedir = os.path.dirname(playbook)
self.playbook = self._parse_playbook(playbook) self.playbook = self._parse_playbook(playbook)
@ -384,7 +383,7 @@ class PlayBook(object):
else: else:
self.failures[host] = self.failures[host] + 1 self.failures[host] = self.failures[host] + 1
else: else:
self.callbacks.on_ok(host) self.callbacks.on_ok(host, results)
if not host in self.invocations: if not host in self.invocations:
self.invocations[host] = 1 self.invocations[host] = 1
else: else:
@ -418,7 +417,9 @@ class PlayBook(object):
# for this particular pattern group # for this particular pattern group
for x in handlers: for x in handlers:
name = x['name'] name = x.get('name', None)
if name is None:
raise errors.AnsibleError('handler is missing a name')
if match_name == name: if match_name == name:
# flag the handler with the list of hosts # flag the handler with the list of hosts
# it needs to be run on, it will be run later # it needs to be run on, it will be run later

@ -385,6 +385,12 @@ class Runner(object):
and then run the async module wrapping the other module and then run the async module wrapping the other module
''' '''
# hack to make the 'shell' module keyword really be executed
# by the command module
if self.module_name == 'shell':
self.module_name = 'command'
self.module_args.append("#USE_SHELL")
async = self._transfer_module(conn, tmp, 'async_wrapper') async = self._transfer_module(conn, tmp, 'async_wrapper')
module = self._transfer_module(conn, tmp, self.module_name) module = self._transfer_module(conn, tmp, self.module_name)
result = self._execute_module(conn, tmp, async, self.module_args, result = self._execute_module(conn, tmp, async, self.module_args,

@ -35,9 +35,12 @@ class TestCallbacks(object):
def on_failed(self, host, results): def on_failed(self, host, results):
self.events.append([ 'failed', [ host, results ]]) self.events.append([ 'failed', [ host, results ]])
# FIXME: this callback should get results too! def on_ok(self, host, host_result):
def on_ok(self, host): # delete certain info from host_result to make test comparisons easier
self.events.append([ 'ok', [ host ]]) for k in [ 'ansible_job_id', 'md5sum', 'delta', 'start', 'end' ]:
if k in host_result:
del host_result[k]
self.events.append([ 'ok', [ host, host_result ]])
def on_play_start(self, pattern): def on_play_start(self, pattern):
self.events.append([ 'play start', [ pattern ]]) self.events.append([ 'play start', [ pattern ]])
@ -46,13 +49,11 @@ class TestCallbacks(object):
self.events.append([ 'async confused', [ msg ]]) self.events.append([ 'async confused', [ msg ]])
def on_async_poll(self, jid, host, clock, host_result): def on_async_poll(self, jid, host, clock, host_result):
self.events.append([ 'async poll', [ host, jid ]]) self.events.append([ 'async poll', [ host ]])
def on_dark_host(self, host, msg): def on_dark_host(self, host, msg):
self.events.append([ 'failed/dark', [ host, msg ]]) self.events.append([ 'failed/dark', [ host, msg ]])
# FIXME: callbacks need to be fired on notifiers as well
class TestRunner(unittest.TestCase): class TestRunner(unittest.TestCase):
@ -62,6 +63,11 @@ class TestRunner(unittest.TestCase):
self.test_dir = os.path.join(self.cwd, 'test') self.test_dir = os.path.join(self.cwd, 'test')
self.stage_dir = self._prepare_stage_dir() 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')
def _prepare_stage_dir(self): def _prepare_stage_dir(self):
stage_path = os.path.join(self.test_dir, 'test_data') stage_path = os.path.join(self.test_dir, 'test_data')
if os.path.exists(stage_path): if os.path.exists(stage_path):
@ -104,5 +110,10 @@ class TestRunner(unittest.TestCase):
def test_one(self): def test_one(self):
pb = os.path.join(self.test_dir, 'playbook1.yml') pb = os.path.join(self.test_dir, 'playbook1.yml')
print utils.bigjson(self._run(pb)) expected = os.path.join(self.test_dir, 'playbook1.events')
assert False, "this test works, but we need to check the results values to complete it" expected = utils.json_loads(file(expected).read())
actual = self._run(pb)
# if different, this will output to screen
print utils.bigjson(actual)
assert cmp(expected, actual) == 0, "expected events match actual events"

@ -0,0 +1,203 @@
{
"events": [
"start",
[
"play start",
[
"all"
]
],
[
"task start",
[
"test basic success command",
false
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": [
"/bin/true"
],
"rc": 0,
"stderr": "",
"stdout": ""
}
]
],
[
"task start",
[
"test basic success command 2",
false
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": [
"/bin/true"
],
"rc": 0,
"stderr": "",
"stdout": ""
}
]
],
[
"task start",
[
"test basic shell",
false
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": "echo $HOME ",
"rc": 0,
"stderr": "",
"stdout": "/root"
}
]
],
[
"task start",
[
"test copy",
false
]
],
[
"ok",
[
"127.0.0.1",
{
"changed": true,
"group": "root",
"mode": 420,
"path": "/tmp/ansible_test_data_copy.out",
"state": "file",
"user": "root"
}
]
],
[
"task start",
[
"test template",
false
]
],
[
"ok",
[
"127.0.0.1",
{
"changed": true,
"group": "root",
"mode": 420,
"path": "/tmp/ansible_test_data_template.out",
"state": "file",
"user": "root"
}
]
],
[
"task start",
[
"async poll test",
false
]
],
[
"async poll",
[
"127.0.0.1"
]
],
[
"async poll",
[
"127.0.0.1"
]
],
[
"async poll",
[
"127.0.0.1"
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": "sleep 5 ",
"finished": 1,
"rc": 0,
"stderr": "",
"stdout": ""
}
]
],
[
"task start",
[
"on change 1",
true
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": [
"/bin/true"
],
"rc": 0,
"stderr": "",
"stdout": ""
}
]
],
[
"task start",
[
"on change 2",
true
]
],
[
"ok",
[
"127.0.0.1",
{
"cmd": [
"/bin/true"
],
"rc": 0,
"stderr": "",
"stdout": ""
}
]
]
],
"results": {
"127.0.0.1": {
"changed": 2,
"dark": 0,
"failed": 0,
"resources": 8
}
}
}

@ -16,19 +16,44 @@
- name: test basic shell - name: test basic shell
action: shell echo $HOME action: shell echo $HOME
# in the command below, the test file should contain a valid template
# and trigger the change handler
- name: test copy - name: test copy
action: copy src=sample.j2 dest=/tmp/ansible_test_data_copy.out action: copy src=sample.j2 dest=/tmp/ansible_test_data_copy.out
notify:
- on change 1
# this should trigger two change handlers, but the 2nd should
# not be triggered twice because it's already triggered
- name: test template - name: test template
action: template src=sample.j2 dest=/tmp/ansible_test_data_template.out action: template src=sample.j2 dest=/tmp/ansible_test_data_template.out
notify:
- on change 1
- on change 2
# there should be various poll events within the range
- name: async poll test
action: shell sleep 5
async: 10
poll: 3
handlers: handlers:
# in the above test example, this should fire ONCE (at the end)
- name: on change 1 - name: on change 1
action: command /bin/true action: command /bin/true
# in the above test example, this should fire ONCE (at the end)
- name: on change 2 - name: on change 2
action: command /bin/true action: command /bin/true
- action: on change 3
# in the above test example, this should NOT FIRE
- name: on change 3
action: command /bin/true action: command /bin/true

Loading…
Cancel
Save