class CliUtilsTestCase(test.TestCase): def setUp(self): super(CliUtilsTestCase, self).setUp() self.categories = { "deployment": deployment.DeploymentCommands, "task": task.TaskCommands, "verify": verify.VerifyCommands } def tearDown(self): self._unregister_opts() super(CliUtilsTestCase, self).tearDown() def test_print_dict(self): out = six.StringIO() dict = {"key": "value"} cliutils.print_dict(dict, out=out) self.assertEqual( "+----------+-------+\n" "| Property | Value |\n" "+----------+-------+\n" "| key | value |\n" "+----------+-------+\n", out.getvalue()) def test_print_dict_wrap(self): out = six.StringIO() dict = {"key1": "not wrapped", "key2": "this will be wrapped"} cliutils.print_dict(dict, wrap=16, out=out) self.assertEqual( "+----------+--------------+\n" "| Property | Value |\n" "+----------+--------------+\n" "| key1 | not wrapped |\n" "| key2 | this will be |\n" "| | wrapped |\n" "+----------+--------------+\n", out.getvalue()) def test_print_dict_formatters_and_fields(self): out = six.StringIO() dict = {"key1": "value", "key2": "Value", "key3": "vvv"} formatters = {"foo": lambda x: x["key1"], "bar": lambda x: x["key2"]} fields = ["foo", "bar"] cliutils.print_dict(dict, formatters=formatters, fields=fields, out=out) self.assertEqual( "+----------+-------+\n" "| Property | Value |\n" "+----------+-------+\n" "| foo | value |\n" "| bar | Value |\n" "+----------+-------+\n", out.getvalue()) def test_print_dict_header(self): out = six.StringIO() dict = {"key": "value"} cliutils.print_dict(dict, table_label="Some Table", print_header=False, out=out) self.assertEqual( "+-------------+\n" "| Some Table |\n" "+-----+-------+\n" "| key | value |\n" "+-----+-------+\n", out.getvalue()) def test_print_dict_objects(self): class SomeStruct(object): def __init__(self, a, b): self.a = a self.b = b @property def c(self): return self.a + self.b def foo(self): pass @classmethod def bar(cls): pass @staticmethod def foobar(): pass out = six.StringIO() formatters = {"c": lambda x: "a + b = %s" % x.c} cliutils.print_dict(SomeStruct(1, 2), formatters=formatters, out=out) self.assertEqual( "+----------+-----------+\n" "| Property | Value |\n" "+----------+-----------+\n" "| a | 1 |\n" "| b | 2 |\n" "| c | a + b = 3 |\n" "+----------+-----------+\n", out.getvalue()) def test_print_dict_with_spec_chars(self): out = six.StringIO() dict = {"key": "line1\r\nline2"} cliutils.print_dict(dict, out=out) self.assertEqual( "+----------+-------+\n" "| Property | Value |\n" "+----------+-------+\n" "| key | line1 |\n" "| | line2 |\n" "+----------+-------+\n", out.getvalue()) def test_make_header(self): h1 = cliutils.make_header("msg", size=4, symbol="=") self.assertEqual("====\nmsg\n====\n", h1) def test_make_table_header(self): actual = cliutils.make_table_header("Response Times (sec)", 40) expected = "\n".join(( "+--------------------------------------+", "| Response Times (sec) |", )) self.assertEqual(expected, actual) actual = cliutils.make_table_header("Response Times (sec)", 39) expected = "\n".join(( "+-------------------------------------+", "| Response Times (sec) |", )) self.assertEqual(expected, actual) self.assertRaises(ValueError, cliutils.make_table_header, "Response Times (sec)", len("Response Times (sec)")) @ddt.data( { "obj": mock.Mock(foo=6.56565), "args": ["foo", 3], "expected": 6.566 }, { "obj": mock.Mock(foo=6.56565), "args": ["foo"], "expected": 6.56565 }, { "obj": mock.Mock(foo=None), "args": ["foo"], "expected": "n/a" }, { "obj": mock.Mock(foo="n/a"), "args": ["foo"], "expected": "n/a" }, { "obj": mock.Mock(foo="n/a"), "args": ["foo", 3], "expected": "n/a" }, { "obj": { "foo": 6.56565 }, "args": ["foo", 3], "expected": 6.566 }, { "obj": { "foo": 6.56565 }, "args": ["foo"], "expected": 6.56565 }, { "obj": { "foo": None }, "args": ["foo"], "expected": "n/a" }, { "obj": { "foo": "n/a" }, "args": ["foo"], "expected": "n/a" }, { "obj": { "foo": "n/a" }, "args": ["foo", 3], "expected": "n/a" }, { "obj": object, "args": ["unexpected_field", 3], "expected": AttributeError }, { "obj": { "foo": 42 }, "args": ["unexpected_field", 3], "expected": KeyError }) @ddt.unpack def test_pretty_float_formatter(self, obj, args, expected=None): formatter = cliutils.pretty_float_formatter(*args) if type(expected) == type and issubclass(expected, Exception): self.assertRaises(expected, formatter, obj) else: self.assertEqual(expected, formatter(obj)) def test__methods_of_with_class(self): class fake_class(object): def public(self): pass def _private(self): pass result = cliutils._methods_of(fake_class) self.assertEqual(1, len(result)) self.assertEqual("public", result[0][0]) def test__methods_of_with_object(self): class fake_class(object): def public(self): pass def _private(self): pass mock_obj = fake_class() result = cliutils._methods_of(mock_obj) self.assertEqual(1, len(result)) self.assertEqual("public", result[0][0]) def test__methods_of_empty_result(self): class fake_class(object): def _private(self): pass def _private2(self): pass mock_obj = fake_class() result = cliutils._methods_of(mock_obj) self.assertEqual([], result) def _unregister_opts(self): CONF.reset() category_opt = cfg.SubCommandOpt("category", title="Command categories", help="Available categories") CONF.unregister_opt(category_opt) @mock.patch("rally.api.API", side_effect=exceptions.RallyException("config_file")) def test_run_fails(self, mock_rally_api_api): ret = cliutils.run(["rally", "task list"], self.categories) self.assertEqual(2, ret) mock_rally_api_api.assert_called_once_with(config_args=["task list"], skip_db_check=True) @mock.patch("rally.api.API.check_db_revision") def test_run_version(self, mock_api_check_db_revision): ret = cliutils.run(["rally", "version"], self.categories) self.assertEqual(0, ret) @mock.patch("rally.api.API.check_db_revision") def test_run_bash_completion(self, mock_api_check_db_revision): ret = cliutils.run(["rally", "bash-completion"], self.categories) self.assertEqual(0, ret) @mock.patch("rally.api.API.check_db_revision") @mock.patch("rally.common.db.api.task_get", side_effect=exceptions.DBRecordNotFound(criteria="uuid: %s" % FAKE_TASK_UUID, table="tasks")) def test_run_task_not_found(self, mock_task_get, mock_api_check_db_revision): ret = cliutils.run(["rally", "task", "status", "%s" % FAKE_TASK_UUID], self.categories) self.assertTrue(mock_task_get.called) self.assertEqual(203, ret) @mock.patch("rally.api.API.check_db_revision") @mock.patch("rally.cli.cliutils.validate_args", side_effect=cliutils.MissingArgs("missing")) def test_run_task_failed(self, mock_validate_args, mock_api_check_db_revision): ret = cliutils.run(["rally", "task", "status", "%s" % FAKE_TASK_UUID], self.categories) self.assertTrue(mock_validate_args.called) self.assertEqual(1, ret) @mock.patch("rally.api.API.check_db_revision") def test_run_failed_to_open_file(self, mock_api_check_db_revision): class FailuresCommands(object): def failed_to_open_file(self): raise IOError("No such file") ret = cliutils.run(["rally", "failure", "failed-to-open-file"], {"failure": FailuresCommands}) self.assertEqual(1, ret) @mock.patch("rally.api.API.check_db_revision") def test_run_sqlalchmey_operational_failure(self, mock_api_check_db_revision): class SQLAlchemyCommands(object): def operational_failure(self): raise sqlalchemy.exc.OperationalError("Can't open DB file") ret = cliutils.run(["rally", "failure", "operational-failure"], {"failure": SQLAlchemyCommands}) self.assertEqual(1, ret) class TestObj(object): x = 1 y = 2 z = 3.142857142857143 aOrB = 3 # mixed case field @ddt.data( { "args": [[TestObj()], ["x", "y"]], "kwargs": { "print_header": True, "print_border": True, "sortby_index": None }, "expected": ("+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+") }, { "args": [[TestObj()], ["z"]], "kwargs": { "print_header": True, "print_border": True, "sortby_index": None, "formatters": { "z": cliutils.pretty_float_formatter("z", 5) } }, "expected": ("+---------+\n" "| z |\n" "+---------+\n" "| 3.14286 |\n" "+---------+") }, { "args": [[TestObj()], ["x"]], "kwargs": { "print_header": True, "print_border": True }, "expected": ("+---+\n" "| x |\n" "+---+\n" "| 1 |\n" "+---+") }, { "args": [[TestObj()], ["x", "y"]], "kwargs": { "print_header": True, "print_border": True }, "expected": ("+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+") }, { "args": [[TestObj()], ["x"]], "kwargs": { "print_header": False, "print_border": False }, "expected": "1" }, { "args": [[TestObj()], ["x", "y"]], "kwargs": { "print_header": False, "print_border": False }, "expected": "1 2" }, { "args": [[TestObj()], ["x"]], "kwargs": { "print_header": True, "print_border": False }, "expected": "x \n1" }, { "args": [[TestObj()], ["x", "y"]], "kwargs": { "print_header": True, "print_border": False }, "expected": "x y \n1 2" }, { "args": [[TestObj()], ["x"]], "kwargs": { "print_header": False, "print_border": True }, "expected": ("+--+\n" "|1 |\n" "+--+") }, { "args": [[TestObj()], ["x", "y"]], "kwargs": { "print_header": False, "print_border": True }, "expected": ("+--+--+\n" "|1 |2 |\n" "+--+--+") }, { "args": [[TestObj()], ["aOrB"]], "kwargs": { "print_header": True, "print_border": True, "mixed_case_fields": ["aOrB"] }, "expected": ("+------+\n" "| aOrB |\n" "+------+\n" "| 3 |\n" "+------+") }, { "args": [[TestObj()], ["aOrB"]], "kwargs": { "print_header": False, "print_border": True, "mixed_case_fields": ["aOrB"] }, "expected": ("+--+\n" "|3 |\n" "+--+") }, { "args": [[TestObj()], ["aOrB"]], "kwargs": { "print_header": True, "print_border": False, "mixed_case_fields": ["aOrB"] }, "expected": "aOrB \n3" }, { "args": [[TestObj()], ["aOrB"]], "kwargs": { "print_header": False, "print_border": False, "mixed_case_fields": ["aOrB"] }, "expected": "3" }, { "args": [[{ "x": 1, "y": 2 }], ["x", "y"]], "kwargs": { "print_header": True, "print_border": True, "sortby_index": None }, "expected": ("+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+") }, { "args": [[{ "z": 3.142857142857143 }], ["z"]], "kwargs": { "print_header": True, "print_border": True, "sortby_index": None, "formatters": { "z": cliutils.pretty_float_formatter("z", 5) } }, "expected": ("+---------+\n" "| z |\n" "+---------+\n" "| 3.14286 |\n" "+---------+") }, { "args": [[{ "x": 1 }], ["x"]], "kwargs": { "print_header": True, "print_border": True }, "expected": ("+---+\n" "| x |\n" "+---+\n" "| 1 |\n" "+---+") }, { "args": [[{ "x": 1, "y": 2 }], ["x", "y"]], "kwargs": { "print_header": True, "print_border": True }, "expected": ("+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+") }) @ddt.unpack def test_print_list(self, args, kwargs, expected): out = six.moves.StringIO() kwargs["out"] = out cliutils.print_list(*args, **kwargs) self.assertEqual(expected, out.getvalue().strip()) def test_print_list_raises(self): out = six.moves.StringIO() self.assertRaisesRegex(ValueError, "Field labels list.*has different number " "of elements than fields list", cliutils.print_list, [self.TestObj()], ["x"], field_labels=["x", "y"], sortby_index=None, out=out) def test_help_for_grouped_methods(self): class SomeCommand(object): @cliutils.help_group("1_manage") def install(self): pass @cliutils.help_group("1_manage") def uninstall(self): pass @cliutils.help_group("1_manage") def reinstall(self): pass @cliutils.help_group("2_launch") def run(self): pass @cliutils.help_group("2_launch") def rerun(self): pass @cliutils.help_group("3_results") def show(self): pass @cliutils.help_group("3_results") def list(self): pass def do_do_has_do_has_mesh(self): pass self.assertEqual( "\n\nCommands:\n" " do-do-has-do-has-mesh \n" "\n" " install \n" " reinstall \n" " uninstall \n" "\n" " rerun \n" " run \n" "\n" " list \n" " show \n", cliutils._compose_category_description(SomeCommand))
class CliUtilsTestCase(test.TestCase): def setUp(self): super(CliUtilsTestCase, self).setUp() self.categories = { "deployment": deployment.DeploymentCommands, "show": show.ShowCommands, "task": task.TaskCommands, "verify": verify.VerifyCommands } def tearDown(self): self._unregister_opts() super(CliUtilsTestCase, self).tearDown() @mock.patch("rally.cli.cliutils.os.path") def test_find_config_files(self, mock_os_path): mock_os_path.expanduser.return_value = "expanduser" mock_os_path.abspath.return_value = "abspath" mock_os_path.isfile.return_value = True result = cliutils.find_config_files(["path1", "path2"]) mock_os_path.expanduser.assert_called_once_with("path1") mock_os_path.abspath.assert_called_once_with( mock_os_path.expanduser.return_value) mock_os_path.isfile.assert_called_once_with( mock_os_path.abspath.return_value + "/rally.conf") self.assertEqual([mock_os_path.abspath.return_value + "/rally.conf"], result) mock_os_path.isfile.return_value = False result = cliutils.find_config_files(["path1", "path2"]) self.assertIsNone(result) def test_make_header(self): h1 = cliutils.make_header("msg", size=4, symbol="=") self.assertEqual(h1, "====\n msg\n====\n") def test_make_table_header(self): actual = cliutils.make_table_header("Response Times (sec)", 40) expected = "\n".join(( "+--------------------------------------+", "| Response Times (sec) |", )) self.assertEqual(expected, actual) actual = cliutils.make_table_header("Response Times (sec)", 39) expected = "\n".join(( "+-------------------------------------+", "| Response Times (sec) |", )) self.assertEqual(expected, actual) self.assertRaises(ValueError, cliutils.make_table_header, "Response Times (sec)", len("Response Times (sec)")) def test_pretty_float_formatter_rounding(self): test_table_rows = {"test_header": 6.56565} self.__dict__.update(**test_table_rows) formatter = cliutils.pretty_float_formatter("test_header", 3) return_value = formatter(self) self.assertEqual(return_value, 6.566) def test_pretty_float_formatter_nonrounding(self): test_table_rows = {"test_header": 6.56565} self.__dict__.update(**test_table_rows) formatter = cliutils.pretty_float_formatter("test_header") return_value = formatter(self) self.assertEqual(return_value, 6.56565) def test_pretty_float_formatter_none_value(self): test_table_rows = {"test_header": None} self.__dict__.update(**test_table_rows) formatter = cliutils.pretty_float_formatter("test_header") return_value = formatter(self) self.assertEqual(return_value, "n/a") def test_process_keyestone_exc(self): @cliutils.process_keystone_exc def a(a): if a == 1: raise keystone_exc.Unauthorized() if a == 2: raise keystone_exc.AuthorizationFailure() if a == 3: raise keystone_exc.ConnectionRefused() return a self.assertEqual(1, a(1)) self.assertEqual(1, a(2)) self.assertEqual(1, a(3)) self.assertEqual(4, a(4)) def test__methods_of_with_class(self): class fake_class(object): def public(self): pass def _private(self): pass result = cliutils._methods_of(fake_class) self.assertEqual(1, len(result)) self.assertEqual("public", result[0][0]) def test__methods_of_with_object(self): class fake_class(object): def public(self): pass def _private(self): pass mock_obj = fake_class() result = cliutils._methods_of(mock_obj) self.assertEqual(1, len(result)) self.assertEqual("public", result[0][0]) def test__methods_of_empty_result(self): class fake_class(object): def _private(self): pass def _private2(self): pass mock_obj = fake_class() result = cliutils._methods_of(mock_obj) self.assertEqual(result, []) def _unregister_opts(self): CONF.reset() category_opt = cfg.SubCommandOpt("category", title="Command categories", help="Available categories") CONF.unregister_opt(category_opt) @mock.patch("rally.cli.cliutils.CONF", config_file=None, side_effect=cfg.ConfigFilesNotFoundError("config_file")) def test_run_fails(self, mock_cliutils_conf): ret = cliutils.run(["rally", "show", "flavors"], self.categories) self.assertEqual(ret, 2) def test_run_version(self): ret = cliutils.run(["rally", "version"], self.categories) self.assertEqual(ret, 0) def test_run_bash_completion(self): ret = cliutils.run(["rally", "bash-completion"], self.categories) self.assertEqual(ret, 0) def test_run_show(self): ret = cliutils.run(["rally", "show", "keypairs"], self.categories) self.assertEqual(ret, 1) @mock.patch("rally.common.db.task_get", side_effect=exceptions.TaskNotFound(uuid=FAKE_TASK_UUID)) def test_run_task_not_found(self, mock_task_get): ret = cliutils.run(["rally", "task", "status", "%s" % FAKE_TASK_UUID], self.categories) self.assertTrue(mock_task_get.called) self.assertEqual(ret, 1) @mock.patch("rally.cli.cliutils.validate_args", side_effect=cliutils.MissingArgs("missing")) def test_run_show_fails(self, mock_validate_args): ret = cliutils.run(["rally", "show", "keypairs"], self.categories) self.assertTrue(mock_validate_args.called) self.assertEqual(ret, 1) def test_run_failed_to_open_file(self): class FailuresCommands(object): def failed_to_open_file(self): raise IOError("No such file") ret = cliutils.run(["rally", "failure", "failed_to_open_file"], {"failure": FailuresCommands}) self.assertEqual(1, ret) def test_run_sqlalchmey_operational_failure(self): class SQLAlchemyCommands(object): def operational_failure(self): raise sqlalchemy.exc.OperationalError("Can't open DB file") ret = cliutils.run(["rally", "failure", "operational_failure"], {"failure": SQLAlchemyCommands}) self.assertEqual(1, ret) def test_print_list(self): class TestObj(object): x = 1 y = 2 z = 3.142857142857143 aOrB = 3 # mixed case field out = moves.StringIO() cliutils.print_list([TestObj()], ["x", "y"], print_header=True, print_border=True, sortby_index=None, out=out) self.assertEqual( "+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+", out.getvalue().strip()) out = moves.StringIO() formatter = cliutils.pretty_float_formatter("z", 5) cliutils.print_list([TestObj()], ["z"], print_header=True, print_border=True, sortby_index=None, formatters={"z": formatter}, out=out) self.assertEqual( "+---------+\n" "| z |\n" "+---------+\n" "| 3.14286 |\n" "+---------+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x"], print_header=True, print_border=True, out=out) self.assertEqual("+---+\n" "| x |\n" "+---+\n" "| 1 |\n" "+---+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x", "y"], print_header=True, print_border=True, out=out) self.assertEqual( "+---+---+\n" "| x | y |\n" "+---+---+\n" "| 1 | 2 |\n" "+---+---+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x"], print_header=False, print_border=False, out=out) self.assertEqual("1", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x", "y"], print_header=False, print_border=False, out=out) self.assertEqual("1 2", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x"], print_header=True, print_border=False, out=out) self.assertEqual("x \n1", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x", "y"], print_header=True, print_border=False, out=out) self.assertEqual("x y \n1 2", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x"], print_header=False, print_border=True, out=out) self.assertEqual("+--+\n" "|1 |\n" "+--+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["x", "y"], print_header=False, print_border=True, out=out) self.assertEqual("+--+--+\n" "|1 |2 |\n" "+--+--+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["aOrB"], mixed_case_fields=["aOrB"], print_header=True, print_border=True, out=out) self.assertEqual( "+------+\n" "| aOrB |\n" "+------+\n" "| 3 |\n" "+------+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["aOrB"], mixed_case_fields=["aOrB"], print_header=False, print_border=True, out=out) self.assertEqual("+--+\n" "|3 |\n" "+--+", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["aOrB"], mixed_case_fields=["aOrB"], print_header=True, print_border=False, out=out) self.assertEqual("aOrB \n" "3", out.getvalue().strip()) out = moves.StringIO() cliutils.print_list([TestObj()], ["aOrB"], mixed_case_fields=["aOrB"], print_header=False, print_border=False, out=out) self.assertEqual("3", out.getvalue().strip()) out = moves.StringIO() self.assertRaisesRegexp(ValueError, "Field labels list.*has different number " "of elements than fields list", cliutils.print_list, [TestObj()], ["x"], field_labels=["x", "y"], sortby_index=None, out=out)