Metadata database tracks all uploads with project, package, tag, and timestamp queryable via API
This commit is contained in:
271
backend/tests/unit/test_models.py
Normal file
271
backend/tests/unit/test_models.py
Normal file
@@ -0,0 +1,271 @@
|
||||
"""
|
||||
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
|
||||
Reference in New Issue
Block a user