1414from common .djangoapps .student .tests .factories import UserFactory
1515
1616
17- class CourseAuthzTestMixin :
18- """
19- Reusable mixin for testing course-scoped AuthZ endpoints.
17+ class CourseAuthoringAuthzTestMixin :
2018 """
19+ Base mixin for testing AuthZ in the course authoring context.
2120
22- authz_roles_to_assign = [COURSE_STAFF .external_key ]
21+ Responsibilities:
22+ - Enable course authoring AuthZ feature flag
23+ - Seed policies into the AuthZ enforcer
24+ - Provide authenticated test clients
25+ - Provide helpers for assigning roles within a course scope
26+ """
2327
2428 @classmethod
2529 def setUpClass (cls ):
2630 cls .toggle_patcher = patch .object (
2731 core_toggles .AUTHZ_COURSE_AUTHORING_FLAG ,
2832 "is_enabled" ,
29- return_value = True
33+ return_value = True ,
3034 )
3135 cls .toggle_patcher .start ()
32-
3336 super ().setUpClass ()
3437
3538 @classmethod
@@ -40,56 +43,77 @@ def tearDownClass(cls):
4043 def setUp (self ):
4144 super ().setUp ()
4245
43- self ._seed_database_with_policies ()
46+ self ._seed_policies ()
4447
4548 self .authorized_user = UserFactory ()
4649 self .unauthorized_user = UserFactory ()
4750
48- for role in self .authz_roles_to_assign :
49- assign_role_to_user_in_scope (
50- self .authorized_user .username ,
51- role ,
52- str (self .course_key )
53- )
54-
55- AuthzEnforcer .get_enforcer ().load_policy ()
56-
5751 self .authorized_client = APIClient ()
5852 self .authorized_client .force_authenticate (user = self .authorized_user )
5953
6054 self .unauthorized_client = APIClient ()
6155 self .unauthorized_client .force_authenticate (user = self .unauthorized_user )
6256
63- def add_user_to_role (self , user , role ):
57+ def tearDown (self ):
58+ super ().tearDown ()
59+ AuthzEnforcer .get_enforcer ().clear_policy ()
60+
61+ def add_user_to_role_in_course (self , user , role , course_key ):
6462 """Helper method to add a user to a role for the course."""
6563 assign_role_to_user_in_scope (
6664 user .username ,
6765 role ,
68- str (self . course_key )
66+ str (course_key )
6967 )
7068 AuthzEnforcer .get_enforcer ().load_policy ()
7169
72- def tearDown (self ):
73- super ().tearDown ()
74- AuthzEnforcer .get_enforcer ().clear_policy ()
75-
7670 @classmethod
77- def _seed_database_with_policies (cls ):
71+ def _seed_policies (cls ):
7872 """Seed the database with AuthZ policies."""
7973 global_enforcer = AuthzEnforcer .get_enforcer ()
8074 global_enforcer .load_policy ()
8175
8276 model_path = pkg_resources .resource_filename (
8377 "openedx_authz.engine" ,
84- "config/model.conf"
78+ "config/model.conf" ,
8579 )
8680
8781 policy_path = pkg_resources .resource_filename (
8882 "openedx_authz.engine" ,
89- "config/authz.policy"
83+ "config/authz.policy" ,
9084 )
9185
9286 migrate_policy_between_enforcers (
9387 source_enforcer = casbin .Enforcer (model_path , policy_path ),
9488 target_enforcer = global_enforcer ,
9589 )
90+
91+
92+ class CourseAuthzTestMixin (CourseAuthoringAuthzTestMixin ):
93+ """
94+ Reusable mixin for testing course-scoped AuthZ endpoints.
95+ """
96+
97+ authz_roles_to_assign = [COURSE_STAFF .external_key ]
98+
99+ @property
100+ def course_key (self ):
101+ """
102+ Must be defined by subclasses.
103+ """
104+ raise NotImplementedError ("Tests using CourseAuthzTestMixin must define 'course_key'" )
105+
106+ def setUp (self ):
107+ super ().setUp ()
108+ for role in self .authz_roles_to_assign :
109+ assign_role_to_user_in_scope (
110+ self .authorized_user .username ,
111+ role ,
112+ str (self .course_key )
113+ )
114+
115+ AuthzEnforcer .get_enforcer ().load_policy ()
116+
117+ def add_user_to_role (self , user , role ):
118+ """Helper method to add a user to a role for the course."""
119+ self .add_user_to_role_in_course (user , role , self .course_key )
0 commit comments