Merge ~blake-rouse/maas:rbac-pools-cache-perms into maas:master
- Git
- lp:~blake-rouse/maas
- rbac-pools-cache-perms
- Merge into master
Proposed by
Blake Rouse
Status: | Superseded |
---|---|
Proposed branch: | ~blake-rouse/maas:rbac-pools-cache-perms |
Merge into: | maas:master |
Diff against target: |
351 lines (+162/-37) 7 files modified
src/maasserver/models/__init__.py (+23/-9) src/maasserver/models/node.py (+4/-4) src/maasserver/models/resourcepool.py (+2/-1) src/maasserver/rbac.py (+49/-10) src/maasserver/testing/fixtures.py (+25/-1) src/maasserver/tests/test_auth.py (+24/-0) src/maasserver/tests/test_rbac.py (+35/-12) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Maintainers | Pending | ||
Review via email: mp+359062@code.launchpad.net |
This proposal has been superseded by a proposal from 2018-11-20.
Commit message
Use a thread-local cache to cache resource pool identifiers per request.
Description of the change
To post a comment you must log in.
- 37c1e2a... by Blake Rouse
-
Add tests.
Unmerged commits
- 37c1e2a... by Blake Rouse
-
Add tests.
- bcd535d... by Blake Rouse
-
Split 1.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/models/__init__.py b/src/maasserver/models/__init__.py | |||
2 | index 3888e17..ca79112 100644 | |||
3 | --- a/src/maasserver/models/__init__.py | |||
4 | +++ b/src/maasserver/models/__init__.py | |||
5 | @@ -348,12 +348,10 @@ class MAASAuthorizationBackend(ModelBackend): | |||
6 | 348 | rbac_enabled = rbac.is_enabled() | 348 | rbac_enabled = rbac.is_enabled() |
7 | 349 | visible_pools, admin_pools = [], [] | 349 | visible_pools, admin_pools = [], [] |
8 | 350 | if rbac_enabled: | 350 | if rbac_enabled: |
15 | 351 | visible_pools = rbac.get_resource_pools( | 351 | visible_pools = rbac.get_resource_pool_ids( |
16 | 352 | user.username, 'view').values_list( | 352 | user.username, 'view') |
17 | 353 | 'id', flat=True) | 353 | admin_pools = rbac.get_resource_pool_ids( |
18 | 354 | admin_pools = rbac.get_resource_pools( | 354 | user.username, 'admin-machines') |
13 | 355 | user.username, 'admin-machines').values_list( | ||
14 | 356 | 'id', flat=True) | ||
19 | 357 | 355 | ||
20 | 358 | # Sanity check that a `ResourcePool` is being checked against | 356 | # Sanity check that a `ResourcePool` is being checked against |
21 | 359 | # `ResourcePoolPermission`. | 357 | # `ResourcePoolPermission`. |
22 | @@ -363,6 +361,22 @@ class MAASAuthorizationBackend(ModelBackend): | |||
23 | 363 | 'obj type of ResourcePool must be checked ' | 361 | 'obj type of ResourcePool must be checked ' |
24 | 364 | 'against a `ResourcePoolPermission`.') | 362 | 'against a `ResourcePoolPermission`.') |
25 | 365 | 363 | ||
26 | 364 | # Handle node permissions without objects. | ||
27 | 365 | if perm == NodePermission.admin and obj is None: | ||
28 | 366 | # User wants to admin writes to all nodes (aka. create a node), | ||
29 | 367 | # must be superuser for those permissions. | ||
30 | 368 | return user.is_superuser | ||
31 | 369 | elif perm == NodePermission.view and obj is None: | ||
32 | 370 | # XXX 2018-11-20 blake_r: View permission without an obj is used | ||
33 | 371 | # for device create as a standard user. Currently there is no | ||
34 | 372 | # specific DevicePermission and no way for this code path to know | ||
35 | 373 | # its for a device. So it is represented using this path. | ||
36 | 374 | # | ||
37 | 375 | # View is only used for the create action, modifying a created | ||
38 | 376 | # device uses the appropriate `NodePermission.edit` scoped to the | ||
39 | 377 | # device being editted. | ||
40 | 378 | return True | ||
41 | 379 | |||
42 | 366 | # ResourcePool permissions are handled specifically. | 380 | # ResourcePool permissions are handled specifically. |
43 | 367 | if isinstance(perm, ResourcePoolPermission): | 381 | if isinstance(perm, ResourcePoolPermission): |
44 | 368 | return self._perm_resource_pool( | 382 | return self._perm_resource_pool( |
45 | @@ -386,7 +400,7 @@ class MAASAuthorizationBackend(ModelBackend): | |||
46 | 386 | rbac_enabled, user, obj, visible_pools, admin_pools) | 400 | rbac_enabled, user, obj, visible_pools, admin_pools) |
47 | 387 | return obj.pool_id is not None and can_edit | 401 | return obj.pool_id is not None and can_edit |
48 | 388 | elif perm == NodePermission.admin: | 402 | elif perm == NodePermission.admin: |
50 | 389 | return self._can_admin( | 403 | return not obj.locked and self._can_admin( |
51 | 390 | rbac_enabled, user, obj, admin_pools) | 404 | rbac_enabled, user, obj, admin_pools) |
52 | 391 | else: | 405 | else: |
53 | 392 | raise NotImplementedError( | 406 | raise NotImplementedError( |
54 | @@ -501,8 +515,8 @@ class MAASAuthorizationBackend(ModelBackend): | |||
55 | 501 | 515 | ||
56 | 502 | if perm == ResourcePoolPermission.edit: | 516 | if perm == ResourcePoolPermission.edit: |
57 | 503 | if rbac_enabled: | 517 | if rbac_enabled: |
60 | 504 | return obj.id in rbac.get_resource_pools( | 518 | return obj.id in rbac.get_resource_pool_ids( |
61 | 505 | user.username, 'edit').values_list('id', flat=True) | 519 | user.username, 'edit') |
62 | 506 | return user.is_superuser | 520 | return user.is_superuser |
63 | 507 | elif perm == ResourcePoolPermission.view: | 521 | elif perm == ResourcePoolPermission.view: |
64 | 508 | if rbac_enabled: | 522 | if rbac_enabled: |
65 | diff --git a/src/maasserver/models/node.py b/src/maasserver/models/node.py | |||
66 | index 18beda4..cdbeb8a 100644 | |||
67 | --- a/src/maasserver/models/node.py | |||
68 | +++ b/src/maasserver/models/node.py | |||
69 | @@ -485,11 +485,11 @@ class BaseNodeManager(Manager, NodeQueriesMixin): | |||
70 | 485 | "Invalid permission check (invalid permission name: %s)." % | 485 | "Invalid permission check (invalid permission name: %s)." % |
71 | 486 | perm) | 486 | perm) |
72 | 487 | if rbac.is_enabled(): | 487 | if rbac.is_enabled(): |
75 | 488 | visible_pools = rbac.get_resource_pools(user.username, 'view') | 488 | visible_pools = rbac.get_resource_pool_ids(user.username, 'view') |
76 | 489 | admin_pools = rbac.get_resource_pools( | 489 | admin_pools = rbac.get_resource_pool_ids( |
77 | 490 | user.username, 'admin-machines') | 490 | user.username, 'admin-machines') |
80 | 491 | condition |= Q(pool__in=admin_pools) | 491 | condition |= Q(pool_id__in=admin_pools) |
81 | 492 | nodes = nodes.filter(pool__in=visible_pools) | 492 | nodes = nodes.filter(pool_id__in=visible_pools) |
82 | 493 | 493 | ||
83 | 494 | return nodes.filter(condition) | 494 | return nodes.filter(condition) |
84 | 495 | 495 | ||
85 | diff --git a/src/maasserver/models/resourcepool.py b/src/maasserver/models/resourcepool.py | |||
86 | index 618f218..fc7af6c 100644 | |||
87 | --- a/src/maasserver/models/resourcepool.py | |||
88 | +++ b/src/maasserver/models/resourcepool.py | |||
89 | @@ -98,7 +98,8 @@ class ResourcePoolManager(Manager, ResourcePoolQueriesMixin): | |||
90 | 98 | # Circular imports. | 98 | # Circular imports. |
91 | 99 | from maasserver.rbac import rbac | 99 | from maasserver.rbac import rbac |
92 | 100 | if rbac.is_enabled(): | 100 | if rbac.is_enabled(): |
94 | 101 | return rbac.get_resource_pools(user.username, 'view') | 101 | return self.filter( |
95 | 102 | id__in=rbac.get_resource_pool_ids(user.username, 'view')) | ||
96 | 102 | return self.all() | 103 | return self.all() |
97 | 103 | 104 | ||
98 | 104 | 105 | ||
99 | diff --git a/src/maasserver/rbac.py b/src/maasserver/rbac.py | |||
100 | index ba24cf8..bff808c 100644 | |||
101 | --- a/src/maasserver/rbac.py | |||
102 | +++ b/src/maasserver/rbac.py | |||
103 | @@ -258,26 +258,65 @@ class RBACWrapper: | |||
104 | 258 | This marks a client as cleared that way only a new client is created | 258 | This marks a client as cleared that way only a new client is created |
105 | 259 | if the `rbac_url` is changed. | 259 | if the `rbac_url` is changed. |
106 | 260 | """ | 260 | """ |
107 | 261 | self.clear_cache() | ||
108 | 261 | self._store.cleared = True | 262 | self._store.cleared = True |
109 | 262 | 263 | ||
110 | 263 | def is_enabled(self): | 264 | def is_enabled(self): |
111 | 264 | """Return whether MAAS has been configured to use RBAC.""" | 265 | """Return whether MAAS has been configured to use RBAC.""" |
112 | 265 | return self.client is not None | 266 | return self.client is not None |
113 | 266 | 267 | ||
116 | 267 | def get_resource_pools(self, user, permission): | 268 | def get_cache(self, resource, user, default=dict): |
117 | 268 | """Get the resource pools that given user has the given permission on. | 269 | """Return the cache for the `resource` and `user`.""" |
118 | 270 | cache = getattr(self._store, 'cache', None) | ||
119 | 271 | if cache is None: | ||
120 | 272 | cache = {} | ||
121 | 273 | setattr(self._store, 'cache', cache) | ||
122 | 274 | key = (resource, user) | ||
123 | 275 | if key in cache: | ||
124 | 276 | return cache[key] | ||
125 | 277 | scoped = default() | ||
126 | 278 | cache[key] = scoped | ||
127 | 279 | return scoped | ||
128 | 280 | |||
129 | 281 | def clear_cache(self): | ||
130 | 282 | """Clears the entire cache.""" | ||
131 | 283 | if hasattr(self._store, 'cache'): | ||
132 | 284 | delattr(self._store, 'cache') | ||
133 | 285 | |||
134 | 286 | def _get_resource_pool_identifiers(self, user, permission): | ||
135 | 287 | """Get the resource pool identifiers from RBAC. | ||
136 | 288 | |||
137 | 289 | Uses the thread-local cache so only one request is made to RBAC per | ||
138 | 290 | request to MAAS. | ||
139 | 269 | 291 | ||
140 | 270 | @param user: The user name of the user. | 292 | @param user: The user name of the user. |
141 | 271 | @param permission: A permission that the user should | 293 | @param permission: A permission that the user should |
142 | 272 | have on the resource pool. | 294 | have on the resource pool. |
143 | 273 | """ | 295 | """ |
148 | 274 | pool_identifiers = self.client.allowed_for_user( | 296 | cache = self.get_cache('resource-pool', user) |
149 | 275 | 'resource-pool', user, permission) | 297 | pool_identifiers = cache.get(permission, None) |
150 | 276 | pools = ResourcePool.objects.all() | 298 | if pool_identifiers is None: |
151 | 277 | if pool_identifiers is not ALL_RESOURCES: | 299 | pool_identifiers = self.client.allowed_for_user( |
152 | 300 | 'resource-pool', user, permission) | ||
153 | 301 | cache[permission] = pool_identifiers | ||
154 | 302 | return pool_identifiers | ||
155 | 303 | |||
156 | 304 | def get_resource_pool_ids(self, user, permission): | ||
157 | 305 | """Get the resource pools ids that given user has the given | ||
158 | 306 | permission on. | ||
159 | 307 | |||
160 | 308 | @param user: The user name of the user. | ||
161 | 309 | @param permission: A permission that the user should | ||
162 | 310 | have on the resource pool. | ||
163 | 311 | """ | ||
164 | 312 | pool_identifiers = self._get_resource_pool_identifiers( | ||
165 | 313 | user, permission) | ||
166 | 314 | if pool_identifiers is ALL_RESOURCES: | ||
167 | 315 | pool_ids = list( | ||
168 | 316 | ResourcePool.objects.all().values_list('id', flat=True)) | ||
169 | 317 | else: | ||
170 | 278 | pool_ids = [int(identifier) for identifier in pool_identifiers] | 318 | pool_ids = [int(identifier) for identifier in pool_identifiers] |
173 | 279 | pools = pools.filter(id__in=pool_ids) | 319 | return pool_ids |
172 | 280 | return pools | ||
174 | 281 | 320 | ||
175 | 282 | def can_create_resource_pool(self, user): | 321 | def can_create_resource_pool(self, user): |
176 | 283 | """Return True if the `user` can create a resource pool. | 322 | """Return True if the `user` can create a resource pool. |
177 | @@ -287,8 +326,8 @@ class RBACWrapper: | |||
178 | 287 | 326 | ||
179 | 288 | @param user: The user name of the user. | 327 | @param user: The user name of the user. |
180 | 289 | """ | 328 | """ |
183 | 290 | pool_identifiers = self.client.allowed_for_user( | 329 | pool_identifiers = self._get_resource_pool_identifiers( |
184 | 291 | 'resource-pool', user, 'edit') | 330 | user, 'edit') |
185 | 292 | return pool_identifiers is ALL_RESOURCES | 331 | return pool_identifiers is ALL_RESOURCES |
186 | 293 | 332 | ||
187 | 294 | 333 | ||
188 | diff --git a/src/maasserver/testing/fixtures.py b/src/maasserver/testing/fixtures.py | |||
189 | index 747d6eb..f1cdae2 100644 | |||
190 | --- a/src/maasserver/testing/fixtures.py | |||
191 | +++ b/src/maasserver/testing/fixtures.py | |||
192 | @@ -11,9 +11,13 @@ __all__ = [ | |||
193 | 11 | import inspect | 11 | import inspect |
194 | 12 | import logging | 12 | import logging |
195 | 13 | 13 | ||
196 | 14 | from django.db import connection | ||
197 | 14 | import fixtures | 15 | import fixtures |
198 | 15 | from maasserver.models.config import Config | 16 | from maasserver.models.config import Config |
200 | 16 | from maasserver.rbac import rbac | 17 | from maasserver.rbac import ( |
201 | 18 | FakeRBACClient, | ||
202 | 19 | rbac, | ||
203 | 20 | ) | ||
204 | 17 | from maasserver.testing.factory import factory | 21 | from maasserver.testing.factory import factory |
205 | 18 | 22 | ||
206 | 19 | 23 | ||
207 | @@ -102,3 +106,23 @@ class RBACForceOffFixture(fixtures.Fixture): | |||
208 | 102 | rbac._get_rbac_url = orig_get_url | 106 | rbac._get_rbac_url = orig_get_url |
209 | 103 | 107 | ||
210 | 104 | self.addCleanup(cleanup) | 108 | self.addCleanup(cleanup) |
211 | 109 | |||
212 | 110 | |||
213 | 111 | class RBACEnabled(fixtures.Fixture): | ||
214 | 112 | """Fixture that enables RBAC.""" | ||
215 | 113 | |||
216 | 114 | def _setUp(self): | ||
217 | 115 | # Must be called inside a transaction. | ||
218 | 116 | assert connection.in_atomic_block | ||
219 | 117 | |||
220 | 118 | Config.objects.set_config('rbac_url', 'http://rbac.example.com') | ||
221 | 119 | client = FakeRBACClient() | ||
222 | 120 | rbac._store.client = client | ||
223 | 121 | rbac._store.cleared = False | ||
224 | 122 | self.store = client.store | ||
225 | 123 | |||
226 | 124 | def cleanup(): | ||
227 | 125 | rbac._store.client = None | ||
228 | 126 | rbac.clear() | ||
229 | 127 | |||
230 | 128 | self.addCleanup(cleanup) | ||
231 | diff --git a/src/maasserver/tests/test_auth.py b/src/maasserver/tests/test_auth.py | |||
232 | index e94107d..09153e9 100644 | |||
233 | --- a/src/maasserver/tests/test_auth.py | |||
234 | +++ b/src/maasserver/tests/test_auth.py | |||
235 | @@ -234,6 +234,30 @@ class TestMAASAuthorizationBackend(MAASServerTestCase, EnableRBACMixin): | |||
236 | 234 | NodePermission.admin, | 234 | NodePermission.admin, |
237 | 235 | make_allocated_node())) | 235 | make_allocated_node())) |
238 | 236 | 236 | ||
239 | 237 | def test_admin_cannot_admin_locked_nodes(self): | ||
240 | 238 | backend = MAASAuthorizationBackend() | ||
241 | 239 | node = make_allocated_node() | ||
242 | 240 | node.locked = True | ||
243 | 241 | node.save() | ||
244 | 242 | self.assertFalse(backend.has_perm( | ||
245 | 243 | factory.make_admin(), | ||
246 | 244 | NodePermission.admin, node)) | ||
247 | 245 | |||
248 | 246 | def test_user_cannot_admin_all_nodes(self): | ||
249 | 247 | backend = MAASAuthorizationBackend() | ||
250 | 248 | self.assertFalse( | ||
251 | 249 | backend.has_perm(factory.make_User(), NodePermission.admin)) | ||
252 | 250 | |||
253 | 251 | def test_user_can_admin_all_nodes(self): | ||
254 | 252 | backend = MAASAuthorizationBackend() | ||
255 | 253 | self.assertTrue( | ||
256 | 254 | backend.has_perm(factory.make_admin(), NodePermission.admin)) | ||
257 | 255 | |||
258 | 256 | def test_user_can_view_all_nodes(self): | ||
259 | 257 | backend = MAASAuthorizationBackend() | ||
260 | 258 | self.assertTrue( | ||
261 | 259 | backend.has_perm(factory.make_User(), NodePermission.view)) | ||
262 | 260 | |||
263 | 237 | def test_user_cannot_view_nodes_owned_by_others(self): | 261 | def test_user_cannot_view_nodes_owned_by_others(self): |
264 | 238 | backend = MAASAuthorizationBackend() | 262 | backend = MAASAuthorizationBackend() |
265 | 239 | self.assertFalse(backend.has_perm( | 263 | self.assertFalse(backend.has_perm( |
266 | diff --git a/src/maasserver/tests/test_rbac.py b/src/maasserver/tests/test_rbac.py | |||
267 | index 721d552..f76238b 100644 | |||
268 | --- a/src/maasserver/tests/test_rbac.py | |||
269 | +++ b/src/maasserver/tests/test_rbac.py | |||
270 | @@ -254,24 +254,24 @@ class TestRBACWrapperGetResourcePools(MAASServerTestCase): | |||
271 | 254 | ResourcePool.objects.get_default_resource_pool()) | 254 | ResourcePool.objects.get_default_resource_pool()) |
272 | 255 | self.store.add_pool(self.default_pool) | 255 | self.store.add_pool(self.default_pool) |
273 | 256 | 256 | ||
275 | 257 | def test_get_resource_pools_unknown_user(self): | 257 | def test_get_resource_pool_ids_unknown_user(self): |
276 | 258 | self.store.add_pool(factory.make_ResourcePool()) | 258 | self.store.add_pool(factory.make_ResourcePool()) |
277 | 259 | self.assertNotIn('user', self.store.allowed) | 259 | self.assertNotIn('user', self.store.allowed) |
278 | 260 | self.assertEqual( | 260 | self.assertEqual( |
279 | 261 | [], | 261 | [], |
281 | 262 | list(self.rbac.get_resource_pools('user', 'view'))) | 262 | list(self.rbac.get_resource_pool_ids('user', 'view'))) |
282 | 263 | 263 | ||
284 | 264 | def test_get_resource_pools_user_allowed_all(self): | 264 | def test_get_resource_pools_ids_user_allowed_all(self): |
285 | 265 | pool1 = factory.make_ResourcePool() | 265 | pool1 = factory.make_ResourcePool() |
286 | 266 | pool2 = factory.make_ResourcePool() | 266 | pool2 = factory.make_ResourcePool() |
287 | 267 | self.store.add_pool(pool1) | 267 | self.store.add_pool(pool1) |
288 | 268 | self.store.add_pool(pool2) | 268 | self.store.add_pool(pool2) |
289 | 269 | self.store.allow('user', ALL_RESOURCES, 'view') | 269 | self.store.allow('user', ALL_RESOURCES, 'view') |
290 | 270 | self.assertCountEqual( | 270 | self.assertCountEqual( |
293 | 271 | [self.default_pool, pool1, pool2], | 271 | [self.default_pool.id, pool1.id, pool2.id], |
294 | 272 | self.rbac.get_resource_pools('user', 'view')) | 272 | self.rbac.get_resource_pool_ids('user', 'view')) |
295 | 273 | 273 | ||
297 | 274 | def test_get_resource_pools_user_allowed_other_permission(self): | 274 | def test_get_resource_pools_ids_user_allowed_other_permission(self): |
298 | 275 | pool1 = factory.make_ResourcePool() | 275 | pool1 = factory.make_ResourcePool() |
299 | 276 | pool2 = factory.make_ResourcePool() | 276 | pool2 = factory.make_ResourcePool() |
300 | 277 | self.store.add_pool(pool1) | 277 | self.store.add_pool(pool1) |
301 | @@ -279,21 +279,44 @@ class TestRBACWrapperGetResourcePools(MAASServerTestCase): | |||
302 | 279 | self.store.allow('user', pool1, 'view') | 279 | self.store.allow('user', pool1, 'view') |
303 | 280 | self.store.allow('user', pool2, 'edit') | 280 | self.store.allow('user', pool2, 'edit') |
304 | 281 | self.assertCountEqual( | 281 | self.assertCountEqual( |
307 | 282 | [pool1], | 282 | [pool1.id], |
308 | 283 | self.rbac.get_resource_pools('user', 'view')) | 283 | self.rbac.get_resource_pool_ids('user', 'view')) |
309 | 284 | self.assertCountEqual( | 284 | self.assertCountEqual( |
310 | 285 | [], | 285 | [], |
312 | 286 | self.rbac.get_resource_pools('user', 'admin-machines')) | 286 | self.rbac.get_resource_pool_ids('user', 'admin-machines')) |
313 | 287 | 287 | ||
315 | 288 | def test_get_resource_pools_user_allowed_some(self): | 288 | def test_get_resource_pool_ids_user_allowed_some(self): |
316 | 289 | pool1 = factory.make_ResourcePool() | 289 | pool1 = factory.make_ResourcePool() |
317 | 290 | pool2 = factory.make_ResourcePool() | 290 | pool2 = factory.make_ResourcePool() |
318 | 291 | self.store.add_pool(pool1) | 291 | self.store.add_pool(pool1) |
319 | 292 | self.store.add_pool(pool2) | 292 | self.store.add_pool(pool2) |
320 | 293 | self.store.allow('user', pool1, 'view') | 293 | self.store.allow('user', pool1, 'view') |
321 | 294 | self.assertEqual( | 294 | self.assertEqual( |
324 | 295 | sorted([pool1]), | 295 | sorted([pool1.id]), |
325 | 296 | sorted(self.rbac.get_resource_pools('user', 'view'))) | 296 | sorted(self.rbac.get_resource_pool_ids('user', 'view'))) |
326 | 297 | |||
327 | 298 | def test_get_resource_pool_ids_one_request_per_clear_cache(self): | ||
328 | 299 | self.store.allow('user', self.default_pool, 'view') | ||
329 | 300 | pools_one = self.rbac.get_resource_pool_ids('user', 'view') | ||
330 | 301 | new_pool = factory.make_ResourcePool() | ||
331 | 302 | self.store.allow('user', new_pool, 'view') | ||
332 | 303 | pools_two = self.rbac.get_resource_pool_ids('user', 'view') | ||
333 | 304 | self.rbac.clear_cache() | ||
334 | 305 | pools_three = self.rbac.get_resource_pool_ids('user', 'view') | ||
335 | 306 | self.assertItemsEqual([self.default_pool.id], pools_one) | ||
336 | 307 | self.assertItemsEqual([self.default_pool.id], pools_two) | ||
337 | 308 | self.assertItemsEqual([self.default_pool.id, new_pool.id], pools_three) | ||
338 | 309 | |||
339 | 310 | def test_get_resource_pool_ids_ALL_RESOURCES_always_returns_all(self): | ||
340 | 311 | self.store.allow('user', ALL_RESOURCES, 'view') | ||
341 | 312 | pools_one = self.rbac.get_resource_pool_ids('user', 'view') | ||
342 | 313 | new_pool = factory.make_ResourcePool() | ||
343 | 314 | pools_two = self.rbac.get_resource_pool_ids('user', 'view') | ||
344 | 315 | self.rbac.clear_cache() | ||
345 | 316 | pools_three = self.rbac.get_resource_pool_ids('user', 'view') | ||
346 | 317 | self.assertItemsEqual([self.default_pool.id], pools_one) | ||
347 | 318 | self.assertItemsEqual([self.default_pool.id, new_pool.id], pools_two) | ||
348 | 319 | self.assertItemsEqual([self.default_pool.id, new_pool.id], pools_three) | ||
349 | 297 | 320 | ||
350 | 298 | def test_can_create_resource_pool_returns_True(self): | 321 | def test_can_create_resource_pool_returns_True(self): |
351 | 299 | self.store.allow('user', ALL_RESOURCES, 'edit') | 322 | self.store.allow('user', ALL_RESOURCES, 'edit') |