Merge "Add json schema for disable service"
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index ec430b7..dd2f56b 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -76,8 +76,9 @@
To enable and use tenant isolation you only need to configure 2 things:
#. A set of admin credentials with permissions to create users and
- tenants/projects. This is specified in the identity section with the
- admin_username, admin_tenant_name, and admin_password options
+ tenants/projects. This is specified in the auth section with the
+ admin_username, admin_tenant_name, admin_domain_name, and admin_password
+ options
#. To enable tenant_isolation in the auth section with the
allow_tenant_isolation option.
@@ -126,6 +127,9 @@
Non-locking test accounts (aka credentials config options)
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+**Starting in the Liberty release this mechanism was deprecated and will be
+removed in a future release**
+
When Tempest was refactored to allow for locking test accounts, the original
non-tenant isolated case was converted to internally work similarly to the
accounts.yaml file. This mechanism was then called the non-locking test accounts
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index 7333acb..e5c17ca 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -14,10 +14,14 @@
# under the License.
import datetime
-import time
from tempest.api.compute import base
from tempest import test
+from tempest_lib import exceptions as e
+
+# Time that waits for until returning valid response
+# TODO(takmatsu): Ideally this value would come from configuration.
+VALID_WAIT = 30
class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
@@ -35,7 +39,6 @@
# Create a server in the demo tenant
cls.create_test_server(wait_until='ACTIVE')
- time.sleep(2)
now = datetime.datetime.now()
cls.start = cls._parse_strtime(now - datetime.timedelta(days=1))
@@ -46,17 +49,32 @@
# Returns formatted datetime
return at.strftime('%Y-%m-%dT%H:%M:%S.%f')
+ def call_until_valid(self, func, duration, *args, **kwargs):
+ # Call until get valid response for "duration"
+ # because tenant usage doesn't become available immediately
+ # after create VM.
+ def is_valid():
+ try:
+ self.resp = func(*args, **kwargs)
+ return True
+ except e.InvalidHTTPResponseBody:
+ return False
+ test.call_until_true(is_valid, duration, 1)
+ return self.resp
+
@test.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e')
def test_list_usage_all_tenants(self):
# Get usage for all tenants
- tenant_usage = self.adm_client.list_tenant_usages(
+ tenant_usage = self.call_until_valid(
+ self.adm_client.list_tenant_usages, VALID_WAIT,
start=self.start, end=self.end, detailed="1")['tenant_usages'][0]
self.assertEqual(len(tenant_usage), 8)
@test.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e')
def test_get_usage_tenant(self):
# Get usage for a specific tenant
- tenant_usage = self.adm_client.show_tenant_usage(
+ tenant_usage = self.call_until_valid(
+ self.adm_client.show_tenant_usage, VALID_WAIT,
self.tenant_id, start=self.start, end=self.end)['tenant_usage']
self.assertEqual(len(tenant_usage), 8)
@@ -64,7 +82,7 @@
@test.idempotent_id('9d00a412-b40e-4fd9-8eba-97b496316116')
def test_get_usage_tenant_with_non_admin_user(self):
# Get usage for a specific tenant with non admin user
- tenant_usage = self.client.show_tenant_usage(
+ tenant_usage = self.call_until_valid(
+ self.client.show_tenant_usage, VALID_WAIT,
self.tenant_id, start=self.start, end=self.end)['tenant_usage']
-
self.assertEqual(len(tenant_usage), 8)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index b0fdbac..ec2192f 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -246,8 +246,8 @@
name = data_utils.rand_name(cls.__name__ + "-Server-Group")
if policy is None:
policy = ['affinity']
- body = (cls.server_groups_client.create_server_group(name, policy)
- ['server_group'])
+ body = cls.server_groups_client.create_server_group(
+ name=name, policies=policy)['server_group']
cls.server_groups.append(body['id'])
return body
diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py
new file mode 100644
index 0000000..21247b1
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespaces.py
@@ -0,0 +1,71 @@
+# Copyright 2015 Red Hat, Inc.
+# All Rights Reserved.
+#
+# 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.
+
+from tempest.api.image import base
+from tempest.common.utils import data_utils
+from tempest import test
+from tempest_lib import exceptions as lib_exc
+
+
+class MetadataNamespacesTest(base.BaseV2ImageTest):
+ """
+ Here we will test the Metadata definition Namespaces basic functionality.
+ """
+ @test.idempotent_id('319b765e-7f3d-4b3d-8b37-3ca3876ee768')
+ def test_basic_metadata_definition_namespaces(self):
+ # get the available resource types and use one resource_type
+ body = self.client.list_resource_types()
+ resource_name = body['resource_types'][0]['name']
+ name = [{'name': resource_name}]
+ namespace_name = data_utils.rand_name('namespace')
+ # create the metadef namespaces
+ body = self.client.create_namespaces(namespace=namespace_name,
+ visibility='public',
+ description='Tempest',
+ display_name=namespace_name,
+ resource_type_associations=name,
+ protected=True)
+ self.addCleanup(self._cleanup_namespace, namespace_name)
+ # get namespaces details
+ body = self.client.show_namespaces(namespace_name)
+ self.assertEqual(namespace_name, body['namespace'])
+ self.assertEqual('public', body['visibility'])
+ # unable to delete protected namespace
+ self.assertRaises(lib_exc.Forbidden, self.client.delete_namespaces,
+ namespace_name)
+ # update the visibility to private and protected to False
+ body = self.client.update_namespaces(namespace=namespace_name,
+ description='Tempest',
+ visibility='private',
+ display_name=namespace_name,
+ protected=False)
+ self.assertEqual('private', body['visibility'])
+ self.assertEqual(False, body['protected'])
+ # now able to delete the non-protected namespace
+ self.client.delete_namespaces(namespace_name)
+
+ def _cleanup_namespace(self, namespace_name):
+ # this is used to cleanup the resources
+ try:
+ body = self.client.show_namespaces(namespace_name)
+ self.assertEqual(namespace_name, body['namespace'])
+ body = self.client.update_namespaces(namespace=namespace_name,
+ description='Tempest',
+ visibility='private',
+ display_name=namespace_name,
+ protected=False)
+ self.client.delete_namespaces(namespace_name)
+ except lib_exc.NotFound:
+ pass
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
new file mode 100644
index 0000000..09478ca
--- /dev/null
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -0,0 +1,78 @@
+# Copyright 2015 GlobalLogic. All rights reserved.
+#
+# 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.
+
+from tempest.api.network import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+from tempest_lib import exceptions as lib_exc
+
+CONF = config.CONF
+
+
+class SubnetPoolsTestJSON(base.BaseNetworkTest):
+ """
+ Tests the following operations in the subnetpools API using the REST client
+ for Neutron:
+
+ Create a subnet pool.
+ Update a subnet pool.
+ Delete a subnet pool.
+ Lists subnet pool.
+ Show subnet pool details.
+
+ v2.0 of the Neutron API is assumed. It is assumed that subnetpools
+ options mentioned in the [network-feature-enabled] section and
+ default_network option mentioned in the [network] section of
+ etc/tempest.conf:
+
+ """
+
+ @classmethod
+ def skip_checks(cls):
+ super(SubnetPoolsTestJSON, cls).skip_checks()
+ if not test.is_extension_enabled('subnetpools', 'network'):
+ msg = "subnet pools extension not enabled."
+ raise cls.skipException(msg)
+
+ @test.attr(type='smoke')
+ @test.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811')
+ def test_create_list_show_update_delete_subnetpools(self):
+ subnetpool_name = data_utils.rand_name('subnetpools')
+ # create subnet pool
+ prefix = CONF.network.default_network
+ body = self.client.create_subnetpools(name=subnetpool_name,
+ prefixes=prefix)
+ subnetpool_id = body["subnetpool"]["id"]
+ self.addCleanup(self._cleanup_subnetpools, subnetpool_id)
+ self.assertEqual(subnetpool_name, body["subnetpool"]["name"])
+ # get detail about subnet pool
+ body = self.client.show_subnetpools(subnetpool_id)
+ self.assertEqual(subnetpool_name, body["subnetpool"]["name"])
+ # update the subnet pool
+ subnetpool_name = data_utils.rand_name('subnetpools_update')
+ body = self.client.update_subnetpools(subnetpool_id,
+ name=subnetpool_name)
+ self.assertEqual(subnetpool_name, body["subnetpool"]["name"])
+ # delete subnet pool
+ body = self.client.delete_subnetpools(subnetpool_id)
+ self.assertRaises(lib_exc.NotFound, self.client.show_subnetpools,
+ subnetpool_id)
+
+ def _cleanup_subnetpools(self, subnetpool_id):
+ # this is used to cleanup the resources
+ try:
+ self.client.delete_subnetpools(subnetpool_id)
+ except lib_exc.NotFound:
+ pass
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 783a5fc..5e80f50 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -26,7 +26,7 @@
# Type of credentials available from configuration
CREDENTIAL_TYPES = {
- 'identity_admin': ('identity', 'admin'),
+ 'identity_admin': ('auth', 'admin'),
'user': ('identity', None),
'alt_user': ('identity', 'alt')
}
diff --git a/tempest/config.py b/tempest/config.py
index eb49fed..85db089 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -82,6 +82,26 @@
"creates. However in some neutron configurations, like "
"with VLAN provider networks, this doesn't work. So if "
"set to False the isolated networks will not be created"),
+ cfg.StrOpt('admin_username',
+ help="Username for an administrative user. This is needed for "
+ "authenticating requests made by tenant isolation to "
+ "create users and projects",
+ deprecated_group='identity'),
+ cfg.StrOpt('admin_tenant_name',
+ help="Tenant name to use for an administrative user. This is "
+ "needed for authenticating requests made by tenant "
+ "isolation to create users and projects",
+ deprecated_group='identity'),
+ cfg.StrOpt('admin_password',
+ help="Password to use for an administrative user. This is "
+ "needed for authenticating requests made by tenant "
+ "isolation to create users and projects",
+ secret=True,
+ deprecated_group='identity'),
+ cfg.StrOpt('admin_domain_name',
+ help="Admin domain name for authentication (Keystone V3)."
+ "The same domain applies to user and project",
+ deprecated_group='identity'),
]
identity_group = cfg.OptGroup(name='identity',
@@ -133,42 +153,38 @@
help="The endpoint type to use for OpenStack Identity "
"(Keystone) API v3"),
cfg.StrOpt('username',
- help="Username to use for Nova API requests."),
+ help="Username to use for Nova API requests.",
+ deprecated_for_removal=True),
cfg.StrOpt('tenant_name',
- help="Tenant name to use for Nova API requests."),
+ help="Tenant name to use for Nova API requests.",
+ deprecated_for_removal=True),
cfg.StrOpt('admin_role',
default='admin',
help="Role required to administrate keystone."),
cfg.StrOpt('password',
help="API key to use when authenticating.",
- secret=True),
+ secret=True,
+ deprecated_for_removal=True),
cfg.StrOpt('domain_name',
help="Domain name for authentication (Keystone V3)."
- "The same domain applies to user and project"),
+ "The same domain applies to user and project",
+ deprecated_for_removal=True),
cfg.StrOpt('alt_username',
help="Username of alternate user to use for Nova API "
- "requests."),
+ "requests.",
+ deprecated_for_removal=True),
cfg.StrOpt('alt_tenant_name',
help="Alternate user's Tenant name to use for Nova API "
- "requests."),
+ "requests.",
+ deprecated_for_removal=True),
cfg.StrOpt('alt_password',
help="API key to use when authenticating as alternate user.",
- secret=True),
+ secret=True,
+ deprecated_for_removal=True),
cfg.StrOpt('alt_domain_name',
help="Alternate domain name for authentication (Keystone V3)."
- "The same domain applies to user and project"),
- cfg.StrOpt('admin_username',
- help="Administrative Username to use for "
- "Keystone API requests."),
- cfg.StrOpt('admin_tenant_name',
- help="Administrative Tenant name to use for Keystone API "
- "requests."),
- cfg.StrOpt('admin_password',
- help="API key to use when authenticating as admin.",
- secret=True),
- cfg.StrOpt('admin_domain_name',
- help="Admin domain name for authentication (Keystone V3)."
- "The same domain applies to user and project"),
+ "The same domain applies to user and project",
+ deprecated_for_removal=True),
cfg.StrOpt('default_domain_id',
default='default',
help="ID of the default domain"),
@@ -544,6 +560,10 @@
" with pre-configured ports."
" Supported ports are:"
" ['normal','direct','macvtap']"),
+ cfg.ListOpt('default_network',
+ default=["1.0.0.0/16", "2.0.0.0/16"],
+ help="List of ip pools"
+ " for subnetpools creation"),
]
network_feature_group = cfg.OptGroup(name='network-feature-enabled',
diff --git a/tempest/services/compute/json/server_groups_client.py b/tempest/services/compute/json/server_groups_client.py
index 33501fb..62258d3 100644
--- a/tempest/services/compute/json/server_groups_client.py
+++ b/tempest/services/compute/json/server_groups_client.py
@@ -22,18 +22,13 @@
class ServerGroupsClient(service_client.ServiceClient):
- def create_server_group(self, name, policies):
+ def create_server_group(self, **kwargs):
"""
Create the server group
name : Name of the server-group
policies : List of the policies - affinity/anti-affinity)
"""
- post_body = {
- 'name': name,
- 'policies': policies,
- }
-
- post_body = json.dumps({'server_group': post_body})
+ post_body = json.dumps({'server_group': kwargs})
resp, body = self.post('os-server-groups', post_body)
body = json.loads(body)
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 6cad746..eea179d 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -212,3 +212,63 @@
self.expected_success(200, resp.status)
body = json.loads(body)
return service_client.ResponseBody(resp, body)
+
+ def list_resource_types(self):
+ url = '/v2/metadefs/resource_types'
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def create_namespaces(self, namespace, **kwargs):
+ params = {
+ "namespace": namespace,
+ }
+
+ for option in kwargs:
+ value = kwargs.get(option)
+ if isinstance(value, dict) or isinstance(value, tuple):
+ params.update(value)
+ else:
+ params[option] = value
+
+ data = json.dumps(params)
+ self._validate_schema(data)
+
+ resp, body = self.post('/v2/metadefs/namespaces', data)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def show_namespaces(self, namespace):
+ url = '/v2/metadefs/namespaces/%s' % namespace
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def update_namespaces(self, namespace, visibility, **kwargs):
+ params = {
+ "namespace": namespace,
+ "visibility": visibility
+ }
+ for option in kwargs:
+ value = kwargs.get(option)
+ if isinstance(value, dict) or isinstance(value, tuple):
+ params.update(value)
+ else:
+ params[option] = value
+
+ data = json.dumps(params)
+ self._validate_schema(data)
+ url = '/v2/metadefs/namespaces/%s' % namespace
+ resp, body = self.put(url, body=data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return service_client.ResponseBody(resp, body)
+
+ def delete_namespaces(self, namespace):
+ url = '/v2/metadefs/namespaces/%s' % namespace
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return service_client.ResponseBody(resp)
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 10bd23e..d766aa5 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -423,3 +423,25 @@
post_body = {'network_id': network_id}
uri = '/agents/%s/dhcp-networks' % agent_id
return self.create_resource(uri, post_body)
+
+ def list_subnetpools(self, **filters):
+ uri = '/subnetpools'
+ return self.list_resources(uri, **filters)
+
+ def create_subnetpools(self, **kwargs):
+ uri = '/subnetpools'
+ post_data = {'subnetpool': kwargs}
+ return self.create_resource(uri, post_data)
+
+ def show_subnetpools(self, subnetpool_id, **fields):
+ uri = '/subnetpools/%s' % subnetpool_id
+ return self.show_resource(uri, **fields)
+
+ def update_subnetpools(self, subnetpool_id, **kwargs):
+ uri = '/subnetpools/%s' % subnetpool_id
+ post_data = {'subnetpool': kwargs}
+ return self.update_resource(uri, post_data)
+
+ def delete_subnetpools(self, subnetpool_id):
+ uri = '/subnetpools/%s' % subnetpool_id
+ return self.delete_resource(uri)
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index 5c69c5e..9f47ccc 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -64,9 +64,9 @@
else:
(u, t, p) = (None, None, None)
- cfg.CONF.set_default('admin_username', u, group='identity')
- cfg.CONF.set_default('admin_tenant_name', t, group='identity')
- cfg.CONF.set_default('admin_password', p, group='identity')
+ cfg.CONF.set_default('admin_username', u, group='auth')
+ cfg.CONF.set_default('admin_tenant_name', t, group='auth')
+ cfg.CONF.set_default('admin_password', p, group='auth')
expected = admin_creds is not None or tenant_isolation
observed = credentials.is_admin_available()
diff --git a/tempest/tests/common/test_cred_provider.py b/tempest/tests/common/test_cred_provider.py
index 1bc7147..d404660 100644
--- a/tempest/tests/common/test_cred_provider.py
+++ b/tempest/tests/common/test_cred_provider.py
@@ -123,5 +123,9 @@
cfg.CONF.set_default('auth_version', 'v3', group='identity')
# Identity group items
for prefix in ['', 'alt_', 'admin_']:
+ if prefix == 'admin_':
+ group = 'auth'
+ else:
+ group = 'identity'
cfg.CONF.set_default(prefix + 'domain_name', 'fake_domain_name',
- group='identity')
+ group=group)
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 4898c9c..ca8bc3e 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -48,9 +48,13 @@
for config_option in ['username', 'password', 'tenant_name']:
# Identity group items
for prefix in ['', 'alt_', 'admin_']:
+ if prefix == 'admin_':
+ group = 'auth'
+ else:
+ group = 'identity'
self.conf.set_default(prefix + config_option,
'fake_' + config_option,
- group='identity')
+ group=group)
class FakePrivate(config.TempestConfigPrivate):
diff --git a/tempest/tests/services/compute/test_images_client.py b/tempest/tests/services/compute/test_images_client.py
new file mode 100644
index 0000000..1d532b7
--- /dev/null
+++ b/tempest/tests/services/compute/test_images_client.py
@@ -0,0 +1,240 @@
+# Copyright 2015 NEC Corporation. All rights reserved.
+#
+# 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 copy
+
+from oslotest import mockpatch
+from tempest_lib import exceptions as lib_exc
+
+from tempest.services.compute.json import images_client
+from tempest.tests import fake_auth_provider
+from tempest.tests.services.compute import base
+
+
+class TestImagesClient(base.BaseComputeServiceTest):
+ # Data Dictionaries used for testing #
+ FAKE_IMAGE_METADATA = {
+ "list":
+ {"metadata": {
+ "auto_disk_config": "True",
+ "Label": "Changed"
+ }},
+ "set_item":
+ {"meta": {
+ "auto_disk_config": "True"
+ }},
+ "show_item":
+ {"meta": {
+ "kernel_id": "nokernel",
+ }},
+ "update":
+ {"metadata": {
+ "kernel_id": "False",
+ "Label": "UpdatedImage"
+ }},
+ "set":
+ {"metadata": {
+ "Label": "Changed",
+ "auto_disk_config": "True"
+ }},
+ "delete_item": {}
+ }
+
+ FAKE_IMAGE_DATA = {
+ "list":
+ {"images": [
+ {"id": "70a599e0-31e7-49b7-b260-868f441e862b",
+ "links": [
+ {"href": "http://openstack.example.com/v2/openstack" +
+ "/images/70a599e0-31e7-49b7-b260-868f441e862b",
+ "rel": "self"
+ }
+ ],
+ "name": "fakeimage7"
+ }]},
+ "show": {"image": {
+ "created": "2011-01-01T01:02:03Z",
+ "id": "70a599e0-31e7-49b7-b260-868f441e862b",
+ "links": [
+ {
+ "href": "http://openstack.example.com/v2/openstack" +
+ "/images/70a599e0-31e7-49b7-b260-868f441e862b",
+ "rel": "self"
+ },
+ ],
+ "metadata": {
+ "architecture": "x86_64",
+ "auto_disk_config": "True",
+ "kernel_id": "nokernel",
+ "ramdisk_id": "nokernel"
+ },
+ "minDisk": 0,
+ "minRam": 0,
+ "name": "fakeimage7",
+ "progress": 100,
+ "status": "ACTIVE",
+ "updated": "2011-01-01T01:02:03Z"}},
+ "delete": {}
+ }
+ func2mock = {
+ 'get': 'tempest.common.service_client.ServiceClient.get',
+ 'post': 'tempest.common.service_client.ServiceClient.post',
+ 'put': 'tempest.common.service_client.ServiceClient.put',
+ 'delete': 'tempest.common.service_client.ServiceClient.delete'}
+ # Variable definition
+ FAKE_IMAGE_ID = FAKE_IMAGE_DATA['show']['image']['id']
+ FAKE_CREATE_INFO = {'location': 'None'}
+ FAKE_METADATA = FAKE_IMAGE_METADATA['show_item']['meta']
+
+ def setUp(self):
+ super(TestImagesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = images_client.ImagesClient(fake_auth,
+ "compute", "regionOne")
+
+ def _test_image_operation(self, operation="delete", bytes_body=False):
+ response_code = 200
+ mock_operation = self.func2mock['get']
+ expected_op = self.FAKE_IMAGE_DATA[operation]
+ params = {"image_id": self.FAKE_IMAGE_ID}
+ if operation == 'list':
+ function = self.client.list_images
+ elif operation == 'show':
+ function = self.client.show_image
+ else:
+ function = self.client.delete_image
+ mock_operation = self.func2mock['delete']
+ response_code = 204
+
+ self.check_service_client_function(
+ function, mock_operation, expected_op,
+ bytes_body, response_code, **params)
+
+ def _test_image_metadata(self, operation="set_item", bytes_body=False):
+ response_code = 200
+ expected_op = self.FAKE_IMAGE_METADATA[operation]
+ if operation == 'list':
+ function = self.client.list_image_metadata
+ mock_operation = self.func2mock['get']
+ params = {"image_id": self.FAKE_IMAGE_ID}
+
+ elif operation == 'set':
+ function = self.client.set_image_metadata
+ mock_operation = self.func2mock['put']
+ params = {"image_id": "_dummy_data",
+ "meta": self.FAKE_METADATA}
+
+ elif operation == 'update':
+ function = self.client.update_image_metadata
+ mock_operation = self.func2mock['post']
+ params = {"image_id": self.FAKE_IMAGE_ID,
+ "meta": self.FAKE_METADATA}
+
+ elif operation == 'show_item':
+ mock_operation = self.func2mock['get']
+ function = self.client.show_image_metadata_item
+ params = {"image_id": self.FAKE_IMAGE_ID,
+ "key": "123"}
+
+ elif operation == 'delete_item':
+ function = self.client.delete_image_metadata_item
+ mock_operation = self.func2mock['delete']
+ response_code = 204
+ params = {"image_id": self.FAKE_IMAGE_ID,
+ "key": "123"}
+
+ else:
+ function = self.client.set_image_metadata_item
+ mock_operation = self.func2mock['put']
+ params = {"image_id": self.FAKE_IMAGE_ID,
+ "key": "123",
+ "meta": self.FAKE_METADATA}
+
+ self.check_service_client_function(
+ function, mock_operation, expected_op,
+ bytes_body, response_code, **params)
+
+ def _test_resource_deleted(self, bytes_body=False):
+ params = {"id": self.FAKE_IMAGE_ID}
+ expected_op = self.FAKE_IMAGE_DATA['show']['image']
+ self.useFixture(mockpatch.Patch('tempest.services.compute.json'
+ '.images_client.ImagesClient.show_image',
+ side_effect=lib_exc.NotFound))
+ self.assertEqual(True, self.client.is_resource_deleted(**params))
+ tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show'])
+ tempdata['image']['id'] = None
+ self.useFixture(mockpatch.Patch('tempest.services.compute.json'
+ '.images_client.ImagesClient.show_image',
+ return_value=expected_op))
+ self.assertEqual(False, self.client.is_resource_deleted(**params))
+
+ def test_list_images_with_str_body(self):
+ self._test_image_operation('list')
+
+ def test_list_images_with_bytes_body(self):
+ self._test_image_operation('list', True)
+
+ def test_show_image_with_str_body(self):
+ self._test_image_operation('show')
+
+ def test_show_image_with_bytes_body(self):
+ self._test_image_operation('show', True)
+
+ def test_delete_image_with_str_body(self):
+ self._test_image_operation('delete')
+
+ def test_delete_image_with_bytes_body(self):
+ self._test_image_operation('delete', True)
+
+ def test_list_image_metadata_with_str_body(self):
+ self._test_image_metadata('list')
+
+ def test_list_image_metadata_with_bytes_body(self):
+ self._test_image_metadata('list', True)
+
+ def test_set_image_metadata_with_str_body(self):
+ self._test_image_metadata('set')
+
+ def test_set_image_metadata_with_bytes_body(self):
+ self._test_image_metadata('set', True)
+
+ def test_update_image_metadata_with_str_body(self):
+ self._test_image_metadata('update')
+
+ def test_update_image_metadata_with_bytes_body(self):
+ self._test_image_metadata('update', True)
+
+ def test_set_image_metadata_item_with_str_body(self):
+ self._test_image_metadata()
+
+ def test_set_image_metadata_item_with_bytes_body(self):
+ self._test_image_metadata(bytes_body=True)
+
+ def test_show_image_metadata_item_with_str_body(self):
+ self._test_image_metadata('show_item')
+
+ def test_show_image_metadata_item_with_bytes_body(self):
+ self._test_image_metadata('show_item', True)
+
+ def test_delete_image_metadata_item_with_str_body(self):
+ self._test_image_metadata('delete_item')
+
+ def test_delete_image_metadata_item_with_bytes_body(self):
+ self._test_image_metadata('delete_item', True)
+
+ def test_resource_delete_with_str_body(self):
+ self._test_resource_deleted()
+
+ def test_resource_delete_with_bytes_body(self):
+ self._test_resource_deleted(True)