Merge "Keystone v3 extension os-ep-filter api testcases"
diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml
new file mode 100644
index 0000000..69320fb
--- /dev/null
+++ b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Defines the identity v3 OS-EP-FILTER extension API client.
+ This client manages associations between endpoints, projects
+ along with groups.
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 6075026..10121d9 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -223,6 +223,7 @@
cls.role_assignments = cls.os_admin.role_assignments_client
cls.oauth_consumers_client = cls.os_adm.oauth_consumers_client
cls.domain_config_client = cls.os_adm.domain_config_client
+ cls.endpoint_filter_client = cls.os_adm.endpoint_filter_client
if CONF.identity.admin_domain_scope:
# NOTE(andreaf) When keystone policy requires it, the identity
# admin clients for these tests shall use 'domain' scoped tokens.
diff --git a/tempest/clients.py b/tempest/clients.py
index 4ef6872..e000a74 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -231,6 +231,8 @@
**params_v3)
self.domain_config_client = self.identity_v3.DomainConfigurationClient(
**params_v3)
+ self.endpoint_filter_client = \
+ self.identity_v3.EndPointsFilterClient(**params_v3)
# Token clients do not use the catalog. They only need default_params.
# They read auth_url, so they should only be set if the corresponding
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index f2f3391..6f498d9 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -17,6 +17,8 @@
from tempest.lib.services.identity.v3.domain_configuration_client \
import DomainConfigurationClient
from tempest.lib.services.identity.v3.domains_client import DomainsClient
+from tempest.lib.services.identity.v3.endpoint_filter_client import \
+ EndPointsFilterClient
from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
from tempest.lib.services.identity.v3.groups_client import GroupsClient
from tempest.lib.services.identity.v3.identity_client import IdentityClient
@@ -37,8 +39,8 @@
from tempest.lib.services.identity.v3.versions_client import VersionsClient
__all__ = ['CredentialsClient', 'DomainsClient', 'DomainConfigurationClient',
- 'EndPointsClient', 'GroupsClient', 'IdentityClient',
- 'InheritedRolesClient', 'OAUTHConsumerClient', 'PoliciesClient',
- 'ProjectsClient', 'RegionsClient', 'RoleAssignmentsClient',
- 'RolesClient', 'ServicesClient', 'V3TokenClient', 'TrustsClient',
- 'UsersClient', 'VersionsClient']
+ 'EndPointsClient', 'EndPointsFilterClient', 'GroupsClient',
+ 'IdentityClient', 'InheritedRolesClient', 'OAUTHConsumerClient',
+ 'PoliciesClient', 'ProjectsClient', 'RegionsClient',
+ 'RoleAssignmentsClient', 'RolesClient', 'ServicesClient',
+ 'V3TokenClient', 'TrustsClient', 'UsersClient', 'VersionsClient']
diff --git a/tempest/lib/services/identity/v3/endpoint_filter_client.py b/tempest/lib/services/identity/v3/endpoint_filter_client.py
new file mode 100644
index 0000000..a8cd722
--- /dev/null
+++ b/tempest/lib/services/identity/v3/endpoint_filter_client.py
@@ -0,0 +1,68 @@
+# Copyright 2017 AT&T Corp.
+# 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.
+
+"""
+https://developer.openstack.org/api-ref/identity/v3-ext/#os-ep-filter-api
+"""
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class EndPointsFilterClient(rest_client.RestClient):
+ api_version = "v3"
+ ep_filter = "OS-EP-FILTER"
+
+ def list_projects_for_endpoint(self, endpoint_id):
+ """List all projects that are associated with the endpoint."""
+ resp, body = self.get(self.ep_filter + '/endpoints/%s/projects' %
+ endpoint_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def add_endpoint_to_project(self, project_id, endpoint_id):
+ """Add association between project and endpoint. """
+ body = None
+ resp, body = self.put(
+ self.ep_filter + '/projects/%s/endpoints/%s' %
+ (project_id, endpoint_id), body)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def check_endpoint_in_project(self, project_id, endpoint_id):
+ """Check association of Project with Endpoint."""
+ resp, body = self.head(
+ self.ep_filter + '/projects/%s/endpoints/%s' %
+ (project_id, endpoint_id), None)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_endpoints_in_project(self, project_id):
+ """List Endpoints associated with Project."""
+ resp, body = self.get(self.ep_filter + '/projects/%s/endpoints'
+ % project_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_endpoint_from_project(self, project_id, endpoint_id):
+ """Delete association between project and endpoint."""
+ resp, body = self.delete(
+ self.ep_filter + '/projects/%s/endpoints/%s'
+ % (project_id, endpoint_id))
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py
new file mode 100644
index 0000000..7faf6a0
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py
@@ -0,0 +1,165 @@
+# Copyright 2017 AT&T Corp.
+# 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.identity.v3 import endpoint_filter_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEndPointsFilterClient(base.BaseServiceTest):
+ FAKE_LIST_PROJECTS_FOR_ENDPOINTS = {
+ "projects": [
+ {
+ "domain_id": "1777c7",
+ "enabled": True,
+ "id": "1234ab1",
+ "type": "compute",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/1234ab1"
+ },
+ "name": "Project 1",
+ "description": "Project 1 description",
+ },
+ {
+ "domain_id": "1777c7",
+ "enabled": True,
+ "id": "5678cd2",
+ "type": "compute",
+ "links": {
+ "self": "http://example.com/identity/v3/projects/5678cd2"
+ },
+ "name": "Project 2",
+ "description": "Project 2 description",
+ }
+ ],
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/endpoints/\
+ u6ay5u/projects",
+ "previous": None,
+ "next": None
+ }
+ }
+
+ FAKE_LIST_ENDPOINTS_FOR_PROJECTS = {
+ "endpoints": [
+ {
+ "id": "u6ay5u",
+ "interface": "public",
+ "url": "http://example.com/identity/",
+ "region": "north",
+ "links": {
+ "self": "http://example.com/identity/v3/endpoints/u6ay5u"
+ },
+ "service_id": "5um4r",
+ },
+ {
+ "id": "u6ay5u",
+ "interface": "internal",
+ "url": "http://example.com/identity/",
+ "region": "south",
+ "links": {
+ "self": "http://example.com/identity/v3/endpoints/u6ay5u"
+ },
+ "service_id": "5um4r",
+ },
+ ],
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/projects/\
+ 1234ab1/endpoints",
+ "previous": None,
+ "next": None
+ }
+ }
+
+ def setUp(self):
+ super(TestEndPointsFilterClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = endpoint_filter_client.EndPointsFilterClient(
+ fake_auth, 'identity', 'regionOne')
+
+ def _test_add_endpoint_to_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.add_endpoint_to_project,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ bytes_body,
+ status=204,
+ project_id=3,
+ endpoint_id=4)
+
+ def _test_check_endpoint_in_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_endpoint_in_project,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ bytes_body,
+ status=204,
+ project_id=3,
+ endpoint_id=4)
+
+ def _test_list_projects_for_endpoint(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_projects_for_endpoint,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_PROJECTS_FOR_ENDPOINTS,
+ bytes_body,
+ status=200,
+ endpoint_id=3)
+
+ def _test_list_endpoints_in_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints_in_project,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINTS_FOR_PROJECTS,
+ bytes_body,
+ status=200,
+ project_id=4)
+
+ def _test_delete_endpoint_from_project(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.delete_endpoint_from_project,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ bytes_body,
+ status=204,
+ project_id=3,
+ endpoint_id=4)
+
+ def test_add_endpoint_to_project_with_str_body(self):
+ self._test_add_endpoint_to_project()
+
+ def test_add_endpoint_to_project_with_bytes_body(self):
+ self._test_add_endpoint_to_project(bytes_body=True)
+
+ def test_check_endpoint_in_project_with_str_body(self):
+ self._test_check_endpoint_in_project()
+
+ def test_check_endpoint_in_project_with_bytes_body(self):
+ self._test_check_endpoint_in_project(bytes_body=True)
+
+ def test_list_projects_for_endpoint_with_str_body(self):
+ self._test_list_projects_for_endpoint()
+
+ def test_list_projects_for_endpoint_with_bytes_body(self):
+ self._test_list_projects_for_endpoint(bytes_body=True)
+
+ def test_list_endpoints_in_project_with_str_body(self):
+ self._test_list_endpoints_in_project()
+
+ def test_list_endpoints_in_project_with_bytes_body(self):
+ self._test_list_endpoints_in_project(bytes_body=True)
+
+ def test_delete_endpoint_from_project(self):
+ self._test_delete_endpoint_from_project()