|
11 | 11 | from ddt import ddt, unpack |
12 | 12 | from django.test import TestCase |
13 | 13 |
|
14 | | -from openedx_authz.api.data import ContentLibraryData, RoleAssignmentData, RoleData, ScopeData, SubjectData |
| 14 | +from openedx_authz.api.data import ( |
| 15 | + ActionData, |
| 16 | + ContentLibraryData, |
| 17 | + PermissionData, |
| 18 | + RoleAssignmentData, |
| 19 | + RoleData, |
| 20 | + ScopeData, |
| 21 | + SubjectData, |
| 22 | +) |
15 | 23 | from openedx_authz.api.roles import ( |
16 | 24 | assign_role_to_subject_in_scope, |
17 | 25 | batch_assign_role_to_subjects_in_scope, |
18 | 26 | get_all_subject_role_assignments_in_scope, |
19 | 27 | get_permissions_for_active_roles_in_scope, |
20 | 28 | get_permissions_for_single_role, |
21 | 29 | get_role_definitions_in_scope, |
22 | | - get_scopes_for_role_and_subject, |
| 30 | + get_scopes_for_subject_and_permission, |
23 | 31 | get_subject_role_assignments, |
24 | 32 | get_subject_role_assignments_for_role_in_scope, |
25 | 33 | get_subject_role_assignments_in_scope, |
@@ -509,23 +517,108 @@ def test_get_role_assignments_in_scope(self, role_name, scope_name, expected_cou |
509 | 517 |
|
510 | 518 | self.assertEqual(len(role_assignments), expected_count) |
511 | 519 |
|
512 | | - def test_get_scopes_for_role_and_subject(self): |
513 | | - """Test retrieving scopes for a given role and subject. |
| 520 | + @ddt_data( |
| 521 | + # Test case: alice with 'view_library' permission (has library_admin in math_101) |
| 522 | + ( |
| 523 | + "alice", |
| 524 | + "view_library", |
| 525 | + ["lib:Org1:math_101"], |
| 526 | + ), |
| 527 | + # Test case: alice with 'publish_library_content' permission (admin grants publish) |
| 528 | + ( |
| 529 | + "alice", |
| 530 | + "publish_library_content", |
| 531 | + ["lib:Org1:math_101"], |
| 532 | + ), |
| 533 | + # Test case: alice with 'delete_library' permission (admin grants delete) |
| 534 | + ( |
| 535 | + "alice", |
| 536 | + "delete_library", |
| 537 | + ["lib:Org1:math_101"], |
| 538 | + ), |
| 539 | + # Test case: bob with 'view_library' permission (has library_author in history_201) |
| 540 | + ( |
| 541 | + "bob", |
| 542 | + "view_library", |
| 543 | + ["lib:Org1:history_201"], |
| 544 | + ), |
| 545 | + # Test case: bob with 'publish_library_content' permission (author grants publish) |
| 546 | + ( |
| 547 | + "bob", |
| 548 | + "publish_library_content", |
| 549 | + ["lib:Org1:history_201"], |
| 550 | + ), |
| 551 | + # Test case: bob with 'delete_library' permission (author does NOT grant delete) |
| 552 | + ( |
| 553 | + "bob", |
| 554 | + "delete_library", |
| 555 | + [], |
| 556 | + ), |
| 557 | + # Test case: carol with 'view_library' permission (has library_contributor in science_301) |
| 558 | + ( |
| 559 | + "carol", |
| 560 | + "view_library", |
| 561 | + ["lib:Org1:science_301"], |
| 562 | + ), |
| 563 | + # Test case: carol with 'publish_library_content' permission (contributor does NOT grant publish) |
| 564 | + ( |
| 565 | + "carol", |
| 566 | + "publish_library_content", |
| 567 | + [], |
| 568 | + ), |
| 569 | + # Test case: dave with 'view_library' permission (has library_user in english_101) |
| 570 | + ( |
| 571 | + "dave", |
| 572 | + "view_library", |
| 573 | + ["lib:Org1:english_101"], |
| 574 | + ), |
| 575 | + # Test case: dave with 'publish_library_content' permission (user does NOT grant publish) |
| 576 | + ( |
| 577 | + "dave", |
| 578 | + "publish_library_content", |
| 579 | + [], |
| 580 | + ), |
| 581 | + # Test case: liam with 'view_library' permission (has library_author in 3 art libraries) |
| 582 | + ( |
| 583 | + "liam", |
| 584 | + "view_library", |
| 585 | + ["lib:Org4:art_101", "lib:Org4:art_201", "lib:Org4:art_301"], |
| 586 | + ), |
| 587 | + # Test case: non-existent user |
| 588 | + ( |
| 589 | + "nonexistent", |
| 590 | + "view_library", |
| 591 | + [], |
| 592 | + ), |
| 593 | + ) |
| 594 | + @unpack |
| 595 | + def test_get_scopes_for_subject_and_permission(self, subject_name, action_name, expected_scope_names): |
| 596 | + """Test retrieving scopes where a subject has a specific permission. |
| 597 | +
|
| 598 | + This tests the get_scopes_for_subject_and_permission function which |
| 599 | + returns all scopes where a subject has been granted a specific permission |
| 600 | + through their role assignments. |
| 601 | +
|
| 602 | + Args: |
| 603 | + subject_name: The external key of the subject (e.g., 'alice') |
| 604 | + action_name: The action to check (e.g., 'view', 'edit', 'delete') |
| 605 | + expected_scope_names: List of expected scope external keys |
514 | 606 |
|
515 | 607 | Expected result: |
516 | | - - The scopes associated with the specified role and subject are correctly retrieved. |
| 608 | + - Returns all scopes where the subject has roles that grant the permission |
| 609 | + - Returns empty list if subject has no roles with that permission |
517 | 610 | """ |
518 | | - role_name = roles.LIBRARY_AUTHOR.external_key |
519 | | - subject_name = "liam" |
520 | | - expected_scopes = {"lib:Org4:art_101", "lib:Org4:art_201", "lib:Org4:art_301"} |
| 611 | + subject = SubjectData(external_key=subject_name) |
| 612 | + permission = PermissionData(action=ActionData(external_key=action_name)) |
521 | 613 |
|
522 | | - scopes = get_scopes_for_role_and_subject( |
523 | | - RoleData(external_key=role_name), |
524 | | - SubjectData(external_key=subject_name), |
525 | | - ) |
| 614 | + scopes = get_scopes_for_subject_and_permission(subject, permission) |
| 615 | + |
| 616 | + # Extract scope external keys for comparison |
| 617 | + actual_scope_names = [scope.external_key for scope in scopes] |
526 | 618 |
|
527 | | - scope_names = {scope.external_key for scope in scopes} |
528 | | - self.assertEqual(scope_names, expected_scopes) |
| 619 | + self.assertEqual(len(actual_scope_names), len(expected_scope_names)) |
| 620 | + for expected_scope in expected_scope_names: |
| 621 | + self.assertIn(expected_scope, actual_scope_names) |
529 | 622 |
|
530 | 623 | @ddt_data( |
531 | 624 | (roles.LIBRARY_AUTHOR.external_key, "lib:Org4:art_101", {"liam"}), |
|
0 commit comments