from __future__ import annotations import unittest from types import SimpleNamespace from unittest.mock import Mock, patch from govoplan_files.backend.storage.common import FileStorageError from govoplan_files.backend.storage.connector_spaces import soft_delete_connector_space class ConnectorSpaceDeletionTests(unittest.TestCase): def setUp(self) -> None: self.session = Mock() self.space = SimpleNamespace( tenant_id="tenant-1", owner_type="user", owner_user_id="owner-1", owner_group_id=None, deleted_at=None, is_active=True, ) @patch("govoplan_files.backend.storage.connector_spaces.utcnow") @patch("govoplan_files.backend.storage.connector_spaces.ensure_owner_access") def test_owner_can_soft_delete_local_space_definition( self, ensure_owner_access: Mock, utcnow: Mock ) -> None: deleted_at = object() utcnow.return_value = deleted_at result = soft_delete_connector_space( self.session, self.space, user_id="owner-1" ) self.assertIs(result, self.space) self.assertIs(deleted_at, self.space.deleted_at) self.assertFalse(self.space.is_active) ensure_owner_access.assert_called_once_with( self.session, tenant_id="tenant-1", owner_type="user", owner_id="owner-1", user_id="owner-1", is_admin=False, ) self.session.add.assert_called_once_with(self.space) self.session.flush.assert_called_once_with() @patch( "govoplan_files.backend.storage.connector_spaces.ensure_owner_access", side_effect=FileStorageError("File space access denied"), ) def test_inaccessible_space_is_blocked_without_mutation( self, _ensure_owner_access: Mock ) -> None: with self.assertRaisesRegex(FileStorageError, "access denied"): soft_delete_connector_space( self.session, self.space, user_id="other-user" ) self.assertIsNone(self.space.deleted_at) self.assertTrue(self.space.is_active) self.session.add.assert_not_called() self.session.flush.assert_not_called() if __name__ == "__main__": unittest.main()