@@ -742,3 +742,56 @@ def test_no_duplicate_policies_when_policies_already_exist(
742742
743743 # The save_policy might not be called if no changes were made
744744 # We mainly want to ensure no duplicate additions occurred
745+
746+ @mock .patch ('sky.users.permission._policy_lock' )
747+ @mock .patch (
748+ 'sky.users.permission.PermissionService._maybe_initialize_policies' )
749+ @mock .patch (
750+ 'sky.users.permission.PermissionService._maybe_initialize_basic_auth_user'
751+ )
752+ @mock .patch ('sky.users.permission.casbin.Enforcer' )
753+ @mock .patch ('sky.users.permission.sqlalchemy_adapter.Adapter' )
754+ @mock .patch ('sky.users.permission.db_utils.add_all_tables_to_db_sqlalchemy' )
755+ @mock .patch ('sky.global_user_state.initialize_and_get_db' )
756+ def test_lazy_initialize_db_failure_recovery (
757+ self , mock_init_db , mock_add_tables , mock_adapter_class ,
758+ mock_enforcer_class , mock_init_basic_auth , mock_init_policies ,
759+ mock_policy_lock ):
760+ """Test that _lazy_initialize doesn't permanently set
761+ enforcer to None after DB failure on retry."""
762+ # Configure context manager to allow exceptions to propagate
763+ mock_context = mock .Mock ()
764+ mock_context .__enter__ = mock .Mock (return_value = None )
765+ mock_context .__exit__ = mock .Mock (
766+ return_value = False ) # Don't suppress exceptions
767+ mock_policy_lock .return_value = mock_context
768+
769+ mock_engine = mock .Mock ()
770+ mock_init_db .return_value = mock_engine
771+
772+ mock_adapter = mock .Mock ()
773+ mock_adapter_class .return_value = mock_adapter
774+
775+ mock_enforcer = mock .Mock ()
776+ mock_enforcer_class .return_value = mock_enforcer
777+
778+ # First call: add_all_tables_to_db_sqlalchemy raises an error
779+ # Second call: it succeeds
780+ mock_add_tables .side_effect = [
781+ Exception ("Database connection failed" ),
782+ None # Success on second call
783+ ]
784+
785+ service = permission .PermissionService ()
786+
787+ # First call - should raise an exception
788+ with pytest .raises (Exception ) as exc_info :
789+ service ._lazy_initialize ()
790+ assert "Database connection failed" in str (exc_info .value )
791+
792+ # Second call - should succeed
793+ service ._lazy_initialize ()
794+
795+ # Verify that self.enforcer is not None after successful initialization
796+ assert service .enforcer is not None
797+ assert service .enforcer == mock_enforcer
0 commit comments