88import pytest
99
1010from openedx_content import api
11- from openedx_content .models_api import PublishableEntity , PublishLog
11+ from openedx_content .models_api import LearningPackage , PublishableEntity , PublishLog
1212from tests .utils import abort_transaction , capture_events
1313
1414pytestmark = pytest .mark .django_db (transaction = True )
@@ -35,6 +35,98 @@ def change_record(obj: PublishableEntity, old_version: int | None, new_version:
3535 )
3636
3737
38+ # LEARNING_PACKAGE_CREATED
39+
40+
41+ def test_learning_package_created () -> None :
42+ """
43+ Test that LEARNING_PACKAGE_CREATED is emitted when a new ``LearningPackage``
44+ is created.
45+ """
46+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_CREATED ], expected_count = 1 ) as captured :
47+ learning_package = api .create_learning_package (key = "lp1" , title = "Test LP 📦" )
48+
49+ event = captured [0 ]
50+ assert event .signal is api .signals .LEARNING_PACKAGE_CREATED
51+ assert event .kwargs ["learning_package" ].id == learning_package .id
52+ assert event .kwargs ["learning_package" ].title == "Test LP 📦"
53+
54+
55+ def test_learning_package_created_not_emitted_on_update () -> None :
56+ """
57+ Test that updating an existing ``LearningPackage`` does NOT emit
58+ LEARNING_PACKAGE_CREATED. The event is only for new rows.
59+ """
60+ learning_package = api .create_learning_package (key = "lp1" , title = "Test LP 📦" )
61+
62+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_CREATED ], expected_count = 0 ):
63+ api .update_learning_package (learning_package .id , title = "Updated Title" )
64+
65+
66+ def test_learning_package_created_aborted () -> None :
67+ """
68+ Test that LEARNING_PACKAGE_CREATED is NOT emitted when the transaction
69+ that created the ``LearningPackage`` is rolled back.
70+ """
71+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_CREATED ], expected_count = 0 ):
72+ with abort_transaction ():
73+ api .create_learning_package (key = "lp1" , title = "Test LP 📦" )
74+
75+
76+ # LEARNING_PACKAGE_DELETED
77+
78+
79+ def test_learning_package_deleted () -> None :
80+ """
81+ Test that LEARNING_PACKAGE_DELETED is emitted when a ``LearningPackage``
82+ is deleted.
83+ """
84+ learning_package = api .create_learning_package (key = "lp1" , title = "Test LP 📦" )
85+ lp_id = learning_package .id
86+
87+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_DELETED ], expected_count = 1 ) as captured :
88+ learning_package .delete ()
89+
90+ event = captured [0 ]
91+ assert event .signal is api .signals .LEARNING_PACKAGE_DELETED
92+ assert event .kwargs ["learning_package" ].id == lp_id
93+ assert event .kwargs ["learning_package" ].title == "Test LP 📦"
94+
95+
96+ def test_learning_package_deleted_via_queryset () -> None :
97+ """
98+ Test that LEARNING_PACKAGE_DELETED fires once per row when multiple
99+ ``LearningPackage`` instances are deleted via a ``QuerySet.delete()``.
100+ """
101+ lp1 = api .create_learning_package (key = "lp1" , title = "LP 1" )
102+ lp2 = api .create_learning_package (key = "lp2" , title = "LP 2" )
103+
104+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_DELETED ], expected_count = 2 ) as captured :
105+ LearningPackage .objects .filter (id__in = [lp1 .id , lp2 .id ]).delete ()
106+
107+ deleted_ids = {event .kwargs ["learning_package" ].id for event in captured }
108+ assert deleted_ids == {lp1 .id , lp2 .id }
109+
110+
111+ def test_learning_package_deleted_aborted () -> None :
112+ """
113+ Test that LEARNING_PACKAGE_DELETED is NOT emitted when the transaction
114+ that would have deleted the ``LearningPackage`` is rolled back.
115+ """
116+ learning_package = api .create_learning_package (key = "lp1" , title = "Test LP 📦" )
117+ lp_id = learning_package .id
118+
119+ with capture_events (signals = [api .signals .LEARNING_PACKAGE_DELETED ], expected_count = 0 ):
120+ with abort_transaction ():
121+ learning_package .delete ()
122+
123+ # Confirm it's still in the database (the row survived the rollback).
124+ # Note: we can't use ``learning_package.id`` here because Django sets
125+ # ``instance.id = None`` after ``.delete()``, even if the transaction
126+ # ultimately rolls back; that's why we captured it beforehand.
127+ assert LearningPackage .objects .filter (id = lp_id ).exists ()
128+
129+
38130# LEARNING_PACKAGE_ENTITIES_CHANGED
39131
40132
0 commit comments