feat: refactor: test_dataset unit tests #21499 (#21502)

This commit is contained in:
NeatGuyCoding
2025-06-26 10:07:54 +08:00
committed by GitHub
parent 6bb82f8ee0
commit 785d4b3de7
3 changed files with 1313 additions and 1793 deletions

View File

@@ -8,151 +8,298 @@ from services.dataset_service import DatasetService
from services.errors.account import NoPermissionError from services.errors.account import NoPermissionError
class DatasetPermissionTestDataFactory:
"""Factory class for creating test data and mock objects for dataset permission tests."""
@staticmethod
def create_dataset_mock(
dataset_id: str = "dataset-123",
tenant_id: str = "test-tenant-123",
created_by: str = "creator-456",
permission: DatasetPermissionEnum = DatasetPermissionEnum.ONLY_ME,
**kwargs,
) -> Mock:
"""Create a mock dataset with specified attributes."""
dataset = Mock(spec=Dataset)
dataset.id = dataset_id
dataset.tenant_id = tenant_id
dataset.created_by = created_by
dataset.permission = permission
for key, value in kwargs.items():
setattr(dataset, key, value)
return dataset
@staticmethod
def create_user_mock(
user_id: str = "user-789",
tenant_id: str = "test-tenant-123",
role: TenantAccountRole = TenantAccountRole.NORMAL,
**kwargs,
) -> Mock:
"""Create a mock user with specified attributes."""
user = Mock(spec=Account)
user.id = user_id
user.current_tenant_id = tenant_id
user.current_role = role
for key, value in kwargs.items():
setattr(user, key, value)
return user
@staticmethod
def create_dataset_permission_mock(
dataset_id: str = "dataset-123",
account_id: str = "user-789",
**kwargs,
) -> Mock:
"""Create a mock dataset permission record."""
permission = Mock(spec=DatasetPermission)
permission.dataset_id = dataset_id
permission.account_id = account_id
for key, value in kwargs.items():
setattr(permission, key, value)
return permission
class TestDatasetPermissionService: class TestDatasetPermissionService:
"""Test cases for dataset permission checking functionality""" """
Comprehensive unit tests for DatasetService.check_dataset_permission method.
def setup_method(self): This test suite covers all permission scenarios including:
"""Set up test fixtures""" - Cross-tenant access restrictions
# Mock tenant and user - Owner privilege checks
self.tenant_id = "test-tenant-123" - Different permission levels (ONLY_ME, ALL_TEAM, PARTIAL_TEAM)
self.creator_id = "creator-456" - Explicit permission checks for PARTIAL_TEAM
self.normal_user_id = "normal-789" - Error conditions and logging
self.owner_user_id = "owner-999" """
# Mock dataset @pytest.fixture
self.dataset = Mock(spec=Dataset) def mock_dataset_service_dependencies(self):
self.dataset.id = "dataset-123" """Common mock setup for dataset service dependencies."""
self.dataset.tenant_id = self.tenant_id with patch("services.dataset_service.db.session") as mock_session:
self.dataset.created_by = self.creator_id yield {
"db_session": mock_session,
}
# Mock users @pytest.fixture
self.creator_user = Mock(spec=Account) def mock_logging_dependencies(self):
self.creator_user.id = self.creator_id """Mock setup for logging tests."""
self.creator_user.current_tenant_id = self.tenant_id with patch("services.dataset_service.logging") as mock_logging:
self.creator_user.current_role = TenantAccountRole.EDITOR yield {
"logging": mock_logging,
self.normal_user = Mock(spec=Account) }
self.normal_user.id = self.normal_user_id
self.normal_user.current_tenant_id = self.tenant_id
self.normal_user.current_role = TenantAccountRole.NORMAL
self.owner_user = Mock(spec=Account)
self.owner_user.id = self.owner_user_id
self.owner_user.current_tenant_id = self.tenant_id
self.owner_user.current_role = TenantAccountRole.OWNER
def test_permission_check_different_tenant_should_fail(self):
"""Test that users from different tenants cannot access dataset"""
self.normal_user.current_tenant_id = "different-tenant"
with pytest.raises(NoPermissionError, match="You do not have permission to access this dataset."):
DatasetService.check_dataset_permission(self.dataset, self.normal_user)
def test_owner_can_access_any_dataset(self):
"""Test that tenant owners can access any dataset regardless of permission"""
self.dataset.permission = DatasetPermissionEnum.ONLY_ME
def _assert_permission_check_passes(self, dataset: Mock, user: Mock):
"""Helper method to verify that permission check passes without raising exceptions."""
# Should not raise any exception # Should not raise any exception
DatasetService.check_dataset_permission(self.dataset, self.owner_user) DatasetService.check_dataset_permission(dataset, user)
def test_only_me_permission_creator_can_access(self): def _assert_permission_check_fails(
"""Test ONLY_ME permission allows only creator to access""" self, dataset: Mock, user: Mock, expected_message: str = "You do not have permission to access this dataset."
self.dataset.permission = DatasetPermissionEnum.ONLY_ME ):
"""Helper method to verify that permission check fails with expected error."""
with pytest.raises(NoPermissionError, match=expected_message):
DatasetService.check_dataset_permission(dataset, user)
# Creator should be able to access def _assert_database_query_called(self, mock_session: Mock, dataset_id: str, account_id: str):
DatasetService.check_dataset_permission(self.dataset, self.creator_user) """Helper method to verify database query calls for permission checks."""
mock_session.query().filter_by.assert_called_with(dataset_id=dataset_id, account_id=account_id)
def test_only_me_permission_others_cannot_access(self): def _assert_database_query_not_called(self, mock_session: Mock):
"""Test ONLY_ME permission denies access to non-creators""" """Helper method to verify that database query was not called."""
self.dataset.permission = DatasetPermissionEnum.ONLY_ME
with pytest.raises(NoPermissionError, match="You do not have permission to access this dataset."):
DatasetService.check_dataset_permission(self.dataset, self.normal_user)
def test_all_team_permission_allows_access(self):
"""Test ALL_TEAM permission allows any team member to access"""
self.dataset.permission = DatasetPermissionEnum.ALL_TEAM
# Should not raise any exception for team members
DatasetService.check_dataset_permission(self.dataset, self.normal_user)
DatasetService.check_dataset_permission(self.dataset, self.creator_user)
@patch("services.dataset_service.db.session")
def test_partial_team_permission_creator_can_access(self, mock_session):
"""Test PARTIAL_TEAM permission allows creator to access"""
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM
# Should not raise any exception for creator
DatasetService.check_dataset_permission(self.dataset, self.creator_user)
# Should not query database for creator
mock_session.query.assert_not_called() mock_session.query.assert_not_called()
@patch("services.dataset_service.db.session") # ==================== Cross-Tenant Access Tests ====================
def test_partial_team_permission_with_explicit_permission(self, mock_session):
"""Test PARTIAL_TEAM permission allows users with explicit permission""" def test_permission_check_different_tenant_should_fail(self):
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM """Test that users from different tenants cannot access dataset regardless of other permissions."""
# Create dataset and user from different tenants
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
tenant_id="tenant-123", permission=DatasetPermissionEnum.ALL_TEAM
)
user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="user-789", tenant_id="different-tenant-456", role=TenantAccountRole.EDITOR
)
# Should fail due to different tenant
self._assert_permission_check_fails(dataset, user)
# ==================== Owner Privilege Tests ====================
def test_owner_can_access_any_dataset(self):
"""Test that tenant owners can access any dataset regardless of permission level."""
# Create dataset with restrictive permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(permission=DatasetPermissionEnum.ONLY_ME)
# Create owner user
owner_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="owner-999", role=TenantAccountRole.OWNER
)
# Owner should have access regardless of dataset permission
self._assert_permission_check_passes(dataset, owner_user)
# ==================== ONLY_ME Permission Tests ====================
def test_only_me_permission_creator_can_access(self):
"""Test ONLY_ME permission allows only the dataset creator to access."""
# Create dataset with ONLY_ME permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
created_by="creator-456", permission=DatasetPermissionEnum.ONLY_ME
)
# Create creator user
creator_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="creator-456", role=TenantAccountRole.EDITOR
)
# Creator should be able to access
self._assert_permission_check_passes(dataset, creator_user)
def test_only_me_permission_others_cannot_access(self):
"""Test ONLY_ME permission denies access to non-creators."""
# Create dataset with ONLY_ME permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
created_by="creator-456", permission=DatasetPermissionEnum.ONLY_ME
)
# Create normal user (not the creator)
normal_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="normal-789", role=TenantAccountRole.NORMAL
)
# Non-creator should be denied access
self._assert_permission_check_fails(dataset, normal_user)
# ==================== ALL_TEAM Permission Tests ====================
def test_all_team_permission_allows_access(self):
"""Test ALL_TEAM permission allows any team member to access the dataset."""
# Create dataset with ALL_TEAM permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(permission=DatasetPermissionEnum.ALL_TEAM)
# Create different types of team members
normal_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="normal-789", role=TenantAccountRole.NORMAL
)
editor_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="editor-456", role=TenantAccountRole.EDITOR
)
# All team members should have access
self._assert_permission_check_passes(dataset, normal_user)
self._assert_permission_check_passes(dataset, editor_user)
# ==================== PARTIAL_TEAM Permission Tests ====================
def test_partial_team_permission_creator_can_access(self, mock_dataset_service_dependencies):
"""Test PARTIAL_TEAM permission allows creator to access without database query."""
# Create dataset with PARTIAL_TEAM permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
created_by="creator-456", permission=DatasetPermissionEnum.PARTIAL_TEAM
)
# Create creator user
creator_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="creator-456", role=TenantAccountRole.EDITOR
)
# Creator should have access without database query
self._assert_permission_check_passes(dataset, creator_user)
self._assert_database_query_not_called(mock_dataset_service_dependencies["db_session"])
def test_partial_team_permission_with_explicit_permission(self, mock_dataset_service_dependencies):
"""Test PARTIAL_TEAM permission allows users with explicit permission records."""
# Create dataset with PARTIAL_TEAM permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(permission=DatasetPermissionEnum.PARTIAL_TEAM)
# Create normal user (not the creator)
normal_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="normal-789", role=TenantAccountRole.NORMAL
)
# Mock database query to return a permission record # Mock database query to return a permission record
mock_permission = Mock(spec=DatasetPermission) mock_permission = DatasetPermissionTestDataFactory.create_dataset_permission_mock(
mock_session.query().filter_by().first.return_value = mock_permission dataset_id=dataset.id, account_id=normal_user.id
)
mock_dataset_service_dependencies["db_session"].query().filter_by().first.return_value = mock_permission
# Should not raise any exception # User with explicit permission should have access
DatasetService.check_dataset_permission(self.dataset, self.normal_user) self._assert_permission_check_passes(dataset, normal_user)
self._assert_database_query_called(mock_dataset_service_dependencies["db_session"], dataset.id, normal_user.id)
# Verify database was queried correctly def test_partial_team_permission_without_explicit_permission(self, mock_dataset_service_dependencies):
mock_session.query().filter_by.assert_called_with(dataset_id=self.dataset.id, account_id=self.normal_user.id) """Test PARTIAL_TEAM permission denies users without explicit permission records."""
# Create dataset with PARTIAL_TEAM permission
dataset = DatasetPermissionTestDataFactory.create_dataset_mock(permission=DatasetPermissionEnum.PARTIAL_TEAM)
@patch("services.dataset_service.db.session") # Create normal user (not the creator)
def test_partial_team_permission_without_explicit_permission(self, mock_session): normal_user = DatasetPermissionTestDataFactory.create_user_mock(
"""Test PARTIAL_TEAM permission denies users without explicit permission""" user_id="normal-789", role=TenantAccountRole.NORMAL
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM )
# Mock database query to return None (no permission record) # Mock database query to return None (no permission record)
mock_session.query().filter_by().first.return_value = None mock_dataset_service_dependencies["db_session"].query().filter_by().first.return_value = None
with pytest.raises(NoPermissionError, match="You do not have permission to access this dataset."): # User without explicit permission should be denied access
DatasetService.check_dataset_permission(self.dataset, self.normal_user) self._assert_permission_check_fails(dataset, normal_user)
self._assert_database_query_called(mock_dataset_service_dependencies["db_session"], dataset.id, normal_user.id)
# Verify database was queried correctly def test_partial_team_permission_non_creator_without_permission_fails(self, mock_dataset_service_dependencies):
mock_session.query().filter_by.assert_called_with(dataset_id=self.dataset.id, account_id=self.normal_user.id) """Test that non-creators without explicit permission are denied access to PARTIAL_TEAM datasets."""
# Create dataset with PARTIAL_TEAM permission
@patch("services.dataset_service.db.session") dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
def test_partial_team_permission_non_creator_without_permission_fails(self, mock_session): created_by="creator-456", permission=DatasetPermissionEnum.PARTIAL_TEAM
"""Test that non-creators without explicit permission are denied access""" )
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM
# Create a different user (not the creator) # Create a different user (not the creator)
other_user = Mock(spec=Account) other_user = DatasetPermissionTestDataFactory.create_user_mock(
other_user.id = "other-user-123" user_id="other-user-123", role=TenantAccountRole.NORMAL
other_user.current_tenant_id = self.tenant_id )
other_user.current_role = TenantAccountRole.NORMAL
# Mock database query to return None (no permission record) # Mock database query to return None (no permission record)
mock_session.query().filter_by().first.return_value = None mock_dataset_service_dependencies["db_session"].query().filter_by().first.return_value = None
with pytest.raises(NoPermissionError, match="You do not have permission to access this dataset."): # Non-creator without explicit permission should be denied access
DatasetService.check_dataset_permission(self.dataset, other_user) self._assert_permission_check_fails(dataset, other_user)
self._assert_database_query_called(mock_dataset_service_dependencies["db_session"], dataset.id, other_user.id)
# ==================== Enum Usage Tests ====================
def test_partial_team_permission_uses_correct_enum(self): def test_partial_team_permission_uses_correct_enum(self):
"""Test that the method correctly uses DatasetPermissionEnum.PARTIAL_TEAM""" """Test that the method correctly uses DatasetPermissionEnum.PARTIAL_TEAM instead of string literals."""
# This test ensures we're using the enum instead of string literals # Create dataset with PARTIAL_TEAM permission using enum
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM dataset = DatasetPermissionTestDataFactory.create_dataset_mock(
created_by="creator-456", permission=DatasetPermissionEnum.PARTIAL_TEAM
# Creator should always have access )
DatasetService.check_dataset_permission(self.dataset, self.creator_user)
# Create creator user
@patch("services.dataset_service.logging") creator_user = DatasetPermissionTestDataFactory.create_user_mock(
@patch("services.dataset_service.db.session") user_id="creator-456", role=TenantAccountRole.EDITOR
def test_permission_denied_logs_debug_message(self, mock_session, mock_logging): )
"""Test that permission denied events are logged"""
self.dataset.permission = DatasetPermissionEnum.PARTIAL_TEAM # Creator should always have access regardless of permission level
mock_session.query().filter_by().first.return_value = None self._assert_permission_check_passes(dataset, creator_user)
with pytest.raises(NoPermissionError): # ==================== Logging Tests ====================
DatasetService.check_dataset_permission(self.dataset, self.normal_user)
def test_permission_denied_logs_debug_message(self, mock_dataset_service_dependencies, mock_logging_dependencies):
# Verify debug message was logged """Test that permission denied events are properly logged for debugging purposes."""
mock_logging.debug.assert_called_with( # Create dataset with PARTIAL_TEAM permission
f"User {self.normal_user.id} does not have permission to access dataset {self.dataset.id}" dataset = DatasetPermissionTestDataFactory.create_dataset_mock(permission=DatasetPermissionEnum.PARTIAL_TEAM)
# Create normal user (not the creator)
normal_user = DatasetPermissionTestDataFactory.create_user_mock(
user_id="normal-789", role=TenantAccountRole.NORMAL
)
# Mock database query to return None (no permission record)
mock_dataset_service_dependencies["db_session"].query().filter_by().first.return_value = None
# Attempt permission check (should fail)
with pytest.raises(NoPermissionError):
DatasetService.check_dataset_permission(dataset, normal_user)
# Verify debug message was logged with correct user and dataset information
mock_logging_dependencies["logging"].debug.assert_called_with(
f"User {normal_user.id} does not have permission to access dataset {dataset.id}"
) )