Import tempest results into Rally database

Add a new subcommand to the `verify` command to import tempest results
into an existing deployment in the Rally database. `verify import`
will read a tempest log in subunit format, and import it into the
current deployment (or the one specified in the command line)

The command should be called as

  $ rally verify import --file [log_file] --deployment [uuid]

This version of the patch will require a normal deployment to be
created beforehand.  Also, the log_file needs to be a tempest log in
subunit format; `--file` parameter is required.

Apart from `--file` and `--deployment` parameters, this command
understand `--set-name` and `--no-use` from the `start`
command. `--set-name` can be used to attach a name or a small
description to the tempest result, and `--no-use` will mark the new
verification object as a no-current. So, for example, if we want to
assign a name to the tempest result we can use:

  $ rally verify import --file [log_file] --set-name [name] \
          --deployment [uuid]

Implements: blueprint verification-import

Change-Id: I65194a2f456106fa5731a13f53d5985971aad43a
This commit is contained in:
Alberto Planas 2015-06-17 13:52:32 +02:00
parent 592a4b6cc0
commit fd245dbd60
7 changed files with 112 additions and 4 deletions

View File

@ -49,6 +49,7 @@ _rally()
OPTS["verify_compare"]="--uuid-1 --uuid-2 --csv --html --json --output-file --threshold"
OPTS["verify_detailed"]="--uuid --sort-by"
OPTS["verify_genconfig"]="--deployment --tempest-config --override"
OPTS["verify_import"]="--deployment --set-name --file --no-use"
OPTS["verify_install"]="--deployment --source"
OPTS["verify_list"]=""
OPTS["verify_reinstall"]="--deployment --tempest-config --source"

View File

@ -333,6 +333,29 @@ class Verification(object):
return verifier
@classmethod
def import_file(cls, deployment, set_name, log_file=None):
"""Import tempest log.
:param deployment: UUID or name of a deployment.
:param log_file: User specified Tempest log file name.
:returns: Deployment and verification objects
"""
# TODO(aplanas): Create an external deployment if this is
# missing, as required in the blueprint [1].
# [1] https://blueprints.launchpad.net/rally/+spec/verification-import
deployment_uuid = objects.Deployment.get(deployment)["uuid"]
verification = objects.Verification(deployment_uuid=deployment_uuid)
verifier = tempest.Tempest(deployment_uuid, verification=verification)
LOG.info("Importing verification of deployment: %s" % deployment_uuid)
verification.set_running()
verifier.import_file(set_name=set_name, log_file=log_file)
return deployment, verification
@classmethod
def install_tempest(cls, deployment, source=None):
"""Install Tempest.

View File

@ -89,6 +89,36 @@ class VerifyCommands(object):
if do_use:
self.use(verification["uuid"])
@cliutils.args("--deployment", dest="deployment", type=str,
required=False, help="UUID or name of a deployment.")
@cliutils.args("--set-name", dest="set_name", type=str, required=False,
help="Name of tempest test set. Available sets: %s" % ", ".
join(list(consts.TempestTestsSets) +
list(consts.TempestTestsAPI)))
@cliutils.args("--file", dest="log_file", type=str,
required=True,
help="User specified Tempest log file location")
@cliutils.args("--no-use", action="store_false", dest="do_use",
required=False,
help="Don't set new task as default for future operations")
@cliutils.alias("import")
def import_file(self, deployment=None, set_name=None, log_file=None,
do_use=True):
"""Import a tempest result into rally.
:param deployment: UUID or name of a deployment
:param set_name: Name of tempest test set
:param do_use: Use new task as default for future operations
:param log_file: User specified Tempest log file
"""
deployment, verification = api.Verification.import_file(deployment,
set_name,
log_file)
if do_use:
self.use(verification["uuid"])
def list(self):
"""Display all verifications table, started and finished."""

View File

@ -381,8 +381,8 @@ class Tempest(object):
@utils.log_verification_wrapper(
LOG.info, _("Saving verification results."))
def _save_results(self):
total, test_cases = self.parse_results()
def _save_results(self, log_file=None):
total, test_cases = self.parse_results(log_file)
if total and test_cases and self.verification:
self.verification.finish_verification(total=total,
test_cases=test_cases)
@ -392,3 +392,10 @@ class Tempest(object):
def verify(self, set_name, regex):
self._prepare_and_run(set_name, regex)
self._save_results()
def import_file(self, set_name, log_file):
if log_file:
self.verification.start_verifying(set_name)
self._save_results(log_file)
else:
LOG.error("No import file specified.")

View File

@ -94,6 +94,29 @@ class VerifyCommandsTestCase(test.TestCase):
consts.TempestTestsAPI)
self.assertFalse(mock_verification_verify.called)
@mock.patch("rally.api.Verification.import_file")
def test_import_file(self, mock_verification_import_file):
deployment_id = "fake_uuid"
mock_verification_import_file.return_value = (None, None)
self.verify.import_file(deployment=deployment_id, do_use=False)
default_set_name = None
default_log_file = None
mock_verification_import_file.assert_called_once_with(
deployment_id, default_set_name, default_log_file)
@mock.patch("rally.api.Verification.import_file")
def test_import_file_without_defaults(self, mock_verification_import_file):
deployment_id = "fake_uuid"
set_name = "fake_set_name"
log_file = "fake_log_file"
mock_verification_import_file.return_value = (None, None)
self.verify.import_file(deployment=deployment_id, set_name=set_name,
log_file=log_file, do_use=False)
mock_verification_import_file.assert_called_once_with(
deployment_id, set_name, log_file)
@mock.patch("rally.cli.cliutils.print_list")
@mock.patch("rally.common.db.verification_list")
def test_list(self, mock_common_db_verification_list, mock_print_list):

View File

@ -352,6 +352,20 @@ class VerificationAPITestCase(BaseDeploymentTestCase):
self.tempest.verify.assert_called_once_with(set_name="smoke",
regex=None)
@mock.patch("rally.common.objects.Deployment.get")
@mock.patch("rally.api.objects.Verification")
@mock.patch("rally.verification.tempest.tempest.Tempest")
def test_import_file(self, mock_tempest, mock_verification,
mock_deployment_get):
mock_deployment_get.return_value = {"uuid": self.deployment_uuid}
mock_tempest.return_value = self.tempest
self.tempest.is_installed.return_value = True
api.Verification.import_file(self.deployment_uuid, "smoke", "log_file")
self.tempest.import_file.assert_called_once_with(
set_name="smoke", log_file="log_file")
@mock.patch("rally.api.objects.Deployment.get")
@mock.patch("rally.api.tempest.Tempest")
def test_install_tempest(self, mock_tempest, mock_deployment_get):

View File

@ -362,7 +362,7 @@ class TempestVerifyTestCase(BaseTestCase):
mock_subprocess.check_call.assert_called_once_with(
fake_call, env=mock_tempest_env, cwd=self.verifier.path(),
shell=True)
mock_tempest_parse_results.assert_called_once_with()
mock_tempest_parse_results.assert_called_once_with(None)
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.parse_results",
return_value=(None, None))
@ -388,7 +388,7 @@ class TempestVerifyTestCase(BaseTestCase):
mock_subprocess.check_call.assert_called_once_with(
fake_call, env=mock_tempest_env, cwd=self.verifier.path(),
shell=True)
mock_tempest_parse_results.assert_called_once_with()
mock_tempest_parse_results.assert_called_once_with(None)
@mock.patch(TEMPEST_PATH + ".tempest.Tempest.parse_results",
return_value=(None, None))
@ -417,3 +417,13 @@ class TempestVerifyTestCase(BaseTestCase):
shell=True)
self.assertTrue(mock_tempest_parse_results.called)
self.verifier.verification.set_failed.assert_called_once_with()
def test_import_file(self):
set_name = "identity"
log_file = "log_file"
self.verifier._save_results = mock.Mock()
self.verifier.import_file(set_name, log_file)
mock_start_verifying = self.verifier.verification.start_verifying
mock_start_verifying.assert_called_once_with(set_name)
self.verifier._save_results.assert_called_once_with(log_file)