Add basic tools for integration tests

Add class for represent task config
Add integration tests for rally SLA
Generate html test results

Change-Id: Ifc77d1efad1456df0325fcb0d0d9dca0d9b46866
This commit is contained in:
Sergey Skripnick 2014-06-26 20:55:44 +03:00
parent d6830e8310
commit 98d7946e3c
3 changed files with 97 additions and 16 deletions

12
tests_ci/rally-integrated.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh -ex
env
mkdir -p .testrepository
python -m subunit.run discover tests_ci > .testrepository/subunit.log
EXIT_CODE=$?
subunit2pyunit < .testrepository/subunit.log
subunit-stats < .testrepository/subunit.log
exit $EXIT_CODE

View File

@ -14,7 +14,9 @@
# under the License. # under the License.
import ConfigParser import ConfigParser
import json
import os import os
import pwd
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
@ -22,7 +24,6 @@ import unittest
import mock import mock
"""Test rally command line interface. """Test rally command line interface.
This module is intended for running by OpenStack CI system. This module is intended for running by OpenStack CI system.
@ -32,7 +33,6 @@ To start tests manually please use
""" """
TEST_ENV = { TEST_ENV = {
"OS_USERNAME": "admin", "OS_USERNAME": "admin",
"OS_PASSWORD": "admin", "OS_PASSWORD": "admin",
@ -54,6 +54,18 @@ class RallyCmdError(Exception):
return "Code: %d Output: %s\n" % (self.code, self.output) return "Code: %d Output: %s\n" % (self.code, self.output)
class TaskConfig(object):
def __init__(self, config):
config_file = tempfile.NamedTemporaryFile(delete=False)
config_file.write(json.dumps(config))
config_file.close()
self.filename = config_file.name
def __del__(self):
os.unlink(self.filename)
class Rally(object): class Rally(object):
"""Create and represent separate rally installation. """Create and represent separate rally installation.
@ -66,26 +78,35 @@ class Rally(object):
""" """
def __init__(self): def __init__(self):
# NOTE(sskripnick): we shoud change home dir to avoid races
# and do not touch any user files in ~/.rally
os.environ["HOME"] = pwd.getpwuid(os.getuid()).pw_dir
subprocess.call("rally deployment config > /tmp/.rd.json", shell=True)
self.tmp_dir = tempfile.mkdtemp() self.tmp_dir = tempfile.mkdtemp()
config_filename = os.path.join(self.tmp_dir, 'conf') os.environ["HOME"] = self.tmp_dir
config_filename = os.path.join(self.tmp_dir, "conf")
config = ConfigParser.RawConfigParser() config = ConfigParser.RawConfigParser()
config.add_section('database') config.add_section("database")
config.set('database', 'connection', 'sqlite:///%s/db' % self.tmp_dir) config.set("database", "connection", "sqlite:///%s/db" % self.tmp_dir)
with open(config_filename, 'wb') as conf: with open(config_filename, "wb") as conf:
config.write(conf) config.write(conf)
self.args = ['rally', '-d', '-v', '--config-file', config_filename] self.args = ["rally", "--config-file", config_filename]
subprocess.call(['rally-manage', '--config-file', config_filename, subprocess.call(["rally-manage", "--config-file", config_filename,
'db', 'recreate']) "db", "recreate"])
self("deployment create --file /tmp/.rd.json --name MAIN")
def __del__(self): def __del__(self):
shutil.rmtree(self.tmp_dir) shutil.rmtree(self.tmp_dir)
def __call__(self, cmd): def __call__(self, cmd, getjson=False):
if not isinstance(cmd, list): if not isinstance(cmd, list):
cmd = cmd.split(" ") cmd = cmd.split(" ")
try: try:
return subprocess.check_output(self.args + cmd, output = subprocess.check_output(self.args + cmd,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
if getjson:
return json.loads(output)
return output
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
raise RallyCmdError(e.returncode, e.output) raise RallyCmdError(e.returncode, e.output)
@ -94,7 +115,54 @@ class DeploymentTestCase(unittest.TestCase):
def test_create_fromenv_list_endpoint(self): def test_create_fromenv_list_endpoint(self):
rally = Rally() rally = Rally()
with mock.patch.dict('os.environ', TEST_ENV): with mock.patch.dict("os.environ", TEST_ENV):
rally("deployment create --name t_create --fromenv") rally("deployment create --name t_create --fromenv")
self.assertIn('t_create', rally("deployment list")) self.assertIn("t_create", rally("deployment list"))
self.assertIn(TEST_ENV['OS_AUTH_URL'], rally("deployment endpoint")) self.assertIn(TEST_ENV["OS_AUTH_URL"], rally("deployment endpoint"))
class SLATestCase(unittest.TestCase):
def _get_sample_task_config(self, max_seconds_per_iteration=4,
max_failure_percent=0):
return {
"KeystoneBasic.create_and_list_users": [
{
"args": {
"name_length": 10
},
"runner": {
"type": "constant",
"times": 5,
"concurrency": 5
},
"sla": {
"max_seconds_per_iteration": max_seconds_per_iteration,
"max_failure_percent": max_failure_percent,
}
}
]
}
def test_sla_fail(self):
rally = Rally()
cfg = self._get_sample_task_config(max_seconds_per_iteration=0.001)
config = TaskConfig(cfg)
rally("task start --task %s" % config.filename)
self.assertRaises(RallyCmdError, rally, "task sla_check")
def test_sla_success(self):
rally = Rally()
config = TaskConfig(self._get_sample_task_config())
rally("task start --task %s" % config.filename)
rally("task sla_check")
expected = [
{"benchmark": "KeystoneBasic.create_and_list_users",
"criterion": "max_seconds_per_iteration",
"pos": 0, "success": True},
{"benchmark": "KeystoneBasic.create_and_list_users",
"criterion": "max_failure_percent",
"pos": 0, "success": True},
]
data = rally("task sla_check --json", getjson=True)
self.assertEqual(expected, data)

View File

@ -23,7 +23,8 @@ distribute = false
commands = {posargs} commands = {posargs}
[testenv:cli] [testenv:cli]
commands = python -m unittest tests_ci.test_cli sitepackages = True
commands = {toxinidir}/tests_ci/rally-integrated.sh
[testenv:cover] [testenv:cover]
commands = python setup.py testr --coverage --testr-args='{posargs}' commands = python setup.py testr --coverage --testr-args='{posargs}'