Implied roles methods

Adds the implied roles API calls to the roles_client library:
create, get, check and delete inference rules.

This will enable the possibility to create additional identity
API tests for some features, like implied roles and domain
specific roles.

Change-Id: I1587eb862fac5b533aa4715334d54c86d9af85ff
diff --git a/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
new file mode 100644
index 0000000..9116ef8
--- /dev/null
+++ b/releasenotes/notes/add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add the implied roles feature API to the roles_client library. This
+    feature enables the possibility to create inferences rules between
+    roles (a role being implied by another role).
diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py
index f1339dd..0df23ce 100644
--- a/tempest/lib/services/identity/v3/roles_client.py
+++ b/tempest/lib/services/identity/v3/roles_client.py
@@ -190,3 +190,40 @@
                                (domain_id, group_id, role_id))
         self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp)
+
+    def create_role_inference_rule(self, prior_role, implies_role):
+        """Create a role inference rule."""
+        resp, body = self.put('roles/%s/implies/%s' %
+                              (prior_role, implies_role), None)
+        self.expected_success(201, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def show_role_inference_rule(self, prior_role, implies_role):
+        """Get a role inference rule."""
+        resp, body = self.get('roles/%s/implies/%s' %
+                              (prior_role, implies_role))
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def list_role_inferences_rules(self, prior_role):
+        """List the inferences rules from a role."""
+        resp, body = self.get('roles/%s/implies' % prior_role)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def check_role_inference_rule(self, prior_role, implies_role):
+        """Check a role inference rule."""
+        resp, body = self.head('roles/%s/implies/%s' %
+                               (prior_role, implies_role))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
+
+    def delete_role_inference_rule(self, prior_role, implies_role):
+        """Delete a role inference rule."""
+        resp, body = self.delete('roles/%s/implies/%s' %
+                                 (prior_role, implies_role))
+        self.expected_success(204, resp.status)
+        return rest_client.ResponseBody(resp)
diff --git a/tempest/tests/lib/services/identity/v3/test_roles_client.py b/tempest/tests/lib/services/identity/v3/test_roles_client.py
index 4f70b47..41cea85 100644
--- a/tempest/tests/lib/services/identity/v3/test_roles_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_roles_client.py
@@ -52,6 +52,65 @@
 
     FAKE_LIST_ROLES = {"roles": [FAKE_ROLE_INFO, FAKE_ROLE_INFO_2]}
 
+    FAKE_ROLE_INFERENCE_RULE = {
+        "role_inference": {
+            "prior_role": {
+                "id": FAKE_ROLE_ID,
+                "name": FAKE_ROLE_NAME,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID)
+                }
+            },
+            "implies": {
+                "id": FAKE_ROLE_ID_2,
+                "name": FAKE_ROLE_NAME_2,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID_2)
+                }
+            }
+        },
+        "links": {
+            "self": "http://example.com/identity/v3/roles/"
+                    "%s/implies/%s" % (FAKE_ROLE_ID, FAKE_ROLE_ID_2)
+        }
+    }
+
+    FAKE_LIST_ROLE_INFERENCES_RULES = {
+        "role_inference": {
+            "prior_role": {
+                "id": FAKE_ROLE_ID,
+                "name": FAKE_ROLE_NAME,
+                "links": {
+                    "self": "http://example.com/identity/v3/roles/%s" % (
+                        FAKE_ROLE_ID)
+                }
+            },
+            "implies": [
+                {
+                    "id": FAKE_ROLE_ID_2,
+                    "name": FAKE_ROLE_NAME_2,
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/%s" % (
+                            FAKE_ROLE_ID_2)
+                    }
+                },
+                {
+                    "id": "3",
+                    "name": "test3",
+                    "links": {
+                        "self": "http://example.com/identity/v3/roles/3"
+                    }
+                }
+            ]
+        },
+        "links": {
+            "self": "http://example.com/identity/v3/roles/"
+                    "%s/implies" % FAKE_ROLE_ID
+        }
+    }
+
     def setUp(self):
         super(TestRolesClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -172,6 +231,33 @@
             domain_id="b344506af7644f6794d9cb316600b020",
             group_id="123")
 
+    def _test_create_role_inference_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.create_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.put',
+            self.FAKE_ROLE_INFERENCE_RULE,
+            bytes_body,
+            status=201,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def _test_show_role_inference_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.show_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_ROLE_INFERENCE_RULE,
+            bytes_body,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def _test_list_role_inferences_rules(self, bytes_body=False):
+        self.check_service_client_function(
+            self.client.list_role_inferences_rules,
+            'tempest.lib.common.rest_client.RestClient.get',
+            self.FAKE_LIST_ROLE_INFERENCES_RULES,
+            bytes_body,
+            prior_role=self.FAKE_ROLE_ID)
+
     def test_create_role_with_str_body(self):
         self._test_create_role()
 
@@ -319,3 +405,39 @@
             group_id="123",
             role_id="1234",
             status=204)
+
+    def test_create_role_inference_rule_with_str_body(self):
+        self._test_create_role_inference_rule()
+
+    def test_create_role_inference_rule_with_bytes_body(self):
+        self._test_create_role_inference_rule(bytes_body=True)
+
+    def test_show_role_inference_rule_with_str_body(self):
+        self._test_show_role_inference_rule()
+
+    def test_show_role_inference_rule_with_bytes_body(self):
+        self._test_show_role_inference_rule(bytes_body=True)
+
+    def test_list_role_inferences_rules_with_str_body(self):
+        self._test_list_role_inferences_rules()
+
+    def test_list_role_inferences_rules_with_bytes_body(self):
+        self._test_list_role_inferences_rules(bytes_body=True)
+
+    def test_check_role_inference_rule(self):
+        self.check_service_client_function(
+            self.client.check_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.head',
+            {},
+            status=204,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)
+
+    def test_delete_role_inference_rule(self):
+        self.check_service_client_function(
+            self.client.delete_role_inference_rule,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            prior_role=self.FAKE_ROLE_ID,
+            implies_role=self.FAKE_ROLE_ID_2)