Skip to content

Commit 8b584e2

Browse files
committed
test: add unit tests for new org glob scopes
1 parent d51a1a4 commit 8b584e2

1 file changed

Lines changed: 134 additions & 1 deletion

File tree

openedx_authz/tests/api/test_data.py

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
from unittest.mock import Mock, patch
44

55
from ddt import data, ddt, unpack
6-
from django.test import TestCase
6+
from django.test import TestCase, override_settings
77
from opaque_keys.edx.locator import LibraryLocatorV2
88

99
from openedx_authz.api.data import (
1010
ActionData,
1111
ContentLibraryData,
1212
CourseOverviewData,
13+
OrgCourseGlobData,
14+
OrgLibraryGlobData,
1315
PermissionData,
1416
RoleAssignmentData,
1517
RoleData,
@@ -19,6 +21,7 @@
1921
UserData,
2022
)
2123
from openedx_authz.constants import permissions, roles
24+
from openedx_authz.tests.stubs.models import ContentLibrary, CourseOverview, Organization
2225

2326

2427
@ddt
@@ -233,9 +236,17 @@ def test_scope_data_registration(self):
233236
self.assertIn("course-v1", ScopeData.scope_registry)
234237
self.assertIs(ScopeData.scope_registry["course-v1"], CourseOverviewData)
235238

239+
# Glob registries for organization-level scopes
240+
self.assertIn("lib", ScopeMeta.glob_registry)
241+
self.assertIs(ScopeMeta.glob_registry["lib"], OrgLibraryGlobData)
242+
self.assertIn("course-v1", ScopeMeta.glob_registry)
243+
self.assertIs(ScopeMeta.glob_registry["course-v1"], OrgCourseGlobData)
244+
236245
@data(
237246
("course-v1^course-v1:WGU+CS002+2025_T1", CourseOverviewData),
238247
("lib^lib:DemoX:CSPROB", ContentLibraryData),
248+
("lib^lib:DemoX*", OrgLibraryGlobData),
249+
("course-v1^course-v1:OpenedX*", OrgCourseGlobData),
239250
("global^generic_scope", ScopeData),
240251
)
241252
@unpack
@@ -254,6 +265,8 @@ def test_dynamic_instantiation_via_namespaced_key(self, namespaced_key, expected
254265
@data(
255266
("course-v1^course-v1:WGU+CS002+2025_T1", CourseOverviewData),
256267
("lib^lib:DemoX:CSPROB", ContentLibraryData),
268+
("lib^lib:DemoX*", OrgLibraryGlobData),
269+
("course-v1^course-v1:OpenedX*", OrgCourseGlobData),
257270
("global^generic", ScopeData),
258271
("unknown^something", ScopeData),
259272
)
@@ -273,6 +286,8 @@ def test_get_subclass_by_namespaced_key(self, namespaced_key, expected_class):
273286
@data(
274287
("course-v1:WGU+CS002+2025_T1", CourseOverviewData),
275288
("lib:DemoX:CSPROB", ContentLibraryData),
289+
("lib:DemoX*", OrgLibraryGlobData),
290+
("course-v1:OpenedX*", OrgCourseGlobData),
276291
("lib:edX:Demo", ContentLibraryData),
277292
("global:generic_scope", ScopeData),
278293
)
@@ -654,3 +669,121 @@ def test_exists_returns_false_when_library_does_not_exist(self, mock_content_lib
654669
result = library_scope.exists()
655670

656671
self.assertFalse(result)
672+
673+
674+
@ddt
675+
@override_settings(OPENEDX_AUTHZ_CONTENT_LIBRARY_MODEL="content_libraries.ContentLibrary")
676+
class TestOrgLibraryGlobData(TestCase):
677+
"""Tests for the OrgLibraryGlobData scope."""
678+
679+
@data(
680+
("lib:DemoX*", True),
681+
("lib:Org-123*", True),
682+
("lib:Org.with.dots*", True),
683+
("lib:Org:With:Colon*", False),
684+
("lib:Org", False),
685+
("other:DemoX*", False),
686+
("lib:DemoX**", False),
687+
)
688+
@unpack
689+
def test_validate_external_key(self, external_key, expected_valid):
690+
"""Validate organization-level library glob external keys."""
691+
self.assertEqual(OrgLibraryGlobData.validate_external_key(external_key), expected_valid)
692+
693+
@data(
694+
("lib:DemoX*", "DemoX"),
695+
("lib:Org-123*", "Org-123"),
696+
("lib:Org.with.dots*", "Org.with.dots"),
697+
("lib:Org:With:Colon*", None),
698+
("lib:*", None),
699+
)
700+
@unpack
701+
def test_get_org(self, external_key, expected_org):
702+
"""Test organization extraction from library glob pattern."""
703+
self.assertEqual(OrgLibraryGlobData.get_org(external_key), expected_org)
704+
705+
def test_exists_true_when_org_has_libraries_in_db(self):
706+
"""exists() returns True when at least one library with the org exists in the DB."""
707+
org_name = "DemoX"
708+
organization = Organization.objects.create(short_name=org_name)
709+
ContentLibrary.objects.create(org=organization, slug="testlib", title="Test Library")
710+
711+
result = OrgLibraryGlobData(external_key=f"lib:{org_name}*").exists()
712+
713+
self.assertTrue(result)
714+
715+
def test_exists_false_when_org_does_not_exist_in_db(self):
716+
"""exists() returns False when the org does not exist in the DB."""
717+
org_name = "DemoX"
718+
719+
result = OrgLibraryGlobData(external_key=f"lib:{org_name}*").exists()
720+
721+
self.assertFalse(result)
722+
723+
def test_exists_false_when_org_exists_but_no_libraries_in_db(self):
724+
"""exists() returns False when the org exists but no libraries exist in the DB."""
725+
org_name = "DemoX"
726+
Organization.objects.create(short_name=org_name)
727+
728+
result = OrgLibraryGlobData(external_key=f"lib:{org_name}*").exists()
729+
730+
self.assertFalse(result)
731+
732+
733+
@ddt
734+
@override_settings(OPENEDX_AUTHZ_COURSE_OVERVIEW_MODEL="course_overviews.CourseOverview")
735+
class TestOrgCourseGlobData(TestCase):
736+
"""Tests for the OrgCourseGlobData scope."""
737+
738+
@data(
739+
("course-v1:OpenedX*", True),
740+
("course-v1:My-Org_1*", True),
741+
("course-v1:Org.with.dots*", True),
742+
("course-v1:Org:With:Plus*", False),
743+
("course-v1:OpenedX", False),
744+
("other:OpenedX*", False),
745+
("course-v1:OpenedX**", False),
746+
)
747+
@unpack
748+
def test_validate_external_key(self, external_key, expected_valid):
749+
"""Validate organization-level course glob external keys."""
750+
self.assertEqual(OrgCourseGlobData.validate_external_key(external_key), expected_valid)
751+
752+
@data(
753+
("course-v1:OpenedX*", "OpenedX"),
754+
("course-v1:My-Org_1*", "My-Org_1"),
755+
("course-v1:Org.with.dots*", "Org.with.dots"),
756+
("course-v1:Org:With:Plus*", None),
757+
("course-v1:*", None),
758+
)
759+
@unpack
760+
def test_get_org(self, external_key, expected_org):
761+
"""Test organization extraction from course glob pattern."""
762+
self.assertEqual(OrgCourseGlobData.get_org(external_key), expected_org)
763+
764+
def test_exists_true_when_org_has_courses(self):
765+
"""exists() returns True when at least one course with the org exists."""
766+
org_name = "OpenedX"
767+
Organization.objects.create(short_name=org_name)
768+
CourseOverview.objects.create(org=org_name, display_name="Test Course")
769+
770+
result = OrgCourseGlobData(external_key=f"course-v1:{org_name}*").exists()
771+
772+
self.assertTrue(result)
773+
774+
def test_exists_false_when_org_does_not_exist(self):
775+
"""exists() returns False when the org does not exist."""
776+
org_name = "OpenedX"
777+
778+
result = OrgCourseGlobData(external_key=f"course-v1:{org_name}*").exists()
779+
780+
self.assertFalse(result)
781+
782+
def test_exists_false_when_org_exists_but_no_courses(self):
783+
"""exists() returns False when the org exists but no courses exist."""
784+
org_name = "OpenedX"
785+
Organization.objects.create(short_name=org_name)
786+
787+
result = OrgCourseGlobData(external_key=f"course-v1:{org_name}*").exists()
788+
789+
self.assertFalse(result)

0 commit comments

Comments
 (0)