# #region TestSeedPermissions [C:2] [TYPE Module] [SEMANTICS test,rbac,permissions,seed] # @BRIEF Tests for seed_permissions.py script (mocked DB, no real auth.db). # @RELATION BINDS_TO -> [SeedPermissionsScript] # @TEST_EDGE: initial_permissions_structure -> All entries have resource+action # @TEST_EDGE: initial_permissions_values -> Known permissions present # @TEST_EDGE: seed_permissions_adds_new -> Creates missing permissions # @TEST_EDGE: seed_permissions_idempotent -> Skips existing permissions # @TEST_EDGE: seed_permissions_creates_user_role -> Creates User role if missing # @TEST_EDGE: seed_permissions_assigns_to_user_role -> Assigns permissions to User role # @TEST_EDGE: seed_permissions_db_error -> Rollback on failure import sys from pathlib import Path from unittest.mock import MagicMock, patch, PropertyMock import pytest sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) # ============================================================================= # INITIAL_PERMISSIONS # ============================================================================= class TestInitialPermissions: """Data integrity tests for INITIAL_PERMISSIONS constant.""" def test_all_entries_have_resource_and_action(self): """Invariant: every permission has both resource and action.""" from src.scripts.seed_permissions import INITIAL_PERMISSIONS for perm in INITIAL_PERMISSIONS: assert "resource" in perm, f"Missing resource in {perm}" assert "action" in perm, f"Missing action in {perm}" assert isinstance(perm["resource"], str), f"resource not str: {perm}" assert isinstance(perm["action"], str), f"action not str: {perm}" def test_known_permissions_present(self): """Structural: expected permissions exist in the set.""" from src.scripts.seed_permissions import INITIAL_PERMISSIONS perm_set = {(p["resource"], p["action"]) for p in INITIAL_PERMISSIONS} assert ("admin:users", "READ") in perm_set assert ("admin:users", "WRITE") in perm_set assert ("plugin:migration", "EXECUTE") in perm_set assert ("dataset:session", "APPROVE") in perm_set assert ("dataset:execution", "LAUNCH_PROD") in perm_set assert ("settings.connections", "MANAGE") in perm_set def test_no_duplicate_permissions(self): """Invariant: no duplicate (resource, action) pairs.""" from src.scripts.seed_permissions import INITIAL_PERMISSIONS pairs = [(p["resource"], p["action"]) for p in INITIAL_PERMISSIONS] assert len(pairs) == len(set(pairs)), "Duplicate permissions found" def test_non_empty(self): """Structural: INITIAL_PERMISSIONS is not empty.""" from src.scripts.seed_permissions import INITIAL_PERMISSIONS assert len(INITIAL_PERMISSIONS) > 0 # ============================================================================= # seed_permissions # ============================================================================= class TestSeedPermissions: """Tests for seed_permissions.seed_permissions().""" @patch("src.scripts.seed_permissions.AuthSessionLocal") @patch("src.scripts.seed_permissions.AuthRepository") @patch("src.scripts.seed_permissions.Role") def test_adds_new_permissions(self, MockRole, MockRepo, MockSession): """Happy: creates all missing permissions.""" from src.scripts.seed_permissions import seed_permissions mock_db = MagicMock() MockSession.return_value = mock_db # No existing permissions (query returns None for all) mock_db.query.return_value.filter.return_value.first.return_value = None # Mock AuthRepository mock_repo = MagicMock() MockRepo.return_value = mock_repo # Mock get_role_by_name to return None -> creates User role mock_repo.get_role_by_name.return_value = None # Mock get_permission_by_resource_action to return a permission mock_repo.get_permission_by_resource_action.return_value = MagicMock() # Add a User role mock_user_role = MagicMock() mock_user_role.permissions = [] MockRole.return_value = mock_user_role seed_permissions() # Verify permissions were added to DB assert mock_db.add.call_count > 0 mock_db.commit.assert_called() mock_db.close.assert_called_once() @patch("src.scripts.seed_permissions.AuthSessionLocal") @patch("src.scripts.seed_permissions.AuthRepository") @patch("src.scripts.seed_permissions.Role") def test_idempotent_skips_existing(self, MockRole, MockRepo, MockSession): """Edge: existing permissions are skipped (no duplicates).""" from src.scripts.seed_permissions import seed_permissions mock_db = MagicMock() MockSession.return_value = mock_db # All permissions already exist mock_db.query.return_value.filter.return_value.first.return_value = MagicMock() mock_repo = MagicMock() MockRepo.return_value = mock_repo mock_repo.get_role_by_name.return_value = None mock_user_role = MagicMock() mock_user_role.permissions = [] MockRole.return_value = mock_user_role mock_repo.get_permission_by_resource_action.return_value = MagicMock() seed_permissions() # No new permissions should be added (all exist) # add() may still be called for the User role, but not for permissions mock_db.commit.assert_called() mock_db.close.assert_called_once() @patch("src.scripts.seed_permissions.AuthSessionLocal") @patch("src.scripts.seed_permissions.AuthRepository") @patch("src.scripts.seed_permissions.Role") def test_db_error_rollback(self, MockRole, MockRepo, MockSession): """Edge: DB error triggers rollback.""" from src.scripts.seed_permissions import seed_permissions mock_db = MagicMock() MockSession.return_value = mock_db mock_db.query.return_value.filter.return_value.first.return_value = None mock_repo = MagicMock() MockRepo.return_value = mock_repo mock_repo.get_role_by_name.side_effect = Exception("DB fail") seed_permissions() mock_db.rollback.assert_called_once() mock_db.close.assert_called_once() # #endregion TestSeedPermissions