Files
artifact-store/tests
tegwick 28ec2922d3 WP-0001-T003: storage adapter SPI and local filesystem backend
src/artifactstore/storage/:
- spi.py: StorageBackend Protocol (backend_id, put, get, head, delete,
  health) and result dataclasses (StorageReceipt, StorageObjectMetadata,
  DeletionResult, BackendStatus). ObjectNotFoundError exception type.
- registry.py: backend lookup by string ID (register/get/list_backends/
  clear) per ADR-0004.
- backends/local.py: LocalBackend implementation.
  * Object layout <root>/<algorithm>/<hex[0:2]>/<hex[2:4]>/<hex>.
  * Atomic writes: tmpfile + fsync + rename (idempotent re-puts drain the
    stream without rewriting).
  * Defence in depth: resolves the final path and asserts it remains under
    the configured root.
  * Range reads honour HTTP-style inclusive (start, end) tuples.
  * health() returns disk usage via shutil.disk_usage and surfaces an
    unhealthy status when the root has disappeared.
  * delete() cleans up emptied shard directories opportunistically.

tests/unit/test_storage_local.py (14 cases): put/get round-trip; object
key layout matches blueprint; head returns metadata; head/get missing
raise ObjectNotFoundError; put is idempotent; delete returns True then
False; range read returns subrange; range read rejects invalid range;
health reports disk usage; health reports unhealthy when root vanished;
ContentAddress validation blocks path-traversal-flavoured inputs;
registry register/get/list/clear round-trip; idempotent re-put leaves
bytes intact.

Gates: ruff clean, mypy --strict clean on 41 files, 59 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 02:01:25 +02:00
..