@@ -275,6 +275,7 @@ def setUp(self):
275275
276276 class MockPermission :
277277 """Mock class to simulate CourseAccessRole entries for testing the rollback migration."""
278+
278279 def __init__ (self , user , role , course_id , id_in ):
279280 self .user = user
280281 self .role = role
@@ -283,11 +284,13 @@ def __init__(self, user, role, course_id, id_in):
283284
284285 class MockUser :
285286 """Mock class to simulate User objects for testing the rollback migration."""
287+
286288 def __init__ (self , username ):
287289 self .username = username
288290
289291 class MockQuerySet :
290292 """Mock class to simulate QuerySet behavior for testing the rollback migration."""
293+
291294 def __init__ (self , permissions ):
292295 self .permissions = permissions
293296
@@ -305,6 +308,7 @@ def get_or_create(self):
305308
306309 class MockCourseAccessRole :
307310 """Mock class to simulate CourseAccessRole manager for testing the rollback migration."""
311+
308312 objects = MockQuerySet (
309313 [
310314 MockPermission (MockUser ("testuser" ), "instructor" , "course-v1:test" , 1 ),
@@ -946,6 +950,54 @@ def test_authz_rollback_course_authoring_command(self, mock_rollback):
946950
947951 self .assertEqual (call_kwargs ["delete_after_migration" ], True )
948952
953+ @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.CourseAccessRole" , CourseAccessRole )
954+ @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.migrate_legacy_course_roles_to_authz" )
955+ def test_authz_migrate_course_authoring_command_delete_confirmation_no (self , mock_migrate ):
956+ """
957+ Verify that the authz_migrate_course_authoring command does NOT perform deletion
958+ when user provides an answer other than 'yes' during delete confirmation.
959+ """
960+ mock_migrate .return_value = [], []
961+ with patch ("builtins.input" , return_value = "no" ):
962+ call_command ("authz_migrate_course_authoring" , "--delete" , "--course-id-list" , self .course_id )
963+ mock_migrate .assert_not_called ()
964+
965+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.CourseAccessRole" , CourseAccessRole )
966+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.migrate_authz_to_legacy_course_roles" )
967+ def test_authz_rollback_course_authoring_command_delete_confirmation_no (self , mock_rollback ):
968+ """
969+ Verify that the authz_rollback_course_authoring command does NOT perform deletion
970+ when user provides an answer other than 'yes' during delete confirmation.
971+ """
972+ mock_rollback .return_value = [], []
973+ with patch ("builtins.input" , return_value = "no" ):
974+ call_command ("authz_rollback_course_authoring" , "--delete" , "--course-id-list" , self .course_id )
975+ mock_rollback .assert_not_called ()
976+
977+ @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.CourseAccessRole" , CourseAccessRole )
978+ @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.migrate_legacy_course_roles_to_authz" )
979+ def test_authz_migrate_course_authoring_command_migration_exception (self , mock_migrate ):
980+ """
981+ Verify that the authz_migrate_course_authoring command handles exceptions raised
982+ by migrate_legacy_course_roles_to_authz.
983+ """
984+ mock_migrate .side_effect = Exception ("Migration error" )
985+ with self .assertRaises (Exception ) as exc :
986+ call_command ("authz_migrate_course_authoring" , "--course-id-list" , self .course_id )
987+ self .assertIn ("Migration error" , str (exc .exception ))
988+
989+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.CourseAccessRole" , CourseAccessRole )
990+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.migrate_authz_to_legacy_course_roles" )
991+ def test_authz_rollback_course_authoring_command_rollback_exception (self , mock_rollback ):
992+ """
993+ Verify that the authz_rollback_course_authoring command handles exceptions raised
994+ by migrate_authz_to_legacy_course_roles.
995+ """
996+ mock_rollback .side_effect = Exception ("Rollback error" )
997+ with self .assertRaises (Exception ) as exc :
998+ call_command ("authz_rollback_course_authoring" , "--course-id-list" , self .course_id )
999+ self .assertIn ("Rollback error" , str (exc .exception ))
1000+
9491001 @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.CourseAccessRole" , CourseAccessRole )
9501002 def test_authz_migrate_course_authoring_command_no_org_and_courses (self ):
9511003 """
@@ -956,6 +1008,16 @@ def test_authz_migrate_course_authoring_command_no_org_and_courses(self):
9561008 with self .assertRaises (CommandError ):
9571009 call_command ("authz_migrate_course_authoring" )
9581010
1011+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.CourseAccessRole" , CourseAccessRole )
1012+ def test_authz_rollback_course_authoring_command_no_org_and_courses (self ):
1013+ """
1014+ Verify that the authz_rollback_course_authoring command raises an error
1015+ when neither course_id_list nor org_id is provided.
1016+ """
1017+
1018+ with self .assertRaises (CommandError ):
1019+ call_command ("authz_rollback_course_authoring" )
1020+
9591021 @patch ("openedx_authz.management.commands.authz_migrate_course_authoring.CourseAccessRole" , CourseAccessRole )
9601022 def test_authz_migrate_course_authoring_command_with_org_and_courses (self ):
9611023 """
@@ -966,6 +1028,16 @@ def test_authz_migrate_course_authoring_command_with_org_and_courses(self):
9661028 with self .assertRaises (CommandError ):
9671029 call_command ("authz_migrate_course_authoring" , "--course-id-list" , self .course_id , "--org-id" , self .org )
9681030
1031+ @patch ("openedx_authz.management.commands.authz_rollback_course_authoring.CourseAccessRole" , CourseAccessRole )
1032+ def test_authz_rollback_course_authoring_command_with_org_and_courses (self ):
1033+ """
1034+ Verify that the authz_rollback_course_authoring command raises an error
1035+ when both course_id_list and org_id are provided.
1036+ """
1037+
1038+ with self .assertRaises (CommandError ):
1039+ call_command ("authz_rollback_course_authoring" , "--course-id-list" , self .course_id , "--org-id" , self .org )
1040+
9691041 @patch ("openedx_authz.engine.utils.assign_role_to_user_in_scope" , return_value = False )
9701042 @patch ("openedx_authz.engine.utils.LEGACY_COURSE_ROLE_EQUIVALENCES" , {"instructor" : "instructor-role" })
9711043 def test_migrate_legacy_course_roles_to_authz_user_not_added (
@@ -1004,29 +1076,24 @@ def test_migrate_authz_to_legacy_course_roles_user_not_added(self):
10041076 self .assertEqual (len (successes ), 0 )
10051077
10061078 def create_library_env (self ):
1007- """Helper method to create a ContentLibrary environment for testing the migration of legacy permissions
1008- related to ContentLibraryPermission to the new Casbin-based model .
1079+ """
1080+ Helper method to create a ContentLibrary environment for testing .
10091081 """
10101082
10111083 # Create ContentLibrary
10121084 org = Organization .objects .create (name = org_name , short_name = org_short_name )
10131085 library = ContentLibrary .objects .create (org = org , slug = lib_name )
10141086
1015- # Create Users and Groups
1016- users = [
1017- User .objects .create_user (username = user_name , email = f"lib_{ user_name } @example.com" )
1018- for user_name in user_names
1019- ]
1020-
1087+ # Create Groups
10211088 group_users = [
1022- User .objects .create_user (username = user_name , email = f"lib_ { user_name } @example.com" )
1089+ User .objects .create_user (username = user_name , email = f"{ user_name } @example.com" )
10231090 for user_name in group_user_names
10241091 ]
10251092 group = Group .objects .create (name = group_name )
10261093 group .user_set .set (group_users )
10271094
10281095 # Assign legacy permissions for users and group
1029- for user in users :
1096+ for user in self . admin_users + self . staff_users + self . limited_staff + self . data_researcher :
10301097 ContentLibraryPermission .objects .create (
10311098 user = user ,
10321099 library = library ,
@@ -1040,7 +1107,12 @@ def create_library_env(self):
10401107 )
10411108
10421109 @patch ("openedx_authz.api.data.CourseOverview" , CourseOverview )
1043- def test_migrate_authz_to_legacy_course_roles_with_no_course_scopes (self ):
1110+ def test_migrate_authz_to_legacy_course_roles_with_library_env (self ):
1111+ """Test the migration of permissions from the new Casbin-based model back to the legacy CourseAccessRole model
1112+ in a ContentLibrary environment to ensure that the migration functions correctly identify the relevant
1113+ permissions based on the scope and do not attempt to migrate permissions that are outside
1114+ of the specified scope (i.e. permissions related to the ContentLibrary in this case).
1115+ """
10441116 self .create_library_env ()
10451117 migrate_legacy_permissions (ContentLibraryPermission )
10461118 permissions_with_errors , permissions_with_no_errors = migrate_legacy_course_roles_to_authz (
0 commit comments