""" Unit tests for SQLAlchemy models. Tests cover: - Model instantiation and defaults - Property aliases (sha256, format_metadata) - Relationship definitions - Constraint definitions """ import pytest import uuid from datetime import datetime class TestArtifactModel: """Tests for the Artifact model.""" @pytest.mark.unit def test_artifact_sha256_property(self): """Test sha256 property is an alias for id.""" from app.models import Artifact artifact = Artifact( id="a" * 64, size=1024, created_by="test-user", s3_key="fruits/aa/aa/test", ) assert artifact.sha256 == artifact.id assert artifact.sha256 == "a" * 64 @pytest.mark.unit def test_artifact_format_metadata_alias(self): """Test format_metadata is an alias for artifact_metadata.""" from app.models import Artifact test_metadata = {"format": "tarball", "version": "1.0.0"} artifact = Artifact( id="b" * 64, size=2048, created_by="test-user", s3_key="fruits/bb/bb/test", artifact_metadata=test_metadata, ) assert artifact.format_metadata == test_metadata assert artifact.format_metadata == artifact.artifact_metadata @pytest.mark.unit def test_artifact_format_metadata_setter(self): """Test format_metadata setter updates artifact_metadata.""" from app.models import Artifact artifact = Artifact( id="c" * 64, size=512, created_by="test-user", s3_key="fruits/cc/cc/test", ) new_metadata = {"type": "rpm", "arch": "x86_64"} artifact.format_metadata = new_metadata assert artifact.artifact_metadata == new_metadata assert artifact.format_metadata == new_metadata @pytest.mark.unit def test_artifact_default_ref_count(self): """Test artifact ref_count column has default value of 1.""" from app.models import Artifact # Check the column definition has the right default ref_count_col = Artifact.__table__.columns["ref_count"] assert ref_count_col.default is not None assert ref_count_col.default.arg == 1 @pytest.mark.unit def test_artifact_default_metadata_is_dict(self): """Test artifact default metadata is an empty dict.""" from app.models import Artifact artifact = Artifact( id="e" * 64, size=100, created_by="test-user", s3_key="fruits/ee/ee/test", ) # Default might be None until saved, but the column default is dict assert artifact.artifact_metadata is None or isinstance( artifact.artifact_metadata, dict ) class TestProjectModel: """Tests for the Project model.""" @pytest.mark.unit def test_project_default_is_public(self): """Test project is_public column has default value of True.""" from app.models import Project # Check the column definition has the right default is_public_col = Project.__table__.columns["is_public"] assert is_public_col.default is not None assert is_public_col.default.arg is True @pytest.mark.unit def test_project_uuid_generation(self): """Test project generates UUID by default.""" from app.models import Project project = Project( name="uuid-test-project", created_by="test-user", ) # UUID should be set by default function assert project.id is not None or hasattr(Project.id, "default") class TestPackageModel: """Tests for the Package model.""" @pytest.mark.unit def test_package_default_format(self): """Test package format column has default value of 'generic'.""" from app.models import Package # Check the column definition has the right default format_col = Package.__table__.columns["format"] assert format_col.default is not None assert format_col.default.arg == "generic" @pytest.mark.unit def test_package_default_platform(self): """Test package platform column has default value of 'any'.""" from app.models import Package # Check the column definition has the right default platform_col = Package.__table__.columns["platform"] assert platform_col.default is not None assert platform_col.default.arg == "any" class TestTagModel: """Tests for the Tag model.""" @pytest.mark.unit def test_tag_requires_package_id(self): """Test tag requires package_id.""" from app.models import Tag tag = Tag( name="v1.0.0", package_id=uuid.uuid4(), artifact_id="f" * 64, created_by="test-user", ) assert tag.package_id is not None assert tag.artifact_id == "f" * 64 class TestTagHistoryModel: """Tests for the TagHistory model.""" @pytest.mark.unit def test_tag_history_default_change_type(self): """Test tag history change_type column has default value of 'update'.""" from app.models import TagHistory # Check the column definition has the right default change_type_col = TagHistory.__table__.columns["change_type"] assert change_type_col.default is not None assert change_type_col.default.arg == "update" @pytest.mark.unit def test_tag_history_allows_null_old_artifact(self): """Test tag history allows null old_artifact_id (for create events).""" from app.models import TagHistory history = TagHistory( tag_id=uuid.uuid4(), old_artifact_id=None, new_artifact_id="h" * 64, change_type="create", changed_by="test-user", ) assert history.old_artifact_id is None class TestUploadModel: """Tests for the Upload model.""" @pytest.mark.unit def test_upload_default_deduplicated_is_false(self): """Test upload deduplicated column has default value of False.""" from app.models import Upload # Check the column definition has the right default deduplicated_col = Upload.__table__.columns["deduplicated"] assert deduplicated_col.default is not None assert deduplicated_col.default.arg is False @pytest.mark.unit def test_upload_default_checksum_verified_is_true(self): """Test upload checksum_verified column has default value of True.""" from app.models import Upload # Check the column definition has the right default checksum_verified_col = Upload.__table__.columns["checksum_verified"] assert checksum_verified_col.default is not None assert checksum_verified_col.default.arg is True class TestAccessPermissionModel: """Tests for the AccessPermission model.""" @pytest.mark.unit def test_access_permission_levels(self): """Test valid access permission levels.""" from app.models import AccessPermission # This tests the check constraint values valid_levels = ["read", "write", "admin"] for level in valid_levels: permission = AccessPermission( project_id=uuid.uuid4(), user_id="test-user", level=level, ) assert permission.level == level class TestAuditLogModel: """Tests for the AuditLog model.""" @pytest.mark.unit def test_audit_log_required_fields(self): """Test audit log has all required fields.""" from app.models import AuditLog log = AuditLog( action="project.create", resource="/projects/test-project", user_id="test-user", ) assert log.action == "project.create" assert log.resource == "/projects/test-project" assert log.user_id == "test-user" @pytest.mark.unit def test_audit_log_optional_details(self): """Test audit log can have optional details JSON.""" from app.models import AuditLog details = {"old_value": "v1", "new_value": "v2"} log = AuditLog( action="tag.update", resource="/projects/test/packages/pkg/tags/latest", user_id="test-user", details=details, ) assert log.details == details