Files
turnstone/tests/test_skill_resources_storage.py
Patrick Buckley ab1a71c86c feat: add PostgreSQL CI integration tests (#156)
* feat: add PostgreSQL CI integration tests

Add --storage-backend pytest option and shared storage_backend fixture
in conftest.py that creates SQLiteBackend or PostgreSQLBackend based
on the flag. Migrate 13 storage test files to use shared fixture
instead of local SQLiteBackend fixtures.

Add test-postgres CI job with PostgreSQL 17 service container that
runs the full test suite against real PostgreSQL.

* fix: use TRUNCATE CASCADE for PG cleanup, wrap in try/finally

TRUNCATE is faster than per-table DELETE and resets autoincrement
sequences. try/except ensures reset_storage() always runs even if
cleanup fails due to a corrupted connection from a failing test.

* fix: document _engine coupling in PG cleanup comment
2026-03-23 11:11:40 -07:00

57 lines
2.5 KiB
Python

"""Tests for skill resource storage operations."""
from __future__ import annotations
import uuid
class TestDeleteSkillResourceByPath:
def test_delete_existing(self, storage):
skill_id = uuid.uuid4().hex
rid = uuid.uuid4().hex
storage.create_skill_resource(rid, skill_id, "scripts/a.sh", "#!/bin/bash")
assert storage.delete_skill_resource_by_path(skill_id, "scripts/a.sh") is True
assert storage.get_skill_resource(skill_id, "scripts/a.sh") is None
def test_delete_not_found(self, storage):
assert storage.delete_skill_resource_by_path("nonexistent", "scripts/a.sh") is False
def test_delete_wrong_path(self, storage):
skill_id = uuid.uuid4().hex
rid = uuid.uuid4().hex
storage.create_skill_resource(rid, skill_id, "scripts/a.sh", "content")
assert storage.delete_skill_resource_by_path(skill_id, "scripts/b.sh") is False
# Original still exists
assert storage.get_skill_resource(skill_id, "scripts/a.sh") is not None
def test_delete_only_target(self, storage):
"""Deleting one resource doesn't affect others for the same skill."""
skill_id = uuid.uuid4().hex
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "scripts/a.sh", "a")
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "scripts/b.sh", "b")
assert storage.delete_skill_resource_by_path(skill_id, "scripts/a.sh") is True
assert storage.get_skill_resource(skill_id, "scripts/b.sh") is not None
assert len(storage.list_skill_resources(skill_id)) == 1
class TestListSkillResources:
def test_ordering(self, storage):
skill_id = uuid.uuid4().hex
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "scripts/z.sh", "z")
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "assets/a.txt", "a")
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "references/m.md", "m")
rows = storage.list_skill_resources(skill_id)
paths = [r["path"] for r in rows]
assert paths == sorted(paths)
def test_empty(self, storage):
assert storage.list_skill_resources("nonexistent") == []
def test_size_from_content(self, storage):
skill_id = uuid.uuid4().hex
content = "x" * 500
storage.create_skill_resource(uuid.uuid4().hex, skill_id, "scripts/a.sh", content)
rows = storage.list_skill_resources(skill_id)
assert len(rows) == 1
assert len(rows[0]["content"]) == 500