blob: 1c47985488b61975f63ed50012af2fce51858cd7 [file] [log] [blame]
Felipe Monteiroffa47e62017-07-05 03:37:55 +01001# Copyright 2017 AT&T Corporation.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16"""Fixtures for Patrole tests."""
17from __future__ import absolute_import
18
19import fixtures
20import mock
Felipe Monteirob18a3f62017-09-19 04:25:51 +010021import time
Felipe Monteiroffa47e62017-07-05 03:37:55 +010022
Felipe Monteiro3e14f472017-08-17 23:02:11 +010023from tempest import clients
24from tempest.common import credentials_factory as credentials
Felipe Monteiroffa47e62017-07-05 03:37:55 +010025from tempest import config
Felipe Monteirob18a3f62017-09-19 04:25:51 +010026from tempest import test
Felipe Monteiroffa47e62017-07-05 03:37:55 +010027
28from patrole_tempest_plugin import rbac_utils
29
30
31CONF = config.CONF
32
33
34class ConfPatcher(fixtures.Fixture):
35 """Fixture to patch and restore global CONF. Adopted from Nova.
36
37 This also resets overrides for everything that is patched during
38 its teardown.
39 """
40
41 def __init__(self, **kwargs):
42 """Constructor
43
44 :params group: if specified all config options apply to that group.
45 :params **kwargs: the rest of the kwargs are processed as a
46 set of key/value pairs to be set as configuration override.
47 """
48 super(ConfPatcher, self).__init__()
49 self.group = kwargs.pop('group', None)
50 self.args = kwargs
51
52 def setUp(self):
53 super(ConfPatcher, self).setUp()
54 for k, v in self.args.items():
55 self.addCleanup(CONF.clear_override, k, self.group)
56 CONF.set_override(k, v, self.group)
57
58
59class RbacUtilsFixture(fixtures.Fixture):
Felipe Monteiro2693bf72017-08-12 22:56:47 +010060 """Fixture for `RbacUtils` class."""
Felipe Monteiroffa47e62017-07-05 03:37:55 +010061
62 USER_ID = mock.sentinel.user_id
63 PROJECT_ID = mock.sentinel.project_id
64
Felipe Monteiroffa47e62017-07-05 03:37:55 +010065 def setUp(self):
66 super(RbacUtilsFixture, self).setUp()
67
Felipe Monteirof6eb8622017-08-06 06:08:02 +010068 self.useFixture(ConfPatcher(rbac_test_role='member', group='patrole'))
Felipe Monteiroffa47e62017-07-05 03:37:55 +010069 self.useFixture(ConfPatcher(
70 admin_role='admin', auth_version='v3', group='identity'))
71
72 test_obj_kwargs = {
73 'os_primary.credentials.user_id': self.USER_ID,
74 'os_primary.credentials.tenant_id': self.PROJECT_ID,
75 'os_primary.credentials.project_id': self.PROJECT_ID,
76 'get_identity_version.return_value': 'v3'
77 }
Felipe Monteirob18a3f62017-09-19 04:25:51 +010078 self.mock_test_obj = mock.Mock(
79 __name__='patrole_unit_test', spec=test.BaseTestCase,
Mykola Yakovliev1d829782018-08-03 14:37:37 -050080 os_primary=mock.Mock(),
81 get_auth_providers=mock.Mock(return_value=[mock.Mock()]),
82 **test_obj_kwargs)
Felipe Monteiroffa47e62017-07-05 03:37:55 +010083
Felipe Monteirob18a3f62017-09-19 04:25:51 +010084 # Mock out functionality that can't be used by unit tests. Mocking out
85 # time.sleep is a test optimization.
86 self.mock_time = mock.patch.object(
87 rbac_utils, 'time', __name__='mock_time', spec=time).start()
88 mock.patch.object(credentials, 'get_configured_admin_credentials',
89 spec=object).start()
90 mock_admin_mgr = mock.patch.object(
91 clients, 'Manager', spec=clients.Manager,
92 roles_v3_client=mock.Mock(), roles_client=mock.Mock()).start()
Felipe Monteiro3e14f472017-08-17 23:02:11 +010093 self.roles_v3_client = mock_admin_mgr.return_value.roles_v3_client
Felipe Monteiroffa47e62017-07-05 03:37:55 +010094
Felipe Monteiro2693bf72017-08-12 22:56:47 +010095 self.set_roles(['admin', 'member'], [])
96
Felipe Monteiro10e82fd2017-11-21 01:47:20 +000097 def override_role(self, *role_toggles):
98 """Instantiate `rbac_utils.RbacUtils` and call `override_role`.
Felipe Monteiroffa47e62017-07-05 03:37:55 +010099
Felipe Monteiro10e82fd2017-11-21 01:47:20 +0000100 Create an instance of `rbac_utils.RbacUtils` and call `override_role`
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100101 for each boolean value in `role_toggles`. The number of calls to
Felipe Monteiro10e82fd2017-11-21 01:47:20 +0000102 `override_role` is always 1 + len(`role_toggles`) because the
103 `rbac_utils.RbacUtils` constructor automatically calls `override_role`.
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100104
105 :param role_toggles: the list of boolean values iterated over and
Felipe Monteiro10e82fd2017-11-21 01:47:20 +0000106 passed to `override_role`.
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100107 """
Felipe Monteiro10e82fd2017-11-21 01:47:20 +0000108 _rbac_utils = rbac_utils.RbacUtils(self.mock_test_obj)
Felipe Monteiro2693bf72017-08-12 22:56:47 +0100109
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100110 for role_toggle in role_toggles:
Felipe Monteiro10e82fd2017-11-21 01:47:20 +0000111 _rbac_utils._override_role(self.mock_test_obj, role_toggle)
Felipe Monteiro2693bf72017-08-12 22:56:47 +0100112 # NOTE(felipemonteiro): Simulate that a role switch has occurred
113 # by updating the user's current role to the new role. This means
114 # that all API actions involved during a role switch -- listing,
115 # deleting and adding roles -- are executed, making it easier to
116 # assert that mock calls were called as expected.
117 new_role = 'member' if role_toggle else 'admin'
118 self.set_roles(['admin', 'member'], [new_role])
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100119
Felipe Monteiro2693bf72017-08-12 22:56:47 +0100120 def set_roles(self, roles, roles_on_project=None):
121 """Set the list of available roles in the system.
122
123 :param roles: List of roles returned by ``list_roles``.
124 :param roles_on_project: List of roles returned by
125 ``list_user_roles_on_project``.
126 :returns: None.
127 """
128 if not roles_on_project:
129 roles_on_project = []
130 if not isinstance(roles, list):
131 roles = [roles]
132 if not isinstance(roles_on_project, list):
133 roles_on_project = [roles_on_project]
134
135 available_roles = {
Felipe Monteiroffa47e62017-07-05 03:37:55 +0100136 'roles': [{'name': role, 'id': '%s_id' % role} for role in roles]
137 }
Felipe Monteiro2693bf72017-08-12 22:56:47 +0100138 available_project_roles = {
139 'roles': [{'name': role, 'id': '%s_id' % role}
140 for role in roles_on_project]
141 }
142
143 self.roles_v3_client.list_roles.return_value = available_roles
144 self.roles_v3_client.list_user_roles_on_project.return_value = (
145 available_project_roles)