From 8d90866014f6c70802e6ca61d3faa80ff087bf30 Mon Sep 17 00:00:00 2001 From: Rodrigo Duarte Date: Wed, 6 Apr 2016 11:52:19 -0300 Subject: [PATCH] Add identity providers integration tests This patch adds a first set of tests in the keystone tempest plugin. These tests are for the Identity Provider API (part of the Federated Identity API). To run the tests install keystone and run (in tempest): $ tox -e all-plugin -- keystone Change-Id: I64ebba2e57aa952a2262f9e0ad143cea7de259c0 --- keystone_tempest_plugin/clients.py | 28 +++++ .../services/identity/__init__.py | 0 .../services/identity/clients.py | 36 ++++++ .../services/identity/v3/__init__.py | 0 .../identity/v3/identity_providers_client.py | 79 ++++++++++++ .../tests/api/identity/__init__.py | 0 .../tests/api/identity/base.py | 36 ++++++ .../tests/api/identity/v3/__init__.py | 0 .../tests/api/identity/v3/fixtures.py | 28 +++++ .../identity/v3/test_identity_providers.py | 116 ++++++++++++++++++ 10 files changed, 323 insertions(+) create mode 100644 keystone_tempest_plugin/clients.py create mode 100644 keystone_tempest_plugin/services/identity/__init__.py create mode 100644 keystone_tempest_plugin/services/identity/clients.py create mode 100644 keystone_tempest_plugin/services/identity/v3/__init__.py create mode 100644 keystone_tempest_plugin/services/identity/v3/identity_providers_client.py create mode 100644 keystone_tempest_plugin/tests/api/identity/__init__.py create mode 100644 keystone_tempest_plugin/tests/api/identity/base.py create mode 100644 keystone_tempest_plugin/tests/api/identity/v3/__init__.py create mode 100644 keystone_tempest_plugin/tests/api/identity/v3/fixtures.py create mode 100644 keystone_tempest_plugin/tests/api/identity/v3/test_identity_providers.py diff --git a/keystone_tempest_plugin/clients.py b/keystone_tempest_plugin/clients.py new file mode 100644 index 0000000000..35d44556a3 --- /dev/null +++ b/keystone_tempest_plugin/clients.py @@ -0,0 +1,28 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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 keystone_tempest_plugin.services.identity.v3 import ( + identity_providers_client) + +from tempest import clients + + +class Manager(clients.Manager): + + def __init__(self, credentials, service=None): + super(Manager, self).__init__(credentials, service) + + self.identity_providers_client = ( + identity_providers_client.IdentityProvidersClient( + self.auth_provider)) diff --git a/keystone_tempest_plugin/services/identity/__init__.py b/keystone_tempest_plugin/services/identity/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone_tempest_plugin/services/identity/clients.py b/keystone_tempest_plugin/services/identity/clients.py new file mode 100644 index 0000000000..f796cd7024 --- /dev/null +++ b/keystone_tempest_plugin/services/identity/clients.py @@ -0,0 +1,36 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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 import config +from tempest.lib.common import rest_client + + +CONF = config.CONF + +# We only use the identity catalog type +SERVICE_TYPE = 'identity' + + +class Identity(rest_client.RestClient): + """Tempest REST client for keystone.""" + + # Used by the superclass to build the correct URL paths + api_version = 'v3' + + def __init__(self, auth_provider): + super(Identity, self).__init__( + auth_provider, + SERVICE_TYPE, + CONF.identity.region, + endpoint_type='adminURL') diff --git a/keystone_tempest_plugin/services/identity/v3/__init__.py b/keystone_tempest_plugin/services/identity/v3/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone_tempest_plugin/services/identity/v3/identity_providers_client.py b/keystone_tempest_plugin/services/identity/v3/identity_providers_client.py new file mode 100644 index 0000000000..38d35df4ac --- /dev/null +++ b/keystone_tempest_plugin/services/identity/v3/identity_providers_client.py @@ -0,0 +1,79 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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 json + +from tempest.lib.common import rest_client + +from keystone_tempest_plugin.services.identity import clients + + +class IdentityProvidersClient(clients.Identity): + + subpath = 'OS-FEDERATION/identity_providers' + + def _build_path(self, idp_id=None): + return '%s/%s' % (self.subpath, idp_id) if idp_id else self.subpath + + def create_identity_provider(self, idp_id, **kwargs): + """Create an identity provider. + + :param str idp_id: The ID to be used to create the Identity Provider. + :param kwargs: All optional attributes: description (str), enabled + (boolean) and remote_ids (list). + """ + put_body = json.dumps({'identity_provider': kwargs}) + url = self._build_path(idp_id) + resp, body = self.put(url, put_body) + self.expected_success(201, resp.status) + body = json.loads(body) + idp = rest_client.ResponseBody(resp, body) + return idp + + def list_identity_providers(self): + """List the identity providers.""" + url = self._build_path() + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + def show_identity_provider(self, idp_id): + """Get an identity provider.""" + url = self._build_path(idp_id) + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + def delete_identity_provider(self, idp_id): + """Delete an identity provider.""" + url = self._build_path(idp_id) + resp, body = self.delete(url) + self.expected_success(204, resp.status) + return rest_client.ResponseBody(resp, body) + + def update_identity_provider(self, idp_id, **kwargs): + """Update an identity provider. + + :param str idp_id: The ID from the Identity Provider to be updated. + :param kwargs: All optional attributes to update: description (str), + enabled (boolean) and remote_ids (list). + """ + patch_body = json.dumps({'identity_provider': kwargs}) + url = self._build_path(idp_id) + resp, body = self.patch(url, patch_body) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) diff --git a/keystone_tempest_plugin/tests/api/identity/__init__.py b/keystone_tempest_plugin/tests/api/identity/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone_tempest_plugin/tests/api/identity/base.py b/keystone_tempest_plugin/tests/api/identity/base.py new file mode 100644 index 0000000000..ceefee0a0b --- /dev/null +++ b/keystone_tempest_plugin/tests/api/identity/base.py @@ -0,0 +1,36 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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.common import credentials_factory as common_creds +from tempest import test + +from keystone_tempest_plugin import clients + + +class BaseIdentityTest(test.BaseTestCase): + + # The version of the identity that will be used in the tests. + identity_version = 'v3' + + # NOTE(rodrigods): for now, all tests are in the admin scope, if + # necessary, another class can be created to handle non-admin tests. + credential_type = 'identity_admin' + + @classmethod + def setup_clients(cls): + super(BaseIdentityTest, cls).setup_clients() + credentials = common_creds.get_configured_credentials( + cls.credential_type, identity_version=cls.identity_version) + cls.keystone_manager = clients.Manager(credentials=credentials) + cls.idps_client = cls.keystone_manager.identity_providers_client diff --git a/keystone_tempest_plugin/tests/api/identity/v3/__init__.py b/keystone_tempest_plugin/tests/api/identity/v3/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone_tempest_plugin/tests/api/identity/v3/fixtures.py b/keystone_tempest_plugin/tests/api/identity/v3/fixtures.py new file mode 100644 index 0000000000..351320b152 --- /dev/null +++ b/keystone_tempest_plugin/tests/api/identity/v3/fixtures.py @@ -0,0 +1,28 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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.common.utils import data_utils + + +def idp_ref(enabled=None, remote_ids=None): + ref = { + 'description': data_utils.rand_uuid_hex(), + } + if enabled is not None: + ref['enabled'] = enabled + + if remote_ids: + ref['remote_ids'] = remote_ids + + return ref diff --git a/keystone_tempest_plugin/tests/api/identity/v3/test_identity_providers.py b/keystone_tempest_plugin/tests/api/identity/v3/test_identity_providers.py new file mode 100644 index 0000000000..5e1e2cfa29 --- /dev/null +++ b/keystone_tempest_plugin/tests/api/identity/v3/test_identity_providers.py @@ -0,0 +1,116 @@ +# Copyright 2016 Red Hat, Inc. +# +# 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.common.utils import data_utils +from tempest.lib import decorators + +from keystone_tempest_plugin.tests.api.identity import base +from keystone_tempest_plugin.tests.api.identity.v3 import fixtures + + +class IndentityProvidersTest(base.BaseIdentityTest): + + def _assert_identity_provider_attributes(self, idp, idp_id, idp_ref=None): + self.assertIn('id', idp) + self.assertEqual(idp_id, idp['id']) + + # Check the optional attributes have been set + self.assertIn('description', idp) + self.assertIn('enabled', idp) + self.assertIn('remote_ids', idp) + + if idp_ref: + self.assertEqual(idp_ref['description'], idp['description']) + + if 'enabled' in idp_ref: + self.assertEqual(idp_ref['enabled'], idp['enabled']) + + if 'remote_ids' in idp_ref: + self.assertItemsEqual(idp_ref['remote_ids'], idp['remote_ids']) + + def _create_idp(self, idp_id, idp_ref): + idp = self.idps_client.create_identity_provider( + idp_id, **idp_ref)['identity_provider'] + self.addCleanup( + self.idps_client.delete_identity_provider, idp_id) + return idp + + @decorators.idempotent_id('09450910-b816-4150-8513-a2fd4628a0c3') + def test_identity_provider_create(self): + idp_id = data_utils.rand_uuid_hex() + idp_ref = fixtures.idp_ref() + idp = self._create_idp(idp_id, idp_ref) + + # The identity provider is disabled by default + idp_ref['enabled'] = False + + # The remote_ids attribute should be set to an empty list by default + idp_ref['remote_ids'] = [] + + self._assert_identity_provider_attributes(idp, idp_id, idp_ref) + + @decorators.idempotent_id('f430a337-545d-455e-bb6c-cb0fdf4be5c1') + def test_identity_provider_create_with_enabled_true(self): + idp_id = data_utils.rand_uuid_hex() + idp_ref = fixtures.idp_ref(enabled=True) + idp = self._create_idp(idp_id, idp_ref) + + self._assert_identity_provider_attributes(idp, idp_id, idp_ref) + + @decorators.idempotent_id('238e6163-d600-4f59-9982-c621f057221d') + def test_identity_provider_create_with_remote_ids(self): + idp_id = data_utils.rand_uuid_hex() + remote_ids = [data_utils.rand_uuid_hex(), data_utils.rand_uuid_hex()] + idp_ref = fixtures.idp_ref(remote_ids=remote_ids) + idp = self._create_idp(idp_id, idp_ref) + + self._assert_identity_provider_attributes(idp, idp_id, idp_ref) + + @decorators.idempotent_id('8a7817ad-27f8-436b-9cbe-46aa20989beb') + def test_identity_provider_get(self): + idp_id = data_utils.rand_uuid_hex() + idp_create = self._create_idp(idp_id, fixtures.idp_ref()) + + idp_get = self.idps_client.show_identity_provider( + idp_id)['identity_provider'] + self._assert_identity_provider_attributes(idp_get, idp_id, idp_create) + + @decorators.idempotent_id('cbfe5de9-c58a-4810-950c-2acdf985879d') + def test_identity_provider_list(self): + idp_ids = [] + for _ in range(3): + idp_id = data_utils.rand_uuid_hex() + self._create_idp(idp_id, fixtures.idp_ref()) + idp_ids.append(idp_id) + + idp_list = self.idps_client.list_identity_providers()[ + 'identity_providers'] + fetched_ids = [fetched_idp['id'] for fetched_idp in idp_list] + + for idp_id in idp_ids: + self.assertIn(idp_id, fetched_ids) + + @decorators.idempotent_id('36a0d9f0-9517-4139-85d0-f78d905aece5') + def test_identity_provider_update(self): + idp_id = data_utils.rand_uuid_hex() + idp = self._create_idp(idp_id, fixtures.idp_ref(enabled=True)) + + # The identity provider should be enabled + self.assertTrue(idp['enabled']) + + idp = self.idps_client.update_identity_provider( + idp_id, enabled=False)['identity_provider'] + + # The identity provider should be disabled + self.assertFalse(idp['enabled'])