diff options
Diffstat (limited to 'glanceclient/tests')
-rw-r--r-- | glanceclient/tests/functional/base.py | 31 | ||||
-rwxr-xr-x | glanceclient/tests/functional/hooks/post_test_hook.sh | 17 | ||||
-rw-r--r-- | glanceclient/tests/functional/test_readonly_glance.py | 49 | ||||
-rw-r--r-- | glanceclient/tests/unit/test_http.py | 36 | ||||
-rw-r--r-- | glanceclient/tests/unit/test_shell.py | 59 | ||||
-rw-r--r-- | glanceclient/tests/unit/v1/test_images.py | 6 | ||||
-rw-r--r-- | glanceclient/tests/unit/v1/test_shell.py | 4 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_images.py | 12 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_metadefs_namespaces.py | 8 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_metadefs_objects.py | 18 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_metadefs_properties.py | 10 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_schemas.py | 4 | ||||
-rw-r--r-- | glanceclient/tests/unit/v2/test_shell_v2.py | 12 |
13 files changed, 238 insertions, 28 deletions
diff --git a/glanceclient/tests/functional/base.py b/glanceclient/tests/functional/base.py index 89b9092..a39e77d 100644 --- a/glanceclient/tests/functional/base.py +++ b/glanceclient/tests/functional/base.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import ConfigParser import os from tempest_lib.cli import base @@ -27,16 +28,38 @@ class ClientTestBase(base.ClientTestBase): * initially just check return codes, and later test command outputs """ + + def __init__(self, *args, **kwargs): + super(ClientTestBase, self).__init__(*args, **kwargs) + + # Collecting of credentials: + # + # Support the existence of a functional_creds.conf for + # testing. This makes it possible to use a config file. + self.username = os.environ.get('OS_USERNAME') + self.password = os.environ.get('OS_PASSWORD') + self.tenant_name = os.environ.get('OS_TENANT_NAME') + self.uri = os.environ.get('OS_AUTH_URL') + config = ConfigParser.RawConfigParser() + if config.read('functional_creds.conf'): + # the OR pattern means the environment is preferred for + # override + self.username = self.username or config.get('admin', 'user') + self.password = self.password or config.get('admin', 'pass') + self.tenant_name = self.tenant_name or config.get('admin', + 'tenant') + self.uri = self.uri or config.get('auth', 'uri') + def _get_clients(self): cli_dir = os.environ.get( 'OS_GLANCECLIENT_EXEC_DIR', os.path.join(os.path.abspath('.'), '.tox/functional/bin')) return base.CLIClient( - username=os.environ.get('OS_USERNAME'), - password=os.environ.get('OS_PASSWORD'), - tenant_name=os.environ.get('OS_TENANT_NAME'), - uri=os.environ.get('OS_AUTH_URL'), + username=self.username, + password=self.password, + tenant_name=self.tenant_name, + uri=self.uri, cli_dir=cli_dir) def glance(self, *args, **kwargs): diff --git a/glanceclient/tests/functional/hooks/post_test_hook.sh b/glanceclient/tests/functional/hooks/post_test_hook.sh index 34498f3..ef9be3a 100755 --- a/glanceclient/tests/functional/hooks/post_test_hook.sh +++ b/glanceclient/tests/functional/hooks/post_test_hook.sh @@ -28,15 +28,28 @@ function generate_testr_results { export GLANCECLIENT_DIR="$BASE/new/python-glanceclient" +sudo chown -R jenkins:stack $GLANCECLIENT_DIR + # Get admin credentials cd $BASE/new/devstack source openrc admin admin +# pass the appropriate variables via a config file +CREDS_FILE=$GLANCECLIENT_DIR/functional_creds.conf +cat <<EOF > $CREDS_FILE +# Credentials for functional testing +[auth] +uri = $OS_AUTH_URL + +[admin] +user = $OS_USERNAME +tenant = $OS_TENANT_NAME +pass = $OS_PASSWORD + +EOF # Go to the glanceclient dir cd $GLANCECLIENT_DIR -sudo chown -R jenkins:stack $GLANCECLIENT_DIR - # Run tests echo "Running glanceclient functional test suite" set +e diff --git a/glanceclient/tests/functional/test_readonly_glance.py b/glanceclient/tests/functional/test_readonly_glance.py index 773d52d..0082f29 100644 --- a/glanceclient/tests/functional/test_readonly_glance.py +++ b/glanceclient/tests/functional/test_readonly_glance.py @@ -10,6 +10,10 @@ # License for the specific language governing permissions and limitations # under the License. +import re + +from tempest_lib import exceptions + from glanceclient.tests.functional import base @@ -22,4 +26,47 @@ class SimpleReadOnlyGlanceClientTest(base.ClientTestBase): """ def test_list(self): - self.glance('image-list') + out = self.glance('image-list') + endpoints = self.parser.listing(out) + self.assertTableStruct(endpoints, [ + 'ID', 'Name', 'Disk Format', 'Container Format', + 'Size', 'Status']) + + def test_fake_action(self): + self.assertRaises(exceptions.CommandFailed, + self.glance, + 'this-does-not-exist') + + def test_member_list(self): + tenant_name = '--tenant-id %s' % self.tenant_name + out = self.glance('member-list', + params=tenant_name) + endpoints = self.parser.listing(out) + self.assertTableStruct(endpoints, + ['Image ID', 'Member ID', 'Can Share']) + + def test_help(self): + help_text = self.glance('help') + lines = help_text.split('\n') + self.assertFirstLineStartsWith(lines, 'usage: glance') + + commands = [] + cmds_start = lines.index('Positional arguments:') + cmds_end = lines.index('Optional arguments:') + command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)') + for line in lines[cmds_start:cmds_end]: + match = command_pattern.match(line) + if match: + commands.append(match.group(1)) + commands = set(commands) + wanted_commands = set(('image-create', 'image-delete', 'help', + 'image-download', 'image-show', 'image-update', + 'member-create', 'member-delete', + 'member-list', 'image-list')) + self.assertFalse(wanted_commands - commands) + + def test_version(self): + self.glance('', flags='--version') + + def test_debug_list(self): + self.glance('image-list', flags='--debug') diff --git a/glanceclient/tests/unit/test_http.py b/glanceclient/tests/unit/test_http.py index e8bfaaa..e610716 100644 --- a/glanceclient/tests/unit/test_http.py +++ b/glanceclient/tests/unit/test_http.py @@ -12,13 +12,17 @@ # 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 functools import json +from keystoneclient.auth import token_endpoint +from keystoneclient import session import mock import requests from requests_mock.contrib import fixture import six from six.moves.urllib import parse +from testscenarios import load_tests_apply_scenarios as load_tests # noqa import testtools from testtools import matchers import types @@ -30,15 +34,39 @@ from glanceclient import exc from glanceclient.tests import utils +def original_only(f): + @functools.wraps(f) + def wrapper(self, *args, **kwargs): + if not hasattr(self.client, 'log_curl_request'): + self.skipTest('Skip logging tests for session client') + + return f(self, *args, **kwargs) + + class TestClient(testtools.TestCase): + scenarios = [ + ('httpclient', {'create_client': '_create_http_client'}), + ('session', {'create_client': '_create_session_client'}) + ] + + def _create_http_client(self): + return http.HTTPClient(self.endpoint, token=self.token) + + def _create_session_client(self): + auth = token_endpoint.Token(self.endpoint, self.token) + sess = session.Session(auth=auth) + return http.SessionClient(sess) + def setUp(self): super(TestClient, self).setUp() self.mock = self.useFixture(fixture.Fixture()) self.endpoint = 'http://example.com:9292' self.ssl_endpoint = 'https://example.com:9292' - self.client = http.HTTPClient(self.endpoint, token=u'abc123') + self.token = u'abc123' + + self.client = getattr(self, self.create_client)() def test_identity_headers_and_token(self): identity_headers = { @@ -140,6 +168,9 @@ class TestClient(testtools.TestCase): self.assertEqual(text, resp.text) def test_headers_encoding(self): + if not hasattr(self.client, 'encode_headers'): + self.skipTest('Cannot do header encoding check on SessionClient') + value = u'ni\xf1o' headers = {"test": value, "none-val": None} encoded = self.client.encode_headers(headers) @@ -206,6 +237,7 @@ class TestClient(testtools.TestCase): self.assertTrue(isinstance(body, types.GeneratorType)) self.assertEqual([data], list(body)) + @original_only def test_log_http_response_with_non_ascii_char(self): try: response = 'Ok' @@ -216,6 +248,7 @@ class TestClient(testtools.TestCase): except UnicodeDecodeError as e: self.fail("Unexpected UnicodeDecodeError exception '%s'" % e) + @original_only def test_log_curl_request_with_non_ascii_char(self): try: headers = {'header1': 'value1\xa5\xa6'} @@ -225,6 +258,7 @@ class TestClient(testtools.TestCase): except UnicodeDecodeError as e: self.fail("Unexpected UnicodeDecodeError exception '%s'" % e) + @original_only @mock.patch('glanceclient.common.http.LOG.debug') def test_log_curl_request_with_body_and_header(self, mock_log): hd_name = 'header1' diff --git a/glanceclient/tests/unit/test_shell.py b/glanceclient/tests/unit/test_shell.py index ef15561..d6ce9e6 100644 --- a/glanceclient/tests/unit/test_shell.py +++ b/glanceclient/tests/unit/test_shell.py @@ -27,10 +27,11 @@ import requests from requests_mock.contrib import fixture as rm_fixture import six +from glanceclient.common import utils from glanceclient import exc from glanceclient import shell as openstack_shell +from glanceclient.tests import utils as testutils -from glanceclient.tests import utils #NOTE (esheffield) Used for the schema caching tests from glanceclient.v2 import schemas as schemas import json @@ -75,7 +76,7 @@ _s = V3_TOKEN.add_service('image', name='glance') _s.add_standard_endpoints(public=DEFAULT_IMAGE_URL) -class ShellTest(utils.TestCase): +class ShellTest(testutils.TestCase): # auth environment to use auth_env = FAKE_V2_ENV.copy() # expected auth plugin to invoke @@ -311,6 +312,58 @@ class ShellTest(utils.TestCase): except SystemExit as ex: self.assertEqual(130, ex.code) + @mock.patch('glanceclient.common.utils.exit', side_effect=utils.exit) + def test_shell_illegal_version(self, mock_exit): + # Only int versions are allowed on cli + shell = openstack_shell.OpenStackImagesShell() + argstr = '--os-image-api-version 1.1 image-list' + try: + shell.main(argstr.split()) + except SystemExit as ex: + self.assertEqual(1, ex.code) + msg = ("Invalid API version parameter. " + "Supported values are %s" % openstack_shell.SUPPORTED_VERSIONS) + mock_exit.assert_called_with(msg=msg) + + @mock.patch('glanceclient.common.utils.exit', side_effect=utils.exit) + def test_shell_unsupported_version(self, mock_exit): + # Test an integer version which is not supported (-1) + shell = openstack_shell.OpenStackImagesShell() + argstr = '--os-image-api-version -1 image-list' + try: + shell.main(argstr.split()) + except SystemExit as ex: + self.assertEqual(1, ex.code) + msg = ("Invalid API version parameter. " + "Supported values are %s" % openstack_shell.SUPPORTED_VERSIONS) + mock_exit.assert_called_with(msg=msg) + + @mock.patch.object(openstack_shell.OpenStackImagesShell, + 'get_subcommand_parser') + def test_shell_import_error_with_mesage(self, mock_parser): + msg = 'Unable to import module xxx' + mock_parser.side_effect = ImportError('%s' % msg) + shell = openstack_shell.OpenStackImagesShell() + argstr = '--os-image-api-version 2 image-list' + try: + shell.main(argstr.split()) + self.fail('No import error returned') + except ImportError as e: + self.assertEqual(msg, str(e)) + + @mock.patch.object(openstack_shell.OpenStackImagesShell, + 'get_subcommand_parser') + def test_shell_import_error_default_message(self, mock_parser): + mock_parser.side_effect = ImportError + shell = openstack_shell.OpenStackImagesShell() + argstr = '--os-image-api-version 2 image-list' + try: + shell.main(argstr.split()) + self.fail('No import error returned') + except ImportError as e: + msg = 'Unable to import module. Re-run with --debug for more info.' + self.assertEqual(msg, str(e)) + @mock.patch('glanceclient.v1.client.Client') def test_auth_plugin_invocation_without_username_with_v1(self, v1_client): self.make_env(exclude='OS_USERNAME') @@ -419,7 +472,7 @@ class ShellTestWithKeystoneV3Auth(ShellTest): self.assertNotIn(r, stdout.split()) -class ShellCacheSchemaTest(utils.TestCase): +class ShellCacheSchemaTest(testutils.TestCase): def setUp(self): super(ShellCacheSchemaTest, self).setUp() self._mock_client_setup() diff --git a/glanceclient/tests/unit/v1/test_images.py b/glanceclient/tests/unit/v1/test_images.py index 90849d1..1de85ce 100644 --- a/glanceclient/tests/unit/v1/test_images.py +++ b/glanceclient/tests/unit/v1/test_images.py @@ -554,7 +554,7 @@ class ImageManagerTest(testtools.TestCase): except IOError as e: self.assertEqual(errno.EPIPE, e.errno) msg = 'was fd7c5c4fdaa97163ee4ba8842baa537a expected wrong' - self.assertTrue(msg in str(e)) + self.assertIn(msg, str(e)) def test_data_req_id(self): params = { @@ -897,7 +897,7 @@ class ImageTest(testtools.TestCase): except IOError as e: self.assertEqual(errno.EPIPE, e.errno) msg = 'was fd7c5c4fdaa97163ee4ba8842baa537a expected wrong' - self.assertTrue(msg in str(e)) + self.assertIn(msg, str(e)) def test_data_with_checksum(self): image = self.mgr.get('3') @@ -959,5 +959,5 @@ class UrlParameterTest(testtools.TestCase): shell.do_image_list(self.gc, FakeArg({"is_public": "True"})) parts = parse.urlparse(self.api.url) qs_dict = parse.parse_qs(parts.query) - self.assertTrue('is_public' in qs_dict) + self.assertIn('is_public', qs_dict) self.assertTrue(qs_dict['is_public'][0].lower() == "true") diff --git a/glanceclient/tests/unit/v1/test_shell.py b/glanceclient/tests/unit/v1/test_shell.py index 152863b..963c560 100644 --- a/glanceclient/tests/unit/v1/test_shell.py +++ b/glanceclient/tests/unit/v1/test_shell.py @@ -523,7 +523,7 @@ class ShellStdinHandlingTests(testtools.TestCase): self._do_update('44d2c7e1-de4e-4612-8aa2-ba26610c444f') - self.assertTrue('data' in self.collected_args[1]) + self.assertIn('data', self.collected_args[1]) self.assertIsInstance(self.collected_args[1]['data'], file_type) self.assertEqual('Some Data', self.collected_args[1]['data'].read()) @@ -548,7 +548,7 @@ class ShellStdinHandlingTests(testtools.TestCase): self._do_update('44d2c7e1-de4e-4612-8aa2-ba26610c444f') - self.assertTrue('data' in self.collected_args[1]) + self.assertIn('data', self.collected_args[1]) self.assertIsInstance(self.collected_args[1]['data'], file_type) self.assertEqual('Some Data\n', self.collected_args[1]['data'].read()) diff --git a/glanceclient/tests/unit/v2/test_images.py b/glanceclient/tests/unit/v2/test_images.py index 7fc7558..26ee792 100644 --- a/glanceclient/tests/unit/v2/test_images.py +++ b/glanceclient/tests/unit/v2/test_images.py @@ -826,7 +826,7 @@ class TestController(testtools.TestCase): except IOError as e: self.assertEqual(errno.EPIPE, e.errno) msg = 'was 9d3d9048db16a7eee539e93e3618cbe7 expected wrong' - self.assertTrue(msg in str(e)) + self.assertIn(msg, str(e)) def test_data_with_checksum(self): body = self.controller.data('1b1c6366-dd57-11e1-af0f-02163e68b1d8', @@ -989,17 +989,17 @@ class TestController(testtools.TestCase): e = self.assertRaises(exc.HTTPBadRequest, self.controller.add_location, image_id, url, meta) - self.assertTrue(estr in str(e)) + self.assertIn(estr, str(e)) e = self.assertRaises(exc.HTTPBadRequest, self.controller.delete_locations, image_id, set([url])) - self.assertTrue(estr in str(e)) + self.assertIn(estr, str(e)) e = self.assertRaises(exc.HTTPBadRequest, self.controller.update_location, image_id, url, meta) - self.assertTrue(estr in str(e)) + self.assertIn(estr, str(e)) def _empty_get(self, image_id): return ('GET', '/v2/images/%s' % image_id, {}, None) @@ -1052,7 +1052,7 @@ class TestController(testtools.TestCase): err = self.assertRaises(exc.HTTPNotFound, self.controller.delete_locations, image_id, url_set) - self.assertTrue(err_str in str(err)) + self.assertIn(err_str, str(err)) def test_update_location(self): image_id = 'a2b83adc-888e-11e3-8872-78acc0b951d8' @@ -1095,4 +1095,4 @@ class TestController(testtools.TestCase): err = self.assertRaises(exc.HTTPNotFound, self.controller.update_location, image_id, **new_loc) - self.assertTrue(err_str in str(err)) + self.assertIn(err_str, str(err)) diff --git a/glanceclient/tests/unit/v2/test_metadefs_namespaces.py b/glanceclient/tests/unit/v2/test_metadefs_namespaces.py index ecc05ee..5995e6e 100644 --- a/glanceclient/tests/unit/v2/test_metadefs_namespaces.py +++ b/glanceclient/tests/unit/v2/test_metadefs_namespaces.py @@ -664,6 +664,14 @@ class TestNamespaceController(testtools.TestCase): self.assertRaises(TypeError, self.controller.update, NAMESPACE1, **properties) + def test_update_namespace_disallowed_fields(self): + properties = {'display_name': 'My Updated Name'} + self.controller.update(NAMESPACE1, **properties) + actual = self.api.calls + _disallowed_fields = ['self', 'schema', 'created_at', 'updated_at'] + for key in actual[1][3]: + self.assertNotIn(key, _disallowed_fields) + def test_delete_namespace(self): self.controller.delete(NAMESPACE1) expect = [ diff --git a/glanceclient/tests/unit/v2/test_metadefs_objects.py b/glanceclient/tests/unit/v2/test_metadefs_objects.py index c565b3c..610aaee 100644 --- a/glanceclient/tests/unit/v2/test_metadefs_objects.py +++ b/glanceclient/tests/unit/v2/test_metadefs_objects.py @@ -304,6 +304,24 @@ class TestObjectController(testtools.TestCase): self.assertRaises(TypeError, self.controller.update, NAMESPACE1, OBJECT1, **properties) + def test_update_object_disallowed_fields(self): + properties = { + 'description': 'UPDATED_DESCRIPTION' + } + self.controller.update(NAMESPACE1, OBJECT1, **properties) + actual = self.api.calls + # API makes three calls(GET, PUT, GET) for object update. + # PUT has the request body in the list + '''('PUT', '/v2/metadefs/namespaces/Namespace1/objects/Object1', {}, + [('description', 'UPDATED_DESCRIPTION'), + ('name', 'Object1'), + ('properties', ...), + ('required', [])])''' + + _disallowed_fields = ['self', 'schema', 'created_at', 'updated_at'] + for key in actual[1][3]: + self.assertNotIn(key, _disallowed_fields) + def test_delete_object(self): self.controller.delete(NAMESPACE1, OBJECT1) expect = [ diff --git a/glanceclient/tests/unit/v2/test_metadefs_properties.py b/glanceclient/tests/unit/v2/test_metadefs_properties.py index 388bf93..11165b9 100644 --- a/glanceclient/tests/unit/v2/test_metadefs_properties.py +++ b/glanceclient/tests/unit/v2/test_metadefs_properties.py @@ -280,6 +280,16 @@ class TestPropertyController(testtools.TestCase): self.assertRaises(TypeError, self.controller.update, NAMESPACE1, PROPERTY1, **properties) + def test_update_property_disallowed_fields(self): + properties = { + 'description': 'UPDATED_DESCRIPTION' + } + self.controller.update(NAMESPACE1, PROPERTY1, **properties) + actual = self.api.calls + _disallowed_fields = ['created_at', 'updated_at'] + for key in actual[1][3]: + self.assertNotIn(key, _disallowed_fields) + def test_delete_property(self): self.controller.delete(NAMESPACE1, PROPERTY1) expect = [ diff --git a/glanceclient/tests/unit/v2/test_schemas.py b/glanceclient/tests/unit/v2/test_schemas.py index 35788cd..b084d14 100644 --- a/glanceclient/tests/unit/v2/test_schemas.py +++ b/glanceclient/tests/unit/v2/test_schemas.py @@ -121,8 +121,8 @@ class TestController(testtools.TestCase): def test_get_schema(self): schema = self.controller.get('image') self.assertEqual('image', schema.name) - self.assertEqual(['name', 'tags'], - [p.name for p in schema.properties]) + self.assertEqual(set(['name', 'tags']), + set([p.name for p in schema.properties])) class TestSchemaBasedModel(testtools.TestCase): diff --git a/glanceclient/tests/unit/v2/test_shell_v2.py b/glanceclient/tests/unit/v2/test_shell_v2.py index 33985b9..faaad01 100644 --- a/glanceclient/tests/unit/v2/test_shell_v2.py +++ b/glanceclient/tests/unit/v2/test_shell_v2.py @@ -71,7 +71,8 @@ class ShellV2Test(testtools.TestCase): 'properties': [], 'sort_key': ['name', 'id'], 'sort_dir': ['desc', 'asc'], - 'sort': None + 'sort': None, + 'verbose': False } args = self._make_args(input) with mock.patch.object(self.gc.images, 'list') as mocked_list: @@ -104,7 +105,8 @@ class ShellV2Test(testtools.TestCase): 'properties': [], 'sort_key': ['name'], 'sort_dir': ['desc'], - 'sort': None + 'sort': None, + 'verbose': False } args = self._make_args(input) with mock.patch.object(self.gc.images, 'list') as mocked_list: @@ -137,7 +139,8 @@ class ShellV2Test(testtools.TestCase): 'properties': [], 'sort': 'name:desc,size:asc', 'sort_key': [], - 'sort_dir': [] + 'sort_dir': [], + 'verbose': False } args = self._make_args(input) with mock.patch.object(self.gc.images, 'list') as mocked_list: @@ -170,7 +173,8 @@ class ShellV2Test(testtools.TestCase): 'properties': ['os_distro=NixOS', 'architecture=x86_64'], 'sort_key': ['name'], 'sort_dir': ['desc'], - 'sort': None + 'sort': None, + 'verbose': False } args = self._make_args(input) with mock.patch.object(self.gc.images, 'list') as mocked_list: |