diff options
Diffstat (limited to 'openstackclient/tests/unit/test_shell.py')
| -rw-r--r-- | openstackclient/tests/unit/test_shell.py | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/openstackclient/tests/unit/test_shell.py b/openstackclient/tests/unit/test_shell.py new file mode 100644 index 00000000..87cd7f51 --- /dev/null +++ b/openstackclient/tests/unit/test_shell.py @@ -0,0 +1,442 @@ +# Copyright 2012-2013 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock +import os +import sys + +from osc_lib.tests import utils as osc_lib_test_utils +from oslo_utils import importutils +import wrapt + +from openstackclient import shell + + +DEFAULT_AUTH_URL = "http://127.0.0.1:5000/v2.0/" +DEFAULT_PROJECT_ID = "xxxx-yyyy-zzzz" +DEFAULT_PROJECT_NAME = "project" +DEFAULT_DOMAIN_ID = "aaaa-bbbb-cccc" +DEFAULT_DOMAIN_NAME = "default" +DEFAULT_USER_DOMAIN_ID = "aaaa-bbbb-cccc" +DEFAULT_USER_DOMAIN_NAME = "domain" +DEFAULT_PROJECT_DOMAIN_ID = "aaaa-bbbb-cccc" +DEFAULT_PROJECT_DOMAIN_NAME = "domain" +DEFAULT_USERNAME = "username" +DEFAULT_PASSWORD = "password" + +DEFAULT_CLOUD = "altocumulus" +DEFAULT_REGION_NAME = "ZZ9_Plural_Z_Alpha" +DEFAULT_TOKEN = "token" +DEFAULT_SERVICE_URL = "http://127.0.0.1:8771/v3.0/" +DEFAULT_AUTH_PLUGIN = "v2password" +DEFAULT_INTERFACE = "internal" + +DEFAULT_COMPUTE_API_VERSION = "" +DEFAULT_IDENTITY_API_VERSION = "" +DEFAULT_IMAGE_API_VERSION = "" +DEFAULT_VOLUME_API_VERSION = "" +DEFAULT_NETWORK_API_VERSION = "" + +LIB_COMPUTE_API_VERSION = "" +LIB_IDENTITY_API_VERSION = "" +LIB_IMAGE_API_VERSION = "" +LIB_VOLUME_API_VERSION = "" +LIB_NETWORK_API_VERSION = "" + +CLOUD_1 = { + 'clouds': { + 'scc': { + 'auth': { + 'auth_url': DEFAULT_AUTH_URL, + 'project_name': DEFAULT_PROJECT_NAME, + 'username': 'zaphod', + }, + 'region_name': 'occ-cloud', + 'donut': 'glazed', + 'interface': 'public', + } + } +} + +CLOUD_2 = { + 'clouds': { + 'megacloud': { + 'cloud': 'megadodo', + 'auth': { + 'project_name': 'heart-o-gold', + 'username': 'zaphod', + }, + 'region_name': 'occ-cloud,krikkit,occ-env', + 'log_file': '/tmp/test_log_file', + 'log_level': 'debug', + 'cert': 'mycert', + 'key': 'mickey', + } + } +} + +PUBLIC_1 = { + 'public-clouds': { + 'megadodo': { + 'auth': { + 'auth_url': DEFAULT_AUTH_URL, + 'project_name': DEFAULT_PROJECT_NAME, + }, + 'region_name': 'occ-public', + 'donut': 'cake', + } + } +} + + +# The option table values is a tuple of (<value>, <test-opt>, <test-env>) +# where <value> is the test value to use, <test-opt> is True if this option +# should be tested as a CLI option and <test-env> is True of this option +# should be tested as an environment variable. + +# Global options that should be parsed before shell.initialize_app() is called +global_options = { + '--os-cloud': (DEFAULT_CLOUD, True, True), + '--os-region-name': (DEFAULT_REGION_NAME, True, True), + '--os-default-domain': (DEFAULT_DOMAIN_NAME, True, True), + '--os-cacert': ('/dev/null', True, True), + '--timing': (True, True, False), + '--os-profile': ('SECRET_KEY', True, False), + '--os-interface': (DEFAULT_INTERFACE, True, True) +} + + +# Wrap the osc_lib make_shell() function to set the shell class since +# osc-lib's TestShell class doesn't allow us to specify it yet. +# TODO(dtroyer): remove this once the shell_class_patch patch is released +# in osc-lib +def make_shell_wrapper(func, inst, args, kwargs): + if 'shell_class' not in kwargs: + kwargs['shell_class'] = shell.OpenStackShell + return func(*args, **kwargs) + + +wrapt.wrap_function_wrapper( + osc_lib_test_utils, + 'make_shell', + make_shell_wrapper, +) + + +class TestShell(osc_lib_test_utils.TestShell): + + # Full name of the OpenStackShell class to test (cliff.app.App subclass) + shell_class_name = "openstackclient.shell.OpenStackShell" + + # TODO(dtroyer): remove this once the shell_class_patch patch is released + # in osc-lib + app_patch = shell_class_name + + def setUp(self): + super(TestShell, self).setUp() + # TODO(dtroyer): remove this once the shell_class_patch patch is + # released in osc-lib + self.shell_class = importutils.import_class(self.shell_class_name) + + def _assert_token_endpoint_auth(self, cmd_options, default_args): + with mock.patch( + self.shell_class_name + ".initialize_app", + self.app, + ): + _shell = osc_lib_test_utils.make_shell( + shell_class=self.shell_class, + ) + _cmd = cmd_options + " list role" + osc_lib_test_utils.fake_execute(_shell, _cmd) + print("_shell: %s" % _shell) + + self.app.assert_called_with(["list", "role"]) + self.assertEqual( + default_args.get("token", ''), + _shell.options.token, + "token", + ) + self.assertEqual( + default_args.get("url", ''), + _shell.options.url, + "url", + ) + + def _assert_token_auth(self, cmd_options, default_args): + with mock.patch( + self.app_patch + ".initialize_app", + self.app, + ): + _shell = osc_lib_test_utils.make_shell( + shell_class=self.shell_class, + ) + _cmd = cmd_options + " list role" + osc_lib_test_utils.fake_execute(_shell, _cmd) + print("_shell: %s" % _shell) + + self.app.assert_called_with(["list", "role"]) + self.assertEqual( + default_args.get("token", ''), + _shell.options.token, + "token" + ) + self.assertEqual( + default_args.get("auth_url", ''), + _shell.options.auth_url, + "auth_url" + ) + + def _assert_cli(self, cmd_options, default_args): + with mock.patch( + self.shell_class_name + ".initialize_app", + self.app, + ): + _shell = osc_lib_test_utils.make_shell( + shell_class=self.shell_class, + ) + _cmd = cmd_options + " list server" + osc_lib_test_utils.fake_execute(_shell, _cmd) + + self.app.assert_called_with(["list", "server"]) + self.assertEqual(default_args["compute_api_version"], + _shell.options.os_compute_api_version) + self.assertEqual(default_args["identity_api_version"], + _shell.options.os_identity_api_version) + self.assertEqual(default_args["image_api_version"], + _shell.options.os_image_api_version) + self.assertEqual(default_args["volume_api_version"], + _shell.options.os_volume_api_version) + self.assertEqual(default_args["network_api_version"], + _shell.options.os_network_api_version) + + +class TestShellOptions(TestShell): + + def setUp(self): + super(TestShellOptions, self).setUp() + self.useFixture(osc_lib_test_utils.EnvFixture()) + + def _test_options_init_app(self, test_opts): + for opt in test_opts.keys(): + if not test_opts[opt][1]: + continue + key = osc_lib_test_utils.opt2attr(opt) + if isinstance(test_opts[opt][0], str): + cmd = opt + " " + test_opts[opt][0] + else: + cmd = opt + kwargs = { + key: test_opts[opt][0], + } + self._assert_initialize_app_arg(cmd, kwargs) + + def _test_options_get_one_cloud(self, test_opts): + for opt in test_opts.keys(): + if not test_opts[opt][1]: + continue + key = osc_lib_test_utils.opt2attr(opt) + if isinstance(test_opts[opt][0], str): + cmd = opt + " " + test_opts[opt][0] + else: + cmd = opt + kwargs = { + key: test_opts[opt][0], + } + self._assert_cloud_config_arg(cmd, kwargs) + + def _test_env_init_app(self, test_opts): + for opt in test_opts.keys(): + if not test_opts[opt][2]: + continue + key = osc_lib_test_utils.opt2attr(opt) + kwargs = { + key: test_opts[opt][0], + } + env = { + osc_lib_test_utils.opt2env(opt): test_opts[opt][0], + } + os.environ = env.copy() + self._assert_initialize_app_arg("", kwargs) + + def _test_env_get_one_cloud(self, test_opts): + for opt in test_opts.keys(): + if not test_opts[opt][2]: + continue + key = osc_lib_test_utils.opt2attr(opt) + kwargs = { + key: test_opts[opt][0], + } + env = { + osc_lib_test_utils.opt2env(opt): test_opts[opt][0], + } + os.environ = env.copy() + self._assert_cloud_config_arg("", kwargs) + + +class TestShellTokenAuthEnv(TestShell): + + def setUp(self): + super(TestShellTokenAuthEnv, self).setUp() + env = { + "OS_TOKEN": DEFAULT_TOKEN, + "OS_AUTH_URL": DEFAULT_AUTH_URL, + } + self.useFixture(osc_lib_test_utils.EnvFixture(env.copy())) + + def test_env(self): + flag = "" + kwargs = { + "token": DEFAULT_TOKEN, + "auth_url": DEFAULT_AUTH_URL, + } + self._assert_token_auth(flag, kwargs) + + def test_only_token(self): + flag = "--os-token xyzpdq" + kwargs = { + "token": "xyzpdq", + "auth_url": DEFAULT_AUTH_URL, + } + self._assert_token_auth(flag, kwargs) + + def test_only_auth_url(self): + flag = "--os-auth-url http://cloud.local:555" + kwargs = { + "token": DEFAULT_TOKEN, + "auth_url": "http://cloud.local:555", + } + self._assert_token_auth(flag, kwargs) + + def test_empty_auth(self): + os.environ = {} + flag = "" + kwargs = { + "token": '', + "auth_url": '', + } + self._assert_token_auth(flag, kwargs) + + +class TestShellTokenEndpointAuthEnv(TestShell): + + def setUp(self): + super(TestShellTokenEndpointAuthEnv, self).setUp() + env = { + "OS_TOKEN": DEFAULT_TOKEN, + "OS_URL": DEFAULT_SERVICE_URL, + } + self.useFixture(osc_lib_test_utils.EnvFixture(env.copy())) + + def test_env(self): + flag = "" + kwargs = { + "token": DEFAULT_TOKEN, + "url": DEFAULT_SERVICE_URL, + } + self._assert_token_endpoint_auth(flag, kwargs) + + def test_only_token(self): + flag = "--os-token xyzpdq" + kwargs = { + "token": "xyzpdq", + "url": DEFAULT_SERVICE_URL, + } + self._assert_token_auth(flag, kwargs) + + def test_only_url(self): + flag = "--os-url http://cloud.local:555" + kwargs = { + "token": DEFAULT_TOKEN, + "url": "http://cloud.local:555", + } + self._assert_token_auth(flag, kwargs) + + def test_empty_auth(self): + os.environ = {} + flag = "" + kwargs = { + "token": '', + "url": '', + } + self._assert_token_auth(flag, kwargs) + + +class TestShellCli(TestShell): + + def setUp(self): + super(TestShellCli, self).setUp() + env = { + "OS_COMPUTE_API_VERSION": DEFAULT_COMPUTE_API_VERSION, + "OS_IDENTITY_API_VERSION": DEFAULT_IDENTITY_API_VERSION, + "OS_IMAGE_API_VERSION": DEFAULT_IMAGE_API_VERSION, + "OS_VOLUME_API_VERSION": DEFAULT_VOLUME_API_VERSION, + "OS_NETWORK_API_VERSION": DEFAULT_NETWORK_API_VERSION, + } + self.useFixture(osc_lib_test_utils.EnvFixture(env.copy())) + + def test_default_env(self): + flag = "" + kwargs = { + "compute_api_version": DEFAULT_COMPUTE_API_VERSION, + "identity_api_version": DEFAULT_IDENTITY_API_VERSION, + "image_api_version": DEFAULT_IMAGE_API_VERSION, + "volume_api_version": DEFAULT_VOLUME_API_VERSION, + "network_api_version": DEFAULT_NETWORK_API_VERSION, + } + self._assert_cli(flag, kwargs) + + def test_empty_env(self): + os.environ = {} + flag = "" + kwargs = { + "compute_api_version": LIB_COMPUTE_API_VERSION, + "identity_api_version": LIB_IDENTITY_API_VERSION, + "image_api_version": LIB_IMAGE_API_VERSION, + "volume_api_version": LIB_VOLUME_API_VERSION, + "network_api_version": LIB_NETWORK_API_VERSION + } + self._assert_cli(flag, kwargs) + + +class TestShellArgV(TestShell): + """Test the deferred help flag""" + + def setUp(self): + super(TestShellArgV, self).setUp() + + def test_shell_argv(self): + """Test argv decoding + + Python 2 does nothing with argv while Python 3 decodes it into + Unicode before we ever see it. We manually decode when running + under Python 2 so verify that we get the right argv types. + + Use the argv supplied by the test runner so we get actual Python + runtime behaviour; we only need to check the type of argv[0] + which will alwyas be present. + """ + + with mock.patch( + self.shell_class_name + ".run", + self.app, + ): + # Ensure type gets through unmolested through shell.main() + argv = sys.argv + shell.main(sys.argv) + self.assertEqual(type(argv[0]), type(self.app.call_args[0][0][0])) + + # When shell.main() gets sys.argv itself it should be decoded + shell.main() + self.assertEqual(type(u'x'), type(self.app.call_args[0][0][0])) |
