@@ -442,6 +442,185 @@ async def mock_auser():
442442
443443 asyncio .run (run_test ())
444444
445+ def test_async_middleware_with_unauthenticated_user (self ):
446+ """
447+ Test that async middleware handles unauthenticated users correctly.
448+ """
449+
450+ async def run_test ():
451+ mock_response = Mock ()
452+ mock_user = Mock ()
453+ mock_user .is_authenticated = False # Not authenticated
454+
455+ async def async_get_response (request ):
456+ # Verify no distinct_id was set (no user)
457+ distinct_id = get_context_distinct_id ()
458+ self .assertIsNone (distinct_id )
459+ return mock_response
460+
461+ middleware = PosthogContextMiddleware (async_get_response )
462+ middleware .client = Mock ()
463+
464+ request = MockRequest (
465+ headers = {"X-POSTHOG-SESSION-ID" : "test-session" }, method = "GET"
466+ )
467+
468+ async def mock_auser ():
469+ return mock_user
470+
471+ request .auser = mock_auser
472+
473+ with new_context ():
474+ result = middleware (request )
475+ response = await result
476+ self .assertEqual (response , mock_response )
477+
478+ asyncio .run (run_test ())
479+
480+ def test_async_middleware_without_user_attribute (self ):
481+ """
482+ Test that async middleware handles requests without user attribute (no auth middleware).
483+ """
484+
485+ async def run_test ():
486+ mock_response = Mock ()
487+
488+ async def async_get_response (request ):
489+ return mock_response
490+
491+ middleware = PosthogContextMiddleware (async_get_response )
492+ middleware .client = Mock ()
493+
494+ # Request without auser method (no auth middleware)
495+ request = MockRequest (
496+ headers = {"X-POSTHOG-SESSION-ID" : "test-session" }, method = "GET"
497+ )
498+
499+ with new_context ():
500+ result = middleware (request )
501+ response = await result
502+ self .assertEqual (response , mock_response )
503+
504+ asyncio .run (run_test ())
505+
506+ def test_async_middleware_with_extra_tags (self ):
507+ """
508+ Test that async middleware works with extra_tags callback.
509+ """
510+
511+ async def run_test ():
512+ mock_response = Mock ()
513+
514+ def extra_tags_callback (request ):
515+ # Simple sync callback - should work
516+ return {"custom_tag" : "custom_value" }
517+
518+ async def async_get_response (request ):
519+ return mock_response
520+
521+ middleware = PosthogContextMiddleware (async_get_response )
522+ middleware .extra_tags = extra_tags_callback
523+ middleware .client = Mock ()
524+
525+ request = MockRequest (
526+ headers = {"X-POSTHOG-SESSION-ID" : "test-session" }, method = "GET"
527+ )
528+
529+ # Mock auser for no user
530+ async def mock_auser ():
531+ return None
532+
533+ request .auser = mock_auser
534+
535+ with new_context ():
536+ result = middleware (request )
537+ response = await result
538+ self .assertEqual (response , mock_response )
539+
540+ asyncio .run (run_test ())
541+
542+ def test_async_middleware_with_tag_map (self ):
543+ """
544+ Test that async middleware works with tag_map callback.
545+ """
546+
547+ async def run_test ():
548+ mock_response = Mock ()
549+
550+ def tag_map_callback (tags ):
551+ # Simple sync callback - should work
552+ tags ["mapped" ] = "yes"
553+ return tags
554+
555+ async def async_get_response (request ):
556+ return mock_response
557+
558+ middleware = PosthogContextMiddleware (async_get_response )
559+ middleware .tag_map = tag_map_callback
560+ middleware .client = Mock ()
561+
562+ request = MockRequest (
563+ headers = {"X-POSTHOG-SESSION-ID" : "test-session" }, method = "GET"
564+ )
565+
566+ # Mock auser for no user
567+ async def mock_auser ():
568+ return None
569+
570+ request .auser = mock_auser
571+
572+ with new_context ():
573+ result = middleware (request )
574+ response = await result
575+ self .assertEqual (response , mock_response )
576+
577+ asyncio .run (run_test ())
578+
579+ def test_async_middleware_user_extraction_with_all_headers (self ):
580+ """
581+ Test async middleware extracts all request info correctly.
582+ """
583+
584+ async def run_test ():
585+ mock_response = Mock ()
586+ mock_user = Mock ()
587+ mock_user .is_authenticated = True
588+ mock_user .pk = 456
589+ mock_user .
email = "[email protected] " 590+
591+ async def async_get_response (request ):
592+ # Verify all context was set correctly
593+ distinct_id = get_context_distinct_id ()
594+ session_id = get_context_session_id ()
595+ self .assertEqual (distinct_id , "456" )
596+ self .assertEqual (session_id , "async-sess-123" )
597+ return mock_response
598+
599+ middleware = PosthogContextMiddleware (async_get_response )
600+ middleware .client = Mock ()
601+
602+ request = MockRequest (
603+ headers = {
604+ "X-POSTHOG-SESSION-ID" : "async-sess-123" ,
605+ "X-Forwarded-For" : "192.168.1.1" ,
606+ "User-Agent" : "TestAgent/1.0" ,
607+ },
608+ method = "POST" ,
609+ path = "/api/test" ,
610+ )
611+
612+ async def mock_auser ():
613+ return mock_user
614+
615+ request .auser = mock_auser
616+
617+ with new_context ():
618+ result = middleware (request )
619+ response = await result
620+ self .assertEqual (response , mock_response )
621+
622+ asyncio .run (run_test ())
623+
445624
446625class TestPosthogContextMiddlewareHybrid (unittest .TestCase ):
447626 """Test hybrid middleware behavior with mixed sync/async chains"""
0 commit comments