Merge "Add "list Glance API versions" test"
diff --git a/README.rst b/README.rst
index 3d7c804..f44c503 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
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/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/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/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/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/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)