diff --git a/rally/cli/commands/task.py b/rally/cli/commands/task.py index 5a5acced..468e6f71 100644 --- a/rally/cli/commands/task.py +++ b/rally/cli/commands/task.py @@ -554,8 +554,8 @@ class TaskCommands(object): """ filters = {} - headers = ["uuid", "deployment_name", "created_at", "duration", - "status", "tags"] + headers = ["UUID", "Deployment name", "Created at", "Load duration", + "Status", "Tag(s)"] if status in consts.TaskStatus: filters["status"] = status @@ -576,20 +576,24 @@ class TaskCommands(object): if uuids_only: if task_list: - cliutils.print_list(task_list, ["uuid"], - print_header=False, - print_border=False) + print("\n".join([t["uuid"] for t in task_list])) elif task_list: def tags_formatter(t): if not t["tags"]: return "" return "'%s'" % "', '".join(t["tags"]) + formatters = { + "Tag(s)": tags_formatter, + "Load duration": cliutils.pretty_float_formatter( + "task_duration", 3), + "Created at": lambda t: t["created_at"].replace("T", " ") + } + cliutils.print_list( - task_list, - headers, - sortby_index=headers.index("created_at"), - formatters={"tags": tags_formatter}) + task_list, fields=headers, normalize_field_names=True, + sortby_index=headers.index("Created at"), + formatters=formatters) else: if status: print(_("There are no tasks in '%s' status. " diff --git a/tests/functional/test_cli_task.py b/tests/functional/test_cli_task.py index 736e2b0c..587192f9 100644 --- a/tests/functional/test_cli_task.py +++ b/tests/functional/test_cli_task.py @@ -22,6 +22,7 @@ import unittest import mock +from rally import api from tests.functional import utils @@ -93,6 +94,11 @@ class TaskTestCase(unittest.TestCase): r"Using deployment: (?P[0-9a-f\-]{36})", output).group("uuid") + def _get_task_uuid(self, output): + return re.search( + r"\trally task results (?P[0-9a-f\-]{36})", + output).group("uuid") + def test_status(self): rally = utils.Rally() cfg = self._get_sample_task_config() @@ -404,9 +410,37 @@ class TaskTestCase(unittest.TestCase): rally = utils.Rally() cfg = self._get_sample_task_config() config = utils.TaskConfig(cfg) - rally("task start --task %s" % config.filename) + output = rally("task start --task %s --tag foo" % config.filename) + task_uuid = self._get_task_uuid(output) + # obtain the task object from the database, to check that CLI prints + # everything right + rapi = api.API(config_file=rally.config_filename) + task = rapi.task.get(task_id=task_uuid) - self.assertIn("finished", rally("task list --deployment MAIN")) + actual = rally("task list --deployment MAIN") + duration = "%s" % round(task["task_duration"], 3) + duration += " " * (13 - len(duration)) + expected = ( + "+--------------------------------------+-----------------+" + "---------------------+---------------+----------+--------+\n" + "| UUID | Deployment name " + "| Created at | Load duration | Status | Tag(s) |\n" + "+--------------------------------------+-----------------+" + "---------------------+---------------+----------+--------+\n" + "| %(uuid)s | MAIN | %(created_at)s " + "| %(duration)s | finished | 'foo' |\n" + "+--------------------------------------+-----------------+" + "---------------------+---------------+----------+--------+\n" % { + "uuid": task_uuid, + "created_at": task["created_at"].replace("T", " "), + "duration": duration}) + + # self.assertEqual is not used here, since it doesn't show a big diff + # and error message become useless + if expected != actual: + self.fail("AssertionError: Expected output is not equal to actual." + "\nExpected:\"\"\"\n%s\n\"\"\"" + "\nActual:\"\"\"\n%s\n\"\"\"" % (expected, actual)) self.assertIn("There are no tasks", rally("task list --status crashed")) @@ -414,7 +448,7 @@ class TaskTestCase(unittest.TestCase): self.assertIn("finished", rally("task list --status finished")) self.assertIn( - "deployment_name", rally("task list --all-deployments")) + "Deployment name", rally("task list --all-deployments")) self.assertRaises(utils.RallyCliError, rally, "task list --status not_existing_status") @@ -428,26 +462,26 @@ class TaskTestCase(unittest.TestCase): self.assertEqual("", rally("task list --uuids-only")) # Validate against a single task - res = rally("task start --task %s" % config.filename) - task_uuids = [] - for line in res.splitlines(): - if "finished" in line: - task_uuids.append(line.split(" ")[1][:-1]) - self.assertGreater(len(task_uuids), 0) - self.assertIn(task_uuids[0], - rally("task list --uuids-only --deployment MAIN")) + res = rally("task start --task %s --tag " % config.filename) + task_uuid = self._get_task_uuid(res) + self.assertEqual( + task_uuid, + rally("task list --uuids-only --deployment MAIN").strip()) + self.assertIn("finished", rally("task status --uuid %s" % task_uuid)) # Validate against multiple tasks + task_uuids = [task_uuid] for i in range(2): - rally("task start --task %s" % config.filename) - self.assertIn("finished", rally("task list --deployment MAIN")) + out = rally("task start --task %s" % config.filename) + task_uuid = self._get_task_uuid(out) + task_uuids.append(task_uuid) + self.assertIn("finished", + rally("task status --uuid %s" % task_uuid)) res = rally("task list --uuids-only --deployment MAIN") - task_uuids = res.split() - self.assertEqual(3, len(task_uuids)) - res = rally("task list --uuids-only --deployment MAIN " - "--status finished") - for uuid in task_uuids: - self.assertIn(uuid, res) + self.assertEqual(set(task_uuids), set(res.strip().split("\n"))) + res2 = rally("task list --uuids-only --deployment MAIN " + "--status finished") + self.assertEqual(res, res2) def test_validate_is_valid(self): rally = utils.Rally() diff --git a/tests/unit/cli/commands/test_task.py b/tests/unit/cli/commands/test_task.py index c626d15b..574eecc3 100644 --- a/tests/unit/cli/commands/test_task.py +++ b/tests/unit/cli/commands/test_task.py @@ -13,9 +13,9 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime as dt import json import os.path +import sys import ddt import mock @@ -775,43 +775,43 @@ class TaskCommandsTestCase(test.TestCase): return_value="123456789") def test_list(self, mock_get_global, mock_print_list): self.fake_api.task.list.return_value = [ - fakes.FakeTask(uuid="a", - created_at=dt.datetime.now(), - updated_at=dt.datetime.now(), - status="c", - tags=["d"], - deployment_name="some_name")] + {"uuid": "a", + "created_at": "2007-01-01T00:00:01", + "updated_at": "2007-01-01T00:00:03", + "status": consts.TaskStatus.RUNNING, + "tags": ["d"], + "deployment_name": "some_name"}] self.task.list(self.fake_api, status="running") self.fake_api.task.list.assert_called_once_with( deployment=mock_get_global.return_value, status=consts.TaskStatus.RUNNING) - headers = ["uuid", "deployment_name", "created_at", "duration", - "status", "tags"] + headers = ["UUID", "Deployment name", "Created at", "Load duration", + "Status", "Tag(s)"] mock_print_list.assert_called_once_with( - self.fake_api.task.list.return_value, headers, - sortby_index=headers.index("created_at"), + self.fake_api.task.list.return_value, fields=headers, + normalize_field_names=True, + sortby_index=headers.index("Created at"), formatters=mock.ANY) - @mock.patch("rally.cli.commands.task.cliutils.print_list") @mock.patch("rally.cli.commands.task.envutils.get_global", return_value="123456789") - def test_list_uuids_only(self, mock_get_global, mock_print_list): + def test_list_uuids_only(self, mock_get_global): self.fake_api.task.list.return_value = [ - fakes.FakeTask(uuid="a", - created_at=dt.datetime.now(), - updated_at=dt.datetime.now(), - status="c", - tag="d", - deployment_name="some_name")] - self.task.list(self.fake_api, status="running", uuids_only=True) + {"uuid": "a", + "created_at": "2007-01-01T00:00:01", + "updated_at": "2007-01-01T00:00:03", + "status": consts.TaskStatus.RUNNING, + "tags": ["d"], + "deployment_name": "some_name"}] + out = six.StringIO() + with mock.patch.object(sys, "stdout", new=out): + self.task.list(self.fake_api, status="running", uuids_only=True) + self.assertEqual("a\n", out.getvalue()) self.fake_api.task.list.assert_called_once_with( deployment=mock_get_global.return_value, status=consts.TaskStatus.RUNNING) - mock_print_list.assert_called_once_with( - self.fake_api.task.list.return_value, ["uuid"], - print_header=False, print_border=False) def test_list_wrong_status(self): self.assertEqual(1, self.task.list(self.fake_api, deployment="fake", @@ -833,18 +833,18 @@ class TaskCommandsTestCase(test.TestCase): return_value="123456789") def test_list_output(self, mock_get_global): self.fake_api.task.list.return_value = [ - fakes.FakeTask(uuid="UUID-1", - created_at="2007-01-01T00:00:01", - duration="0:00:00.000009", - status="init", - tags=[], - deployment_name="some_name"), - fakes.FakeTask(uuid="UUID-2", - created_at="2007-02-01T00:00:01", - duration="0:00:00.000010", - status="finished", - tags=["tag-1", "tag-2"], - deployment_name="some_name")] + {"uuid": "UUID-1", + "created_at": "2007-01-01T00:00:01", + "task_duration": 0.0000009, + "status": consts.TaskStatus.INIT, + "tags": [], + "deployment_name": "some_name"}, + {"uuid": "UUID-2", + "created_at": "2007-02-01T00:00:01", + "task_duration": 123.99992, + "status": consts.TaskStatus.FINISHED, + "tags": ["tag-1", "tag-2"], + "deployment_name": "some_name"}] # It is a hard task to mock default value of function argument, so we # need to apply this workaround @@ -864,17 +864,17 @@ class TaskCommandsTestCase(test.TestCase): self.assertEqual( "+--------+-----------------+---------------------" - "+----------------+----------+------------------+\n" - "| uuid | deployment_name | created_at " - "| duration | status | tags |\n" + "+---------------+----------+------------------+\n" + "| UUID | Deployment name | Created at " + "| Load duration | Status | Tag(s) |\n" "+--------+-----------------+---------------------" - "+----------------+----------+------------------+\n" - "| UUID-1 | some_name | 2007-01-01T00:00:01 " - "| 0:00:00.000009 | init | |\n" - "| UUID-2 | some_name | 2007-02-01T00:00:01 " - "| 0:00:00.000010 | finished | 'tag-1', 'tag-2' |\n" + "+---------------+----------+------------------+\n" + "| UUID-1 | some_name | 2007-01-01 00:00:01 " + "| 0.0 | init | |\n" + "| UUID-2 | some_name | 2007-02-01 00:00:01 " + "| 124.0 | finished | 'tag-1', 'tag-2' |\n" "+--------+-----------------+---------------------" - "+----------------+----------+------------------+\n", + "+---------------+----------+------------------+\n", print_list_calls[0].getvalue()) def test_delete(self):