Merge "Make remote_client reno readable"
diff --git a/README.rst b/README.rst
index 3d7c804..c1c6a10 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,6 @@
.. image:: http://governance.openstack.org/badges/tempest.svg
:target: http://governance.openstack.org/reference/tags/index.html
- :remote:
.. Change things from this point on
@@ -105,7 +104,7 @@
$ tempest run
from the Tempest workspace directory. Or you can use the ``--workspace``
- argument to run in the workspace you created regarless of your current
+ argument to run in the workspace you created regardless of your current
working directory. For example::
$ tempest run --workspace cloud-01
diff --git a/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
new file mode 100644
index 0000000..471f8f0
--- /dev/null
+++ b/releasenotes/notes/add-list-auth-project-client-5905076d914a3943.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add the list auth projects API to the identity client library. This feature
+ enables the possibility to list projects that are available to be scoped
+ to based on the X-Auth-Token provided in the request.
diff --git a/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml b/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
new file mode 100644
index 0000000..acc7a41
--- /dev/null
+++ b/releasenotes/notes/add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add versions_client module for image service.
+ This new module provides list_versions() method which shows API versions
+ from Image service.
diff --git a/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
new file mode 100644
index 0000000..788bc95
--- /dev/null
+++ b/releasenotes/notes/deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml
@@ -0,0 +1,10 @@
+---
+deprecations:
+ - |
+ Glance v1 APIs are deprecated and v2 are current.
+ Tempest should tests only v2 APIs.
+ Below API version selection config options
+ for glance have been deprecated and will be removed in future.
+
+ * CONF.image_feature_enabled.api_v2
+ * CONF.image_feature_enabled.api_v1
diff --git a/requirements.txt b/requirements.txt
index 6962e3e..92825a7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
netaddr!=0.7.16,>=0.7.13 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
+oslo.config>=3.22.0 # Apache-2.0
oslo.log>=3.11.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py
index 45472df..984f1a9 100644
--- a/tempest/api/compute/admin/test_volume_swap.py
+++ b/tempest/api/compute/admin/test_volume_swap.py
@@ -30,6 +30,9 @@
5. Swap volume from "volume1" to "volume2" as admin.
6. Check the swap volume is successful and "volume2"
is attached to "instance1" and "volume1" is in available state.
+ 7. Swap volume from "volume2" to "volume1" as admin.
+ 8. Check the swap volume is successful and "volume1"
+ is attached to "instance1" and "volume2" is in available state.
"""
@classmethod
@@ -58,13 +61,21 @@
volume1['id'], 'available')
waiters.wait_for_volume_resource_status(self.volumes_client,
volume2['id'], 'in-use')
- self.addCleanup(self.servers_client.detach_volume,
- server['id'], volume2['id'])
# Verify "volume2" is attached to the server
vol_attachments = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
self.assertEqual(1, len(vol_attachments))
self.assertIn(volume2['id'], vol_attachments[0]['volumeId'])
- # TODO(mriedem): Test swapping back from volume2 to volume1 after
- # nova bug 1490236 is fixed.
+ # Swap volume from "volume2" to "volume1"
+ self.admin_servers_client.update_attached_volume(
+ server['id'], volume2['id'], volumeId=volume1['id'])
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume2['id'], 'available')
+ waiters.wait_for_volume_resource_status(self.volumes_client,
+ volume1['id'], 'in-use')
+ # Verify "volume1" is attached to the server
+ vol_attachments = self.servers_client.list_volume_attachments(
+ server['id'])['volumeAttachments']
+ self.assertEqual(1, len(vol_attachments))
+ self.assertIn(volume1['id'], vol_attachments[0]['volumeId'])
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7dafc6b..ef13eef 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -295,20 +295,22 @@
@classmethod
def create_image_from_server(cls, server_id, **kwargs):
"""Wrapper utility that returns an image created from the server."""
- name = data_utils.rand_name(cls.__name__ + "-image")
- if 'name' in kwargs:
- name = kwargs.pop('name')
+ name = kwargs.pop('name',
+ data_utils.rand_name(cls.__name__ + "-image"))
+ wait_until = kwargs.pop('wait_until', None)
+ wait_for_server = kwargs.pop('wait_for_server', True)
- image = cls.compute_images_client.create_image(server_id, name=name)
+ image = cls.compute_images_client.create_image(server_id, name=name,
+ **kwargs)
image_id = data_utils.parse_image_id(image.response['location'])
cls.images.append(image_id)
- if 'wait_until' in kwargs:
+ if wait_until is not None:
try:
waiters.wait_for_image_status(cls.compute_images_client,
- image_id, kwargs['wait_until'])
+ image_id, wait_until)
except lib_exc.NotFound:
- if kwargs['wait_until'].upper() == 'ACTIVE':
+ if wait_until.upper() == 'ACTIVE':
# If the image is not found after create_image returned
# that means the snapshot failed in nova-compute and nova
# deleted the image. There should be a compute fault
@@ -326,8 +328,8 @@
raise
image = cls.compute_images_client.show_image(image_id)['image']
- if kwargs['wait_until'] == 'ACTIVE':
- if kwargs.get('wait_for_server', True):
+ if wait_until.upper() == 'ACTIVE':
+ if wait_for_server:
waiters.wait_for_server_status(cls.servers_client,
server_id, 'ACTIVE')
return image
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 945b191..86013d4 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -54,7 +54,7 @@
meta = {'image_type': 'test'}
self.assertRaises(lib_exc.NotFound,
self.create_image_from_server,
- server['id'], meta=meta)
+ server['id'], metadata=meta)
@test.attr(type=['negative'])
@decorators.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f')
@@ -63,7 +63,7 @@
# Create a new image with invalid server id
meta = {'image_type': 'test'}
self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
- data_utils.rand_name('invalid'), meta=meta)
+ data_utils.rand_name('invalid'), metadata=meta)
@test.attr(type=['negative'])
@decorators.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index bc88564..db24174 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -14,10 +14,8 @@
# under the License.
from tempest.api.compute import base
-from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
CONF = config.CONF
@@ -53,15 +51,11 @@
# Create a new image
name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
- body = self.client.create_image(server_id, name=name,
- metadata=meta)
- image_id = data_utils.parse_image_id(body.response['location'])
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.client.delete_image, image_id)
- waiters.wait_for_image_status(self.client, image_id, 'ACTIVE')
+ image = self.create_image_from_server(server_id, name=name,
+ metadata=meta,
+ wait_until='ACTIVE')
# Verify the image was created correctly
- image = self.client.show_image(image_id)['image']
self.assertEqual(name, image['name'])
self.assertEqual('test', image['metadata']['image_type'])
@@ -76,8 +70,9 @@
(str(original_image['minDisk']), str(flavor_disk_size)))
# Verify the image was deleted correctly
- self.client.delete_image(image_id)
- self.client.wait_for_resource_deletion(image_id)
+ self.client.delete_image(image['id'])
+ self.images.remove(image['id'])
+ self.client.wait_for_resource_deletion(image['id'])
@decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 51826c1..68563bd 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -33,9 +33,6 @@
def tearDown(self):
"""Terminate test instances created after a test is executed."""
- for image_id in self.image_ids:
- self.client.delete_image(image_id)
- self.image_ids.remove(image_id)
self.server_check_teardown()
super(ImagesOneServerNegativeTestJSON, self).tearDown()
@@ -80,25 +77,21 @@
server = cls.create_test_server(wait_until='ACTIVE')
cls.server_id = server['id']
- cls.image_ids = []
-
@test.attr(type=['negative'])
@decorators.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc')
def test_create_image_specify_invalid_metadata(self):
# Return an error when creating image with invalid metadata
- snapshot_name = data_utils.rand_name('test-snap')
meta = {'': ''}
- self.assertRaises(lib_exc.BadRequest, self.client.create_image,
- self.server_id, name=snapshot_name, metadata=meta)
+ self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+ self.server_id, metadata=meta)
@test.attr(type=['negative'])
@decorators.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca')
def test_create_image_specify_metadata_over_limits(self):
# Return an error when creating image with meta data over 255 chars
- snapshot_name = data_utils.rand_name('test-snap')
meta = {'a' * 256: 'b' * 256}
- self.assertRaises(lib_exc.BadRequest, self.client.create_image,
- self.server_id, name=snapshot_name, metadata=meta)
+ self.assertRaises(lib_exc.BadRequest, self.create_image_from_server,
+ self.server_id, metadata=meta)
@test.attr(type=['negative'])
@decorators.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456')
@@ -106,16 +99,16 @@
# Disallow creating another image when first image is being saved
# Create first snapshot
- snapshot_name = data_utils.rand_name('test-snap')
- body = self.client.create_image(self.server_id, name=snapshot_name)
- image_id = data_utils.parse_image_id(body.response['location'])
- self.image_ids.append(image_id)
+ image = self.create_image_from_server(self.server_id)
self.addCleanup(self._reset_server)
# Create second snapshot
- alt_snapshot_name = data_utils.rand_name('test-snap')
- self.assertRaises(lib_exc.Conflict, self.client.create_image,
- self.server_id, name=alt_snapshot_name)
+ self.assertRaises(lib_exc.Conflict, self.create_image_from_server,
+ self.server_id)
+
+ image_id = data_utils.parse_image_id(image.response['location'])
+ self.client.delete_image(image_id)
+ self.images.remove(image_id)
@test.attr(type=['negative'])
@decorators.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581')
@@ -131,14 +124,13 @@
def test_delete_image_that_is_not_yet_active(self):
# Return an error while trying to delete an image what is creating
- snapshot_name = data_utils.rand_name('test-snap')
- body = self.client.create_image(self.server_id, name=snapshot_name)
- image_id = data_utils.parse_image_id(body.response['location'])
- self.image_ids.append(image_id)
+ image = self.create_image_from_server(self.server_id)
+ image_id = data_utils.parse_image_id(image.response['location'])
+
self.addCleanup(self._reset_server)
# Do not wait, attempt to delete the image, ensure it's successful
self.client.delete_image(image_id)
- self.image_ids.remove(image_id)
-
- self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id)
+ self.images.remove(image_id)
+ self.assertRaises(lib_exc.NotFound,
+ self.client.show_image, image_id)
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index ed4d31a..fabb91c 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -16,10 +16,13 @@
import six
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
+CONF = config.CONF
+
class TokensV3TestJSON(base.BaseIdentityV3AdminTest):
@@ -150,3 +153,34 @@
token_auth['token']['project']['id'])
self.assertEqual(project2['name'],
token_auth['token']['project']['name'])
+
+ @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
+ def test_get_available_project_scopes(self):
+ manager_project_id = self.manager.credentials.project_id
+ admin_user_id = self.os_adm.credentials.user_id
+ admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
+
+ # Grant the user the role on both projects.
+ self.roles_client.create_user_role_on_project(
+ manager_project_id, admin_user_id, admin_role_id)
+ self.addCleanup(
+ self.roles_client.delete_role_from_user_on_project,
+ manager_project_id, admin_user_id, admin_role_id)
+
+ assigned_project_ids = [self.os_adm.credentials.project_id,
+ manager_project_id]
+
+ # Get available project scopes
+ available_projects =\
+ self.client.list_auth_projects()['projects']
+
+ # create list to save fetched project's id
+ fetched_project_ids = [i['id'] for i in available_projects]
+
+ # verifying the project ids in list
+ missing_project_ids = \
+ [p for p in assigned_project_ids
+ if p not in fetched_project_ids]
+ self.assertEmpty(missing_project_ids,
+ "Failed to find project_id %s in fetched list" %
+ ', '.join(missing_project_ids))
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 69294fa..c586960 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -145,6 +145,7 @@
cls.namespace_objects_client = cls.os.namespace_objects_client
cls.namespace_tags_client = cls.os.namespace_tags_client
cls.schemas_client = cls.os.schemas_client
+ cls.versions_client = cls.os.image_versions_client
def create_namespace(cls, namespace_name=None, visibility='public',
description='Tempest', protected=False,
diff --git a/tempest/api/image/v2/test_versions.py b/tempest/api/image/v2/test_versions.py
new file mode 100644
index 0000000..24f104c
--- /dev/null
+++ b/tempest/api/image/v2/test_versions.py
@@ -0,0 +1,30 @@
+# Copyright 2017 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.
+
+from tempest.api.image import base
+from tempest.lib import decorators
+from tempest import test
+
+
+class VersionsTest(base.BaseV2ImageTest):
+
+ @decorators.idempotent_id('659ea30a-a17c-4317-832c-0f68ed23c31d')
+ @test.attr(type='smoke')
+ def test_list_versions(self):
+ versions = self.versions_client.list_versions()['versions']
+ expected_resources = ('id', 'links', 'status')
+
+ for version in versions:
+ for res in expected_resources:
+ self.assertIn(res, version)
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index fbfcafc..742fe59 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -239,6 +239,36 @@
'enable_snat': False})
self._verify_gateway_port(router['id'])
+ @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_create_router_set_gateway_with_fixed_ip(self):
+ # Don't know public_network_address, so at first create address
+ # from public_network and delete
+ port = self.admin_ports_client.create_port(
+ network_id=CONF.network.public_network_id)['port']
+ self.admin_ports_client.delete_port(port_id=port['id'])
+
+ fixed_ip = {
+ 'subnet_id': port['fixed_ips'][0]['subnet_id'],
+ 'ip_address': port['fixed_ips'][0]['ip_address']
+ }
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'external_fixed_ips': [fixed_ip]
+ }
+
+ # Create a router and set gateway to fixed_ip
+ router = self.admin_routers_client.create_router(
+ external_gateway_info=external_gateway_info)['router']
+ self.addCleanup(self.admin_routers_client.delete_router,
+ router_id=router['id'])
+ # Examine router's gateway is equal to fixed_ip
+ self.assertEqual(router['external_gateway_info'][
+ 'external_fixed_ips'][0]['ip_address'],
+ fixed_ip['ip_address'])
+
@decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index f46b873..218a79a 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -176,6 +176,16 @@
name=name)
@test.attr(type=['negative'])
+ @decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634')
+ def test_create_security_group_update_name_default(self):
+ # Update security group name to 'default', it should be failed.
+ group_create_body, _ = self._create_security_group()
+ self.assertRaises(lib_exc.Conflict,
+ self.security_groups_client.update_security_group,
+ group_create_body['security_group']['id'],
+ name="default")
+
+ @test.attr(type=['negative'])
@decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
def test_create_duplicate_security_group_rule_fails(self):
# Create duplicate security group rule, it should fail.
diff --git a/tempest/clients.py b/tempest/clients.py
index 9cb918a..e75fa79 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -125,6 +125,8 @@
self.image_v2.NamespacePropertiesClient()
self.namespace_tags_client = \
self.image_v2.NamespaceTagsClient()
+ self.image_versions_client = \
+ self.image_v2.VersionsClient()
def _set_compute_clients(self):
self.agents_client = self.compute.AgentsClient()
diff --git a/tempest/config.py b/tempest/config.py
index fb3b8f4..d5c8ea9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -514,10 +514,20 @@
ImageFeaturesGroup = [
cfg.BoolOpt('api_v2',
default=True,
- help="Is the v2 image API enabled"),
+ help="Is the v2 image API enabled",
+ deprecated_for_removal=True,
+ deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+ 'are current one. In future, Tempest will '
+ 'test v2 APIs only so this config option '
+ 'will be removed.'),
cfg.BoolOpt('api_v1',
default=True,
- help="Is the v1 image API enabled"),
+ help="Is the v1 image API enabled",
+ deprecated_for_removal=True,
+ deprecated_reason='Glance v1 APIs are deprecated and v2 APIs '
+ 'are current one. In future, Tempest will '
+ 'test v2 APIs only so this config option '
+ 'will be removed.'),
cfg.BoolOpt('deactivate_image',
default=False,
help="Is the deactivate-image feature enabled."
diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py
index 8177e35..755c14b 100644
--- a/tempest/lib/services/identity/v3/identity_client.py
+++ b/tempest/lib/services/identity/v3/identity_client.py
@@ -43,3 +43,10 @@
resp, body = self.delete("auth/tokens", headers=headers)
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def list_auth_projects(self):
+ """Get available project scopes."""
+ resp, body = self.get("auth/projects")
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index 7d973e5..99a5321 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -25,7 +25,9 @@
from tempest.lib.services.image.v2.resource_types_client import \
ResourceTypesClient
from tempest.lib.services.image.v2.schemas_client import SchemasClient
+from tempest.lib.services.image.v2.versions_client import VersionsClient
__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient',
'NamespacePropertiesClient', 'NamespaceTagsClient',
- 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
+ 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient',
+ 'VersionsClient']
diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py
new file mode 100644
index 0000000..1adc466
--- /dev/null
+++ b/tempest/lib/services/image/v2/versions_client.py
@@ -0,0 +1,38 @@
+# Copyright 2017 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 time
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class VersionsClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def list_versions(self):
+ """List API versions"""
+ version_url = self._get_base_version_url()
+
+ start = time.time()
+ resp, body = self.raw_request(version_url, 'GET')
+ end = time.time()
+ self._log_request('GET', version_url, resp, secs=(end - start),
+ resp_body=body)
+ self._error_checker(resp, body)
+
+ self.expected_success(300, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 5bbc039..15a0a70 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -104,7 +104,6 @@
def _setup_network_and_servers(self, **kwargs):
boot_with_port = kwargs.pop('boot_with_port', False)
- self.security_group = self._create_security_group()
self.network, self.subnet, self.router = self.create_networks(**kwargs)
self.check_networks()
@@ -152,7 +151,9 @@
def _create_server(self, network, port_id=None):
keypair = self.create_keypair()
self.keypairs[keypair['name']] = keypair
- security_groups = [{'name': self.security_group['name']}]
+ security_groups = [
+ {'name': self._create_security_group()['name']}
+ ]
network = {'uuid': network['id']}
if port_id is not None:
network['port'] = port_id
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index d9b93fe..cfd83d0 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -72,11 +72,11 @@
if dualnet - create IPv6 subnets on a different network
:return: list of created networks
"""
- self.network = self._create_network()
+ network = self._create_network()
if dualnet:
- self.network_v6 = self._create_network()
+ network_v6 = self._create_network()
- sub4 = self._create_subnet(network=self.network,
+ sub4 = self._create_subnet(network=network,
namestart='sub4',
ip_version=4)
@@ -90,7 +90,7 @@
self.subnets_v6 = []
for _ in range(n_subnets6):
- net6 = self.network_v6 if dualnet else self.network
+ net6 = network_v6 if dualnet else network
sub6 = self._create_subnet(network=net6,
namestart='sub6',
ip_version=6,
@@ -105,7 +105,7 @@
router['id'], subnet_id=sub6['id'])
self.subnets_v6.append(sub6)
- return [self.network, self.network_v6] if dualnet else [self.network]
+ return [network, network_v6] if dualnet else [network]
@staticmethod
def define_server_ips(srv):
@@ -121,8 +121,6 @@
def prepare_server(self, networks=None):
username = CONF.validation.image_ssh_user
- networks = networks or [self.network]
-
srv = self.create_server(
key_name=self.keypair['name'],
security_groups=[{'name': self.sec_grp['name']}],
@@ -134,7 +132,7 @@
username=username)
return ssh, ips, srv["id"]
- def turn_nic6_on(self, ssh, sid):
+ def turn_nic6_on(self, ssh, sid, network_id):
"""Turns the IPv6 vNIC on
Required because guest images usually set only the first vNIC on boot.
@@ -142,16 +140,18 @@
@param ssh: RemoteClient ssh instance to server
@param sid: server uuid
+ @param network_id: the network id the NIC is connected to
"""
ports = [
p["mac_address"] for p in
self.admin_manager.ports_client.list_ports(
- device_id=sid, network_id=self.network_v6['id'])['ports']
+ device_id=sid, network_id=network_id)['ports']
]
+
self.assertEqual(1, len(ports),
message=("Multiple IPv6 ports found on network %s. "
"ports: %s")
- % (self.network_v6, ports))
+ % (network_id, ports))
mac6 = ports[0]
ssh.set_nic_state(ssh.get_nic_name_by_mac(mac6))
@@ -168,8 +168,9 @@
# Turn on 2nd NIC for Cirros when dualnet
if dualnet:
- self.turn_nic6_on(sshv4_1, sid1)
- self.turn_nic6_on(sshv4_2, sid2)
+ network, network_v6 = net_list
+ self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
+ self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
# get addresses assigned to vNIC as reported by 'ip address' utility
ips_from_ip_1 = sshv4_1.exec_command("ip address")
diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py
index 9eaaaaf..e435fe2 100644
--- a/tempest/tests/lib/services/identity/v3/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_identity_client.py
@@ -32,6 +32,34 @@
"description": "test_description"
}
+ FAKE_AUTH_PROJECTS = {
+ "projects": [
+ {
+ "domain_id": "1789d1",
+ "enabled": True,
+ "id": "263fd9",
+ "links": {
+ "self": "https://example.com/identity/v3/projects/263fd9"
+ },
+ "name": "Test Group"
+ },
+ {
+ "domain_id": "1789d1",
+ "enabled": True,
+ "id": "50ef01",
+ "links": {
+ "self": "https://example.com/identity/v3/projects/50ef01"
+ },
+ "name": "Build Group"
+ }
+ ],
+ "links": {
+ "self": "https://example.com/identity/v3/auth/projects",
+ "previous": None,
+ "next": None
+ }
+ }
+
def setUp(self):
super(TestIdentityClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -54,6 +82,13 @@
bytes_body,
resp_token="cbc36478b0bd8e67e89")
+ def _test_list_auth_projects(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_auth_projects,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_AUTH_PROJECTS,
+ bytes_body)
+
def test_show_api_description_with_str_body(self):
self._test_show_api_description()
@@ -73,3 +108,9 @@
{},
resp_token="cbc36478b0bd8e67e89",
status=204)
+
+ def test_list_auth_projects_with_str_body(self):
+ self._test_list_auth_projects()
+
+ def test_list_auth_projects_with_bytes_body(self):
+ self._test_list_auth_projects(bytes_body=True)
diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py
new file mode 100644
index 0000000..6234b06
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_versions_client.py
@@ -0,0 +1,94 @@
+# Copyright 2017 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.
+
+from tempest.lib.services.image.v2 import versions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVersionsClient(base.BaseServiceTest):
+
+ FAKE_VERSIONS_INFO = {
+ "versions": [
+ {
+ "status": "CURRENT", "id": "v2.5",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "SUPPORTED", "id": "v2.4",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "SUPPORTED", "id": "v2.3",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "SUPPORTED", "id": "v2.2",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "SUPPORTED", "id": "v2.1",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "SUPPORTED", "id": "v2.0",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v2/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "DEPRECATED", "id": "v1.1",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v1/", "rel": "self"}
+ ]
+ },
+ {
+ "status": "DEPRECATED", "id": "v1.0",
+ "links": [
+ {"href": "https://10.220.1.21:9292/v1/", "rel": "self"}
+ ]
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestVersionsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = versions_client.VersionsClient(fake_auth,
+ 'image',
+ 'regionOne')
+
+ def _test_list_versions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_versions,
+ 'tempest.lib.common.rest_client.RestClient.raw_request',
+ self.FAKE_VERSIONS_INFO,
+ bytes_body,
+ 300)
+
+ def test_list_versions_with_str_body(self):
+ self._test_list_versions()
+
+ def test_list_versions_with_bytes_body(self):
+ self._test_list_versions(bytes_body=True)