Merge branch 'feature/unit-tests-5223' into next

This commit is contained in:
Johannes Meyer 2013-12-16 15:40:03 +01:00
commit eb4afb1eda
24 changed files with 993 additions and 45 deletions

View File

@ -16,3 +16,8 @@ file { '/etc/motd':
owner => root,
group => root
}
user { 'vagrant':
groups => 'icingacmd',
require => Group['icingacmd']
}

View File

@ -1 +1,43 @@
These scripts are used by build.icinga.org to set up a test VM.
Set of scripts to set up and test a virtual demo machine
========================================================
This directory contains a few scripts primarily used by build.icinga.org.
* bootstrap-vm.sh
Ensures that all required software is installed and its configuration
is applied to the VM. (Usually not of interest for the typical user.)
* run_tests.sh
This is a wrapper script intended to be ran manually by a user. (Note
that you need to start this project's vagrant box for this to work!)
* run_tests.py
The actual test-runner. Accepts two options (-C|--config, -O|--output) and
expects one or more filenames or -patterns that should be run on the VM.
* run_tests.conf
The default configuration file for the test-runner. (Used when running
the wrapper script or when no custom configuration file is passed to the
test-runner.)
Format:
- commands: This section is mandatory and contains the commands to use.
- settings: This section is mandatory and defines settings that are applied to
all tests.
- setups: This section is optional and contains setup routines that should
be ran before (setup) and after (teardown) any matching test is
executed. (Note that only one setup can be effective at a time.)
Example:
"^v[1-9]\.test$": {
"setup": {
"copy": ["source >> target"], // Files that should be copied.
// Note that these files remain
// if not removed explicitly
"clean": ["target"], // Files to delete from the system
"exec": ["cmd1", "cmd2"] // Commands to execute on the system
},
"teardown": {
// The same kind of instructions as above can be added here
}
}

3
test/jenkins/apache_state.test Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
sudo service httpd status

View File

@ -1,14 +1,29 @@
#!/bin/sh
if [ "$1" != "run-by-jenkins" ]; then
echo "This script should not be run manually."
exit 1
if [ "$1" != "--force" ]; then
echo 'This script is NOT intended to be ran by an individual user.' \
'If you are not human, pass "--force" as the first option to it!'
exit 1
fi
echo "10.10.27.1 packages.icinga.org" >> /etc/hosts
if [ $# -lt 3 ]; then
echo 'Too few arguments. You need to pass "--force <user> <host>"' \
'to run this script.'
exit 1
fi
groupadd vagrant
rmdir /vagrant && ln -s /root/icinga2 /vagrant
puppet apply --modulepath=/vagrant/.vagrant-puppet/modules /vagrant/.vagrant-puppet/manifests/default.pp
user=$2
host=$3
SSH_OPTIONS="-o PasswordAuthentication=no"
SSH="ssh $SSH_OPTIONS $user@$host"
$SSH "mkdir /vagrant"
scp -qr ../../.vagrant-puppet $user@$host:/vagrant
$SSH "groupadd vagrant"
$SSH "echo '10.10.27.1 packages.icinga.org' >> /etc/hosts"
$SSH "puppet apply --modulepath=/vagrant/.vagrant-puppet/modules" \
" /vagrant/.vagrant-puppet/manifests/default.pp"
exit 0

87
test/jenkins/checkresult.test Executable file
View File

@ -0,0 +1,87 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import os
import sys
import time
import utils
STATE_OK = 0
TYPE_PASSIVE_CHECK = 1
CHECK_INTERVAL = 300 # seconds
CHECKRESULT_READ_INTERVAL = 5 # seconds
CHECKRESULT_LOCATION = '/tmp/icinga2/checkresults'
CHECKRESULT_TEMPLATE = """
host_name=%(hostname)s
service_description=%(servicename)s
check_type=%(check_type)s
check_options=0
scheduled_check=0
reschedule_check=0
latency=0
start_time=%(start_time)s
finish_time=%(finish_time)s
early_timeout=0
exited_ok=%(excited_ok)s
return_code=%(return_code)s
output=%(output)s
"""
def main():
run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql')
# We need to wait a bit first as Icinga processes a
# checkresult only if its newer than the last check
query = 'select unix_timestamp(s.last_check) as last_check ' \
'from icinga_servicestatus as s ' \
'inner join icinga_services as c ' \
'on s.service_object_id = c.service_object_id ' \
"where c.display_name = 'PassiveService1'"
state_time = float(next(iter(run_query(query)), {}).get('last_check', '0'))
if state_time == 0:
print '"PassiveService1" seems not to have been checked yet'
return 1
if (state_time + CHECK_INTERVAL) - time.time() < 30:
time.sleep(45)
# Now pass the checkresult in
with open(os.path.join(CHECKRESULT_LOCATION, 'cfoobar'), 'w') as f:
f.write(CHECKRESULT_TEMPLATE % {
'hostname': 'nsca-ng',
'servicename': 'PassiveService1',
'check_type': TYPE_PASSIVE_CHECK,
'start_time': time.time(),
'finish_time': time.time(),
'excited_ok': '1',
'return_code': STATE_OK,
'output': 'Passing in CheckResult header files works!'
})
# And notfiy Icinga that the file has been completely written...
with open(os.path.join(CHECKRESULT_LOCATION, 'cfoobar.ok'), 'w') as f:
pass
# Lastly check whether the service changed its state
time.sleep(CHECKRESULT_READ_INTERVAL * 2)
query = 'select s.output ' \
'from icinga_servicestatus as s ' \
'inner join icinga_services as c ' \
'on s.service_object_id = c.service_object_id ' \
"where c.display_name = 'PassiveService1'"
output = next(iter(run_query(query)), {}).get('output', '')
if output != 'Passing in CheckResult header files works!':
print 'Checkresult header files seem not to be processed properly'
return 1
print 'Checkresult header files are processed properly'
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,10 @@
#!/bin/sh
if [ -e "/var/run/icinga2/cmd/icinga2.cmd" ];
then
echo "Icinga2 commandpipe found"
exit 0
else
echo "Icinga2 commandpipe not found"
exit 1
fi

View File

@ -0,0 +1,5 @@
library "compat"
object CheckResultReader "reader" {
spool_dir = "/tmp/icinga2/checkresults"
}

View File

@ -0,0 +1,190 @@
from __future__ import unicode_literals
from datetime import datetime, timedelta
CHECK_INTERVAL = 10 # minutes; The actual interval are 5 minutes but as other
# tests might restart Icinga we need to take any
# rescheduling into account
TABLE_PREFIX = 'icinga_'
TABLES = [
# Central tables
'instances',
'objects',
# Debugging tables
'conninfo',
# Historical tables
'acknowledgements',
'commenthistory',
'contactnotifications',
'dbversion',
'downtimehistory',
'eventhandlers',
'externalcommands',
'flappinghistory',
'hostchecks',
'logentries',
'notifications',
'processevents',
'servicechecks',
'statehistory',
'systemcommands',
# Current status tables
'comments',
'customvariablestatus',
'hoststatus',
'programstatus',
'runtimevariables',
'scheduleddowntime',
'servicestatus',
'contactstatus',
# Configuration tables
'commands',
'configfiles',
'configfilevariables',
'contact_addresses',
'contact_notificationcommands',
'contactgroup_members',
'contactgroups',
'contactnotificationmethods',
'contacts',
'customvariables',
'host_contactgroups',
'host_contacts',
'host_parenthosts',
'hostdependencies',
'hostescalation_contactgroups',
'hostescalation_contacts',
'hostescalations',
'hostgroup_members',
'hostgroups',
'hosts',
'service_contactgroups',
'service_contacts',
'servicedependencies',
'serviceescalation_contactgroups',
'serviceescalation_contacts',
'serviceescalations',
'servicegroup_members',
'servicegroups',
'services',
'timeperiod_timeranges',
'timeperiods'
]
EXAMPLE_CONFIG = {
'localhost': ['disk', 'http', 'icinga', 'load', 'ping4',
'ping6', 'processes', 'ssh', 'users'],
'nsca-ng': ['PassiveService1', 'PassiveService2']
}
def validate_tables(tables):
"""
Return whether all tables of the IDO database scheme exist in
the given table listing
"""
missing = [n for n in TABLES if TABLE_PREFIX + n not in tables]
if missing:
print 'Some tables are missing in the IDO'
print 'Missing tables: ' + ', '.join(missing)
return False
print 'All tables were found in the IDO'
return True
def verify_host_config(config_data):
"""
Return whether the example hosts exist in the given "hosts" table
"""
if len([1 for e in config_data if e['alias'] in EXAMPLE_CONFIG]) == 2:
print 'All example hosts are stored in the IDO'
return True
print 'Some example hosts are missing in the IDO'
return False
def verify_service_config(config_data):
"""
Return whether the example services exist in the given "services" table
"""
for hostname, servicename in ((h, s) for h, ss in EXAMPLE_CONFIG.iteritems()
for s in ss):
# Not very efficient, but suitable for just two hosts...
if not any(1 for c in config_data
if c['alias'] == hostname and
c['display_name'] == servicename):
print 'The config stored in the IDO is missing some services'
return False
print 'The service config stored in the IDO is correct'
return True
def check_last_host_status_update(check_info):
"""
Return whether the example hosts are checked as scheduled
"""
for info in check_info:
if info['alias'] == 'localhost':
last_check = datetime.fromtimestamp(float(info['last_check']))
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
seconds=10):
print 'The last status update of host "localhost"' \
' was more than {0} minutes ago'.format(CHECK_INTERVAL)
return False
elif info['alias'] == 'nsca-ng':
if float(info['last_check']) > 0:
print 'The host "nsca-ng" was checked even though' \
' it should not be actively checked'
return False
print 'The updates of both example hosts are processed as configured'
return True
def check_last_service_status_update(check_info):
"""
Return whether the example services are checked as scheduled
"""
for info in check_info:
if info['display_name'] in EXAMPLE_CONFIG.get(info['alias'], []):
last_check = datetime.fromtimestamp(float(info['last_check']))
if datetime.now() - last_check > timedelta(minutes=CHECK_INTERVAL,
seconds=10):
print 'The last status update of service "{0}" of' \
' host "{1}" was more than {2} minutes ago' \
''.format(info['display_name'], info['alias'],
CHECK_INTERVAL)
return False
print 'The updates of all example services are processed as configured'
return True
def check_logentries(logentry_info):
"""
Return whether the given logentry originates from host "localhost"
and refers to its very last hard status change
"""
if logentry_info and logentry_info[0]['alias'] == 'localhost':
entry_time = datetime.fromtimestamp(float(logentry_info[0]['entry_time']))
state_time = datetime.fromtimestamp(float(logentry_info[0]['state_time']))
if entry_time - state_time > timedelta(seconds=10):
print 'The last hard state of host "localhost"' \
' seems not to have been logged'
return False
else:
print 'No logs found in the IDO for host "localhost"'
return False
print 'The last hard state of host "localhost" was properly logged'
return True

145
test/jenkins/files/utils.py Normal file
View File

@ -0,0 +1,145 @@
from __future__ import unicode_literals
import os
import json
import socket
import subprocess
__all__ = ['parse_statusdata', 'run_mysql_query', 'run_pgsql_query',
'LiveStatusSocket']
MYSQL_PARAMS = b"-t -D icinga -u icinga --password=icinga -e".split()
MYSQL_SEPARATOR = '|'
PGSQL_PARAMS = b"-nq -U icinga -d icinga -c".split()
PGSQL_SEPARATOR = '|'
PGSQL_ENVIRONMENT = {
b'PGPASSWORD': b'icinga'
}
def parse_statusdata(data, intelligent_cast=True):
parsed_data, data_type, type_data = {}, '', {}
for line in (l for l in data.split(os.linesep)
if l and not l.startswith('#')):
if '{' in line:
data_type = line.partition('{')[0].strip()
elif '}' in line:
parsed_data.setdefault(data_type, []).append(type_data)
else:
key, _, value = line.partition('=')
if intelligent_cast:
value = _cast_status_value(value)
type_data[key.strip()] = value
return parsed_data
def _cast_status_value(value):
try:
return int(value)
except ValueError:
try:
return float(value)
except ValueError:
return value
def run_mysql_query(query, path):
p = subprocess.Popen([path] + MYSQL_PARAMS + [query.encode('utf-8')],
stdout=subprocess.PIPE)
return _parse_mysql_result([l.decode('utf-8') for l in p.stdout.readlines()])
def _parse_mysql_result(resultset):
result, header = [], None
for line in (l for l in resultset if MYSQL_SEPARATOR in l):
columns = [c.strip() for c in line[1:-3].split(MYSQL_SEPARATOR)]
if header is None:
header = columns
else:
result.append(dict((header[i], v) for i, v in enumerate(columns)))
return result
def run_pgsql_query(query, path):
p = subprocess.Popen([path] + PGSQL_PARAMS + [query.encode('utf-8')],
stdout=subprocess.PIPE, env=PGSQL_ENVIRONMENT)
return _parse_pgsql_result([l.decode('utf-8') for l in p.stdout.readlines()])
def _parse_pgsql_result(resultset):
result, header = [], None
for line in (l for l in resultset if PGSQL_SEPARATOR in l):
columns = [c.strip() for c in line.split(PGSQL_SEPARATOR)]
if header is None:
header = columns
else:
result.append(dict((header[i], v) for i, v in enumerate(columns)))
return result
class LiveStatusError(Exception):
pass
class LiveStatusSocket(object):
options = [
'KeepAlive: on',
'OutputFormat: json',
'ResponseHeader: fixed16'
]
def __init__(self, path):
self.path = path
def __enter__(self):
self.connect()
return self
def __exit__(self, exc_type, exc_value, tb):
self.close()
def connect(self):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.connect(self.path)
def close(self):
self.sock.shutdown(socket.SHUT_RDWR)
self.sock.close()
def query(self, command):
self.send(command)
statuscode, response = self.recv()
if statuscode != 200:
raise LiveStatusError(statuscode, response)
return response
def send(self, query):
full_query = '\n'.join([query] + self.options)
self.sock.sendall((full_query + '\n\n').encode('utf-8'))
def recv(self):
response = b''
response_header = self.sock.recv(16)
response_code = int(response_header[:3])
response_length = int(response_header[3:].strip())
if response_length > 0:
while len(response) < response_length:
response += self.sock.recv(response_length - len(response))
response = response.decode('utf-8')
try:
response = json.loads(response)
except ValueError:
pass
return response_code, response

View File

@ -0,0 +1,38 @@
#!/bin/sh
TIMEOUT=30
case $1 in
mysql)
TYPE='MySQL'
CMD='/usr/bin/mysql -t -D icinga -u icinga --password=icinga -e'
;;
pgsql)
TYPE='PostgreSQL'
CMD='/usr/bin/psql -nq -U icinga -d icinga -c'
export PGPASSWORD='icinga'
;;
*)
echo "No IDO type specifier given!"
exit 1
;;
esac
tries=1
while true
do
out="`$CMD 'select * from icinga_hosts'`"
if [ $tries -lt $TIMEOUT ] && [ "$out" == "" ];
then
sleep 1
tries=$(($tries + 1))
else
if [ $tries -eq $TIMEOUT ];
then
echo "IDO ($TYPE) does not have any hosts or is not responding" >&2
fi
break
fi
done

View File

@ -0,0 +1,3 @@
#!/bin/sh
sudo service icinga2 status

67
test/jenkins/ido_mysql.test Executable file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import sys
import utils
import ido_tests
def main():
run_query = lambda q: utils.run_mysql_query(q, b'/usr/bin/mysql')
if not ido_tests.validate_tables([d['Tables_in_icinga']
for d in run_query('show tables')]):
return 1
host_info = run_query('select * from icinga_hosts')
if not ido_tests.verify_host_config(host_info):
return 1
service_info = run_query(
'select c2.alias, c1.* from icinga_services as c1 '
'inner join icinga_hosts as c2'
' on c1.host_object_id = c2.host_object_id'
)
if not ido_tests.verify_service_config(service_info):
return 1
hostchecks_data = run_query(
'select c.alias, unix_timestamp(s.last_check) as last_check'
' from icinga_hoststatus as s '
'inner join icinga_hosts as c'
' on s.host_object_id = c.host_object_id'
)
if not ido_tests.check_last_host_status_update(hostchecks_data):
return 1
servicechecks_data = run_query(
'select c2.alias, c1.display_name, unix_timestamp(s.last_check) as last_check'
' from icinga_servicestatus as s '
'inner join icinga_services as c1'
' on s.service_object_id = c1.service_object_id '
'inner join icinga_hosts as c2'
' on c1.host_object_id = c2.host_object_id'
)
if not ido_tests.check_last_service_status_update(servicechecks_data):
return 1
logentry_info = run_query(
'select hosts.alias,'
' max(unix_timestamp(logs.entry_time)) as entry_time,'
' max(unix_timestamp(hist.state_time)) as state_time'
' from icinga_logentries as logs '
'inner join icinga_hosts as hosts'
' on logs.object_id = hosts.host_object_id and hosts.alias = "localhost" '
'inner join icinga_statehistory as hist'
' on hist.object_id = hosts.host_object_id and hist.state_type = 1'
)
if not ido_tests.check_logentries(logentry_info):
return 1
return 0
if __name__ == '__main__':
sys.exit(main())

69
test/jenkins/ido_pgsql.test Executable file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import sys
import utils
import ido_tests
def main():
run_query = lambda q: utils.run_pgsql_query(q, b'/usr/bin/psql')
if not ido_tests.validate_tables([d['Name'] for d in run_query('\\dt')
if d['Type'] == 'table']):
return 1
host_info = run_query('select * from icinga_hosts')
if not ido_tests.verify_host_config(host_info):
return 1
service_info = run_query(
'select c2.alias, c1.* from icinga_services as c1 '
'inner join icinga_hosts as c2'
' on c1.host_object_id = c2.host_object_id'
)
if not ido_tests.verify_service_config(service_info):
return 1
hostchecks_data = run_query(
'select c.alias, unix_timestamp(s.last_check) as last_check'
' from icinga_hoststatus as s '
'inner join icinga_hosts as c'
' on s.host_object_id = c.host_object_id'
)
if not ido_tests.check_last_host_status_update(hostchecks_data):
return 1
servicechecks_data = run_query(
'select c2.alias, c1.display_name, unix_timestamp(s.last_check) as last_check'
' from icinga_servicestatus as s '
'inner join icinga_services as c1'
' on s.service_object_id = c1.service_object_id '
'inner join icinga_hosts as c2'
' on c1.host_object_id = c2.host_object_id'
)
if not ido_tests.check_last_service_status_update(servicechecks_data):
return 1
logentry_info = run_query(
'select hosts.alias,'
' max(unix_timestamp(logs.entry_time)) as entry_time,'
' max(unix_timestamp(hist.state_time)) as state_time'
' from icinga_logentries as logs '
'inner join icinga_hosts as hosts'
' on logs.object_id = hosts.host_object_id '
'inner join icinga_statehistory as hist'
' on hist.object_id = hosts.host_object_id '
"where hosts.alias = 'localhost' and hist.state_type = 1 "
'group by hosts.alias'
)
if not ido_tests.check_logentries(logentry_info):
return 1
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,17 @@
#!/bin/sh
if [ ! -e /var/run/icinga2/cmd/livestatus ];
then
sudo icinga2-enable-feature livestatus 1> /dev/null
sudo service icinga2 restart 1> /dev/null
sleep 1
if [ ! -e /var/run/icinga2/cmd/livestatus ];
then
echo "Icinga2 Livestatus socket not found"
exit 1
fi
fi
echo "Icinga2 Livestatus socket found"
exit 0

10
test/jenkins/logfile.test Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
if sudo test -f /var/log/icinga2/icinga2.log;
then
echo "Icinga2 log file found"
exit 0
else
echo "Icinga2 log file not found"
exit 1
fi

3
test/jenkins/mysql_state.test Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
sudo service mysqld status

3
test/jenkins/pgsql_state.test Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
sudo service postgresql status

10
test/jenkins/pidfile.test Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
if [ -f /var/run/icinga2/icinga2.pid ];
then
echo "Icinga2 pidfile found"
exit 0
else
echo "Icinga2 pidfile not found"
exit 1
fi

View File

@ -1,34 +0,0 @@
#!/usr/bin/env python
import sys
from xml.dom.minidom import getDOMImplementation
from subprocess import Popen, PIPE
impl = getDOMImplementation()
result = impl.createDocument(None, "testsuite", None)
testsuite = result.documentElement
for fn in sys.argv[1:]:
process = Popen(["./" + fn], stdout=PIPE, stderr=PIPE)
(stdoutdata, stderrdata) = process.communicate()
testcase = result.createElement("testcase")
testcase.setAttribute("classname", "vm")
testcase.setAttribute("name", fn)
systemout = result.createElement("system-out")
systemout.appendChild(result.createTextNode(stdoutdata))
testcase.appendChild(systemout)
systemerr = result.createElement("system-err")
systemerr.appendChild(result.createTextNode(stderrdata))
testcase.appendChild(systemerr)
if process.returncode != 0:
failure = result.createElement("failure")
failure.setAttribute("type", "returncode")
failure.appendChild(result.createTextNode("code: " + str(process.returncode)))
testcase.appendChild(failure)
testsuite.appendChild(testcase)
print result.toxml()

View File

@ -0,0 +1,60 @@
{
"commands": {
"copy": "scp -qF ssh_config {0} default:{1}",
"exec": "ssh -F ssh_config default '{0}'",
"clean": "ssh -F ssh_config default 'rm -f {0}'"
},
"settings": {
"test_root": "/tmp"
},
"setups": {
"^ido_[a-z]{2}sql.test$": {
"setup": {
"copy": [
"files/ido_tests.py >> /tmp/ido_tests.py",
"files/utils.py >> /tmp/utils.py"
]
},
"teardown": {
"clean": [
"/tmp/ido_tests.py*",
"/tmp/utils.py*"
]
}
},
"checkresult.test": {
"setup": {
"copy": [
"files/configs/checkresult.conf >> /tmp/checkresult.conf",
"files/wait_for_ido.sh >> /tmp/wait_for_ido.sh",
"files/utils.py >> /tmp/utils.py"
],
"exec": [
"sudo mv /tmp/checkresult.conf /etc/icinga2/conf.d/",
"mkdir -p -m 0777 /tmp/icinga2/checkresults",
"sudo service icinga2 restart",
"/tmp/wait_for_ido.sh mysql"
]
},
"teardown": {
"clean": ["/tmp/utils.py*"],
"exec": [
"sudo rm /etc/icinga2/conf.d/checkresult.conf",
"sudo service icinga2 restart",
"rmdir /tmp/icinga2/checkresults",
"/tmp/wait_for_ido.sh mysql",
"/tmp/wait_for_ido.sh pgsql && rm /tmp/wait_for_ido.sh"
]
}
},
"external_commands.test": {
"setup": {
"copy": ["files/utils.py >> /tmp/utils.py"]
},
"teardown": {
"clean": ["/tmp/utils.py*"],
"exec": ["sudo service icinga2 restart"]
}
}
}
}

147
test/jenkins/run_tests.py Executable file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import os
import re
import sys
import json
import glob
import subprocess
from optparse import OptionParser
from xml.dom.minidom import getDOMImplementation
try:
from subprocess import DEVNULL
except ImportError:
DEVNULL = open(os.devnull, 'w')
class TestSuite(object):
def __init__(self, configpath):
self._tests = []
self._results = {}
self.load_config(configpath)
def add_test(self, filepath):
self._tests.append(filepath)
def load_config(self, filepath):
with open(filepath) as f:
self._config = json.load(f)
def get_report(self):
dom = getDOMImplementation()
document = dom.createDocument(None, 'testsuite', None)
xml_root = document.documentElement
for name, info in self._results.iteritems():
testresult = document.createElement('testcase')
testresult.setAttribute('classname', 'vm')
testresult.setAttribute('name', name)
systemout = document.createElement('system-out')
systemout.appendChild(document.createTextNode(info['stdout']))
testresult.appendChild(systemout)
systemerr = document.createElement('system-err')
systemerr.appendChild(document.createTextNode(info['stderr']))
testresult.appendChild(systemerr)
if info['returncode'] != 0:
failure = document.createElement('failure')
failure.setAttribute('type', 'returncode')
failure.appendChild(document.createTextNode(
'code: {0}'.format(info['returncode'])))
testresult.appendChild(failure)
xml_root.appendChild(testresult)
return document.toxml()
def run(self):
for path in self._tests:
test_name = os.path.basename(path)
self._apply_setup_routines(test_name, 'setup')
self._copy_test(path)
self._results[test_name] = self._run_test(path)
self._apply_setup_routines(test_name, 'teardown')
def _apply_setup_routines(self, test_name, context):
instructions = next((t[1].get(context)
for t in self._config.get('setups', {}).iteritems()
if re.match(t[0], test_name)), None)
if instructions is not None:
for instruction in instructions.get('copy', []):
source, _, destination = instruction.partition('>>')
self._copy_file(source.strip(), destination.strip())
for filepath in instructions.get('clean', []):
self._remove_file(filepath)
for command in instructions.get('exec', []):
self._exec_command(command)
def _remove_file(self, path):
command = self._config['commands']['clean'].format(path)
subprocess.call(command, stdout=DEVNULL, shell=True)
def _exec_command(self, command):
command = self._config['commands']['exec'].format(command)
subprocess.call(command, stdout=DEVNULL, shell=True)
def _copy_file(self, source, destination):
command = self._config['commands']['copy'].format(source, destination)
subprocess.call(command, stdout=DEVNULL, shell=True)
def _copy_test(self, path):
self._copy_file(path, os.path.join(self._config['settings']['test_root'],
os.path.basename(path)))
def _run_test(self, path):
command = self._config['commands']['exec']
target = os.path.join(self._config['settings']['test_root'],
os.path.basename(path))
p = subprocess.Popen(command.format(target), stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
out, err = p.communicate()
return {
'stdout': out.decode('utf-8'),
'stderr': err.decode('utf-8'),
'returncode': p.returncode
}
def parse_commandline():
parser = OptionParser(version='0.1')
parser.add_option('-C', '--config', default="run_tests.conf",
help='The path to the config file to use [%default]')
parser.add_option('-O', '--output',
help='The file which to save the test results. '
'(By default this goes to stdout)')
return parser.parse_args()
def main():
options, arguments = parse_commandline()
suite = TestSuite(options.config)
for path in (p for a in arguments for p in glob.glob(a)):
suite.add_test(path)
suite.run()
report = suite.get_report()
if options.output is None:
print report.encode('utf-8')
else:
with open(options.output, 'w') as f:
f.write(report.encode('utf-8'))
return 0
if __name__ == '__main__':
sys.exit(main())

5
test/jenkins/run_tests.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
vagrant ssh-config > ssh_config
./run_tests.py *.test
rm -f ssh_config

51
test/jenkins/statusdata.test Executable file
View File

@ -0,0 +1,51 @@
#!/bin/sh
if [ ! -f /var/cache/icinga2/status.dat ];
then
sudo icinga2-enable-feature statusdata 1> /dev/null
sudo service icinga2 restart 1> /dev/null
n=0
while [ $n -lt 3 ]
do
sleep 15
if [ -f /var/cache/icinga2/status.dat ];
then
break
fi
n=$(( $n + 1))
done
if [ $n -eq 3 ];
then
echo "Icinga2 status.dat not found"
exit 1
fi
fi
echo "Icinga2 status.dat found"
if [ -f /var/cache/icinga2/objects.cache ];
then
echo "Icinga2 objects.cache found"
else
echo "Icinga2 objects.cache not found"
exit 1
fi
status_time=$(stat --format="%Y" /var/cache/icinga2/status.dat)
now=$(date +"%s")
sleep $(((15 + 5) - ($now - $status_time)))
new_status_time=$(stat --format="%Y" /var/cache/icinga2/status.dat)
if [ $new_status_time -eq $status_time ];
then
echo "Icinga2 status.dat is not being updated"
exit 1
else
echo "Icinga2 status.dat is being updated"
fi

View File

@ -1,3 +0,0 @@
#!/bin/sh
echo "Hello World!"
exit 1