Skip to content

Commit bd4f1a3

Browse files
committed
fixup! feat: add course authoring migration and rollback scripts
1 parent f290079 commit bd4f1a3

1 file changed

Lines changed: 83 additions & 11 deletions

File tree

openedx_authz/tests/test_migrations.py

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)