summaryrefslogtreecommitdiff
path: root/glanceclient/tests
diff options
context:
space:
mode:
Diffstat (limited to 'glanceclient/tests')
-rw-r--r--glanceclient/tests/functional/base.py31
-rwxr-xr-xglanceclient/tests/functional/hooks/post_test_hook.sh17
-rw-r--r--glanceclient/tests/functional/test_readonly_glance.py49
-rw-r--r--glanceclient/tests/unit/test_http.py36
-rw-r--r--glanceclient/tests/unit/test_shell.py59
-rw-r--r--glanceclient/tests/unit/v1/test_images.py6
-rw-r--r--glanceclient/tests/unit/v1/test_shell.py4
-rw-r--r--glanceclient/tests/unit/v2/test_images.py12
-rw-r--r--glanceclient/tests/unit/v2/test_metadefs_namespaces.py8
-rw-r--r--glanceclient/tests/unit/v2/test_metadefs_objects.py18
-rw-r--r--glanceclient/tests/unit/v2/test_metadefs_properties.py10
-rw-r--r--glanceclient/tests/unit/v2/test_schemas.py4
-rw-r--r--glanceclient/tests/unit/v2/test_shell_v2.py12
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: