58 lines
2.3 KiB
Python
58 lines
2.3 KiB
Python
"""Real restored audit pagination must preserve numeric sequence ordering."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from modelforge_api.services.audit import AuditWriter
|
|
from modelforge_api.services.recovery import RecoveryService
|
|
from modelforge_api.services.recovery_postgres import parse_target
|
|
from modelforge_api.settings import Settings
|
|
from tests.test_managed_identities_postgres import (
|
|
IdentityDatabase,
|
|
ManagedPostgresTools,
|
|
identity_database,
|
|
)
|
|
|
|
__all__ = ["identity_database"]
|
|
|
|
|
|
def test_restored_audit_numeric_order_crosses_page_boundary(
|
|
identity_database: IdentityDatabase, tmp_path: Path,
|
|
) -> None:
|
|
database = identity_database
|
|
importlib.import_module("alembic.command").upgrade(database.migration(), "head")
|
|
event_count = 512 # Production iteration reads 500 rows per page.
|
|
with Session(database.runtime) as session:
|
|
writer = AuditWriter(session, "operator", "audit-pagination-qualification")
|
|
expected_ids = []
|
|
for ordinal in range(1, event_count + 1):
|
|
event = writer.write(
|
|
"qualification.audit_pagination", "recovery", None,
|
|
{"ordinal": ordinal, "source": "isolated regression fixture"},
|
|
)
|
|
assert event.sequence == ordinal
|
|
expected_ids.append(str(event.id))
|
|
session.commit()
|
|
|
|
archive = tmp_path / "audit-pagination.dump"
|
|
database.archive(archive)
|
|
database.archive(archive, restore=True)
|
|
target = parse_target(database.restored_owner.render_as_string(hide_password=False))
|
|
with Session(database.runtime) as session:
|
|
recovery = RecoveryService(session, Settings(_env_file=None, env="test"))
|
|
recovery.engine = ManagedPostgresTools(
|
|
base_environment=dict(os.environ), timeout_seconds=60,
|
|
)
|
|
events = list(recovery._restored_audit_events(target))
|
|
assert [event.sequence for event in events] == list(range(1, event_count + 1))
|
|
assert [event.id for event in events] == expected_ids
|
|
assert len({event.id for event in events}) == event_count
|
|
checkpoint = recovery._verify_restored_audit_chain(target)
|
|
assert checkpoint.event_count == checkpoint.last_sequence == event_count
|
|
assert checkpoint.last_event_hash == events[-1].event_hash
|