1212
1313import ddt
1414import httpretty
15- from django .conf import settings
1615from django .contrib import auth
17- from enterprise .models import EnterpriseCustomerIdentityProvider , EnterpriseCustomerUser
1816from freezegun import freeze_time
1917from social_core import actions
2018from social_django import views as social_views
2523from common .djangoapps .third_party_auth .exceptions import IncorrectConfigurationException
2624from common .djangoapps .third_party_auth .saml import SapSuccessFactorsIdentityProvider
2725from common .djangoapps .third_party_auth .saml import log as saml_log
26+ from common .djangoapps .third_party_auth .signals import SAMLAccountDisconnected
2827from common .djangoapps .third_party_auth .tasks import fetch_saml_metadata
2928from common .djangoapps .third_party_auth .tests import testutil , utils
3029from common .test .utils import assert_dict_contains_subset
3130from openedx .core .djangoapps .user_authn .views .login import login_user
32- from openedx .features .enterprise_support .tests .factories import EnterpriseCustomerFactory
3331
3432from .base import IntegrationTestMixin
3533
@@ -220,13 +218,7 @@ class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin
220218 "session_index" : "1" ,
221219 }
222220
223- @patch ("openedx.features.enterprise_support.api.enterprise_customer_for_request" )
224- @patch ("openedx.features.enterprise_support.utils.third_party_auth.provider.Registry.get" )
225- def test_full_pipeline_succeeds_for_unlinking_testshib_account (
226- self ,
227- mock_auth_provider ,
228- mock_enterprise_customer_for_request ,
229- ):
221+ def test_full_pipeline_succeeds_for_unlinking_testshib_account (self ):
230222
231223 # First, create, the request and strategy that store pipeline state,
232224 # configure the backend, and mock out wire traffic.
@@ -245,30 +237,6 @@ def test_full_pipeline_succeeds_for_unlinking_testshib_account(
245237 # We're already logged in, so simulate that the cookie is set correctly
246238 self .set_logged_in_cookies (request )
247239
248- # linking a learner with enterprise customer.
249- enterprise_customer = EnterpriseCustomerFactory ()
250- assert EnterpriseCustomerUser .objects .count () == 0 , "Precondition check: no link records should exist"
251- EnterpriseCustomerUser .objects .link_user (enterprise_customer , user .email )
252- assert (
253- EnterpriseCustomerUser .objects .filter (enterprise_customer = enterprise_customer , user_id = user .id ).count () == 1
254- )
255- EnterpriseCustomerIdentityProvider .objects .get_or_create (
256- enterprise_customer = enterprise_customer , provider_id = self .provider .provider_id
257- )
258-
259- enterprise_customer_data = {
260- "uuid" : enterprise_customer .uuid ,
261- "name" : enterprise_customer .name ,
262- "identity_provider" : "saml-default" ,
263- "identity_providers" : [
264- {
265- "provider_id" : "saml-default" ,
266- }
267- ],
268- }
269- mock_auth_provider .return_value .backend_name = "tpa-saml"
270- mock_enterprise_customer_for_request .return_value = enterprise_customer_data
271-
272240 # Instrument the pipeline to get to the dashboard with the full expected state.
273241 self .client .get (pipeline .get_login_url (self .provider .provider_id , pipeline .AUTH_ENTRY_LOGIN ))
274242
@@ -285,31 +253,35 @@ def test_full_pipeline_succeeds_for_unlinking_testshib_account(
285253 # First we expect that we're in the linked state, with a backend entry.
286254 self .assert_social_auth_exists_for_user (request .user , strategy )
287255
288- FEATURES_WITH_ENTERPRISE_ENABLED = settings .FEATURES .copy ()
289- FEATURES_WITH_ENTERPRISE_ENABLED ["ENABLE_ENTERPRISE_INTEGRATION" ] = True
290- with patch .dict ("django.conf.settings.FEATURES" , FEATURES_WITH_ENTERPRISE_ENABLED ):
256+ # Track signal emissions to verify the disconnect signal is sent.
257+ signal_calls = []
258+
259+ def signal_receiver (sender , ** kwargs ):
260+ signal_calls .append (kwargs )
261+
262+ SAMLAccountDisconnected .connect (signal_receiver )
263+ try :
291264 # Fire off the disconnect pipeline without the user information.
292265 actions .do_disconnect (
293266 request .backend , None , None , redirect_field_name = auth .REDIRECT_FIELD_NAME , request = request
294267 )
295- assert (
296- EnterpriseCustomerUser .objects .filter (enterprise_customer = enterprise_customer , user_id = user .id ).count ()
297- != 0
298- )
299268
300269 # Fire off the disconnect pipeline to unlink.
301270 self .assert_redirect_after_pipeline_completes (
302271 actions .do_disconnect (
303272 request .backend , user , None , redirect_field_name = auth .REDIRECT_FIELD_NAME , request = request
304273 )
305274 )
306- # Now we expect to be in the unlinked state, with no backend entry.
307- self .assert_third_party_accounts_state (request , linked = False )
308- self .assert_social_auth_does_not_exist_for_user (user , strategy )
309- assert (
310- EnterpriseCustomerUser .objects .filter (enterprise_customer = enterprise_customer , user_id = user .id ).count ()
311- == 0
312- )
275+ finally :
276+ SAMLAccountDisconnected .disconnect (signal_receiver )
277+
278+ # Now we expect to be in the unlinked state, with no backend entry.
279+ self .assert_third_party_accounts_state (request , linked = False )
280+ self .assert_social_auth_does_not_exist_for_user (user , strategy )
281+ # Verify that the SAMLAccountDisconnected signal was emitted.
282+ # The actual enterprise user unlinking is handled by edx-enterprise's
283+ # signal handler, not by openedx-platform.
284+ assert len (signal_calls ) == 2 , f"Expected 2 signal emissions, got { len (signal_calls )} "
313285
314286 def get_response_data (self ):
315287 """Gets dict (string -> object) of merged data about the user."""
0 commit comments