# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Unit tests for RBAC bootstrap initialization. Tests that bootstrap creates correct rules and initial data. """ from unittest.mock import Mock, patch from modules.interfaces.interfaceBootstrap import ( initRootMandate, initAdminUser, initEventUser, initRbacRules, _createDefaultRoleRules, _createTableSpecificRules, ) from modules.datamodels.datamodelUam import UserInDB, Mandate from modules.datamodels.datamodelRbac import AccessRule, AccessRuleContext from modules.datamodels.datamodelUam import AccessLevel class TestRbacBootstrap: """Test RBAC bootstrap initialization.""" def testInitRootMandateCreatesIfNotExists(self): """Test that initRootMandate creates mandate if it doesn't exist.""" db = Mock() db.getRecordset = Mock(return_value=[]) db.recordCreate = Mock(return_value={"id": "mandate1", "name": "Root"}) mandateId = initRootMandate(db) assert mandateId == "mandate1" db.recordCreate.assert_called_once() callArgs = db.recordCreate.call_args assert isinstance(callArgs[0][1], Mandate) assert callArgs[0][1].name == "root" assert callArgs[0][1].label == "Root" def testInitRootMandateReturnsExisting(self): """Test that initRootMandate returns existing mandate ID.""" db = Mock() db.getRecordset = Mock(return_value=[{"id": "existing_mandate"}]) mandateId = initRootMandate(db) assert mandateId == "existing_mandate" db.recordCreate.assert_not_called() def testInitAdminUserCreatesWithSysadminRole(self): """Test that initAdminUser creates user with isSysAdmin=True.""" db = Mock() db.getRecordset = Mock(return_value=[]) db.recordCreate = Mock(return_value={"id": "admin1", "username": "admin"}) with patch("modules.interfaces.interfaceBootstrap._getPasswordHash", return_value="hashed"): userId = initAdminUser(db, "mandate1") assert userId == "admin1" db.recordCreate.assert_called_once() callArgs = db.recordCreate.call_args user = callArgs[0][1] assert isinstance(user, UserInDB) assert user.username == "admin" assert user.isSysAdmin is True def testInitEventUserCreatesWithSysadminRole(self): """Test that initEventUser creates user with isSysAdmin=True.""" db = Mock() db.getRecordset = Mock(return_value=[]) db.recordCreate = Mock(return_value={"id": "event1", "username": "event"}) with patch("modules.interfaces.interfaceBootstrap._getPasswordHash", return_value="hashed"): userId = initEventUser(db, "mandate1") assert userId == "event1" db.recordCreate.assert_called_once() callArgs = db.recordCreate.call_args user = callArgs[0][1] assert isinstance(user, UserInDB) assert user.username == "event" assert user.isSysAdmin is True def testCreateDefaultRoleRules(self): """Test that _createDefaultRoleRules creates admin + viewer generic DATA rules.""" db = Mock() db.recordCreate = Mock() with patch( "modules.interfaces.interfaceBootstrap._getRoleId", side_effect=lambda d, label: f"rid-{label}", ): _createDefaultRoleRules(db) assert db.recordCreate.call_count == 2 created = [c[0][1] for c in db.recordCreate.call_args_list] byRoleId = {r.roleId: r for r in created} adminRule = byRoleId["rid-admin"] assert adminRule.context == AccessRuleContext.DATA assert adminRule.item is None assert adminRule.view is True assert adminRule.read == AccessLevel.GROUP assert adminRule.create == AccessLevel.GROUP viewerRule = byRoleId["rid-viewer"] assert viewerRule.read == AccessLevel.GROUP assert viewerRule.create == AccessLevel.NONE def testCreateTableSpecificRules(self): """Test that _createTableSpecificRules creates table-specific rules.""" db = Mock() db.recordCreate = Mock() with patch( "modules.interfaces.interfaceBootstrap._getRoleId", side_effect=lambda d, label: f"rid-{label}", ): _createTableSpecificRules(db) assert db.recordCreate.call_count > 0 mandateCalls = [ call for call in db.recordCreate.call_args_list if call[0][1].item == "data.uam.Mandate" ] assert len(mandateCalls) > 0 for call in mandateCalls: rule = call[0][1] assert rule.view is False assert rule.read == AccessLevel.NONE def testInitRbacRulesSkipsIfExists(self): """When AccessRules already exist, init skips full init; ensure-* hooks are not exercised here.""" db = Mock() db.getRecordset = Mock(return_value=[{"id": "existing_rule"}]) db.recordCreate = Mock() with patch("modules.interfaces.interfaceBootstrap._ensureUiContextRules"): with patch("modules.interfaces.interfaceBootstrap._ensureDataContextRules"): initRbacRules(db) db.recordCreate.assert_not_called() def testInitRbacRulesCreatesIfNotExists(self): """Test that initRbacRules creates rules when the AccessRule table is empty.""" db = Mock() db.recordCreate = Mock() db.recordModify = Mock() db.getRecordset = Mock(return_value=[]) with patch( "modules.interfaces.interfaceBootstrap._getRoleId", side_effect=lambda d, label: f"rid-{label}", ): initRbacRules(db) assert db.recordCreate.call_count > 0