88 lines
3.4 KiB
Python
88 lines
3.4 KiB
Python
|
|
"""Read API (CANP-WP-0006 T03)."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_returns_stored_packages(seeded: TestClient) -> None:
|
||
|
|
body = seeded.get("/packages").json()
|
||
|
|
assert body["count"] == 2
|
||
|
|
assert {p["id"] for p in body["packages"]} == {
|
||
|
|
"practice/house-style",
|
||
|
|
"practice/pqrst-estimate",
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def test_search_matches_summary_and_tags(seeded: TestClient) -> None:
|
||
|
|
assert seeded.get("/packages", params={"q": "pqrst"}).json()["count"] == 1
|
||
|
|
assert seeded.get("/packages", params={"q": "fragment"}).json()["count"] == 1
|
||
|
|
assert seeded.get("/packages", params={"q": "nothing-matches"}).json()["count"] == 0
|
||
|
|
|
||
|
|
|
||
|
|
def test_versions_of_a_bare_id(seeded: TestClient) -> None:
|
||
|
|
body = seeded.get("/packages/practice/pqrst-estimate").json()
|
||
|
|
assert body["id"] == "practice/pqrst-estimate"
|
||
|
|
assert [v["version"] for v in body["versions"]] == ["1.0.0"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_manifest_by_qualified_reference(seeded: TestClient) -> None:
|
||
|
|
"""The API speaks the format's own <registry>:<id>@<version> syntax."""
|
||
|
|
body = seeded.get("/packages/local:practice/pqrst-estimate@1.0.0").json()
|
||
|
|
assert body["reference"] == "local:practice/pqrst-estimate@1.0.0"
|
||
|
|
assert "PQRST" in body["manifest"]
|
||
|
|
assert body["content_digest"].startswith("sha256:")
|
||
|
|
|
||
|
|
|
||
|
|
def test_unknown_package_is_404(seeded: TestClient) -> None:
|
||
|
|
assert seeded.get("/packages/nope/missing").status_code == 404
|
||
|
|
|
||
|
|
|
||
|
|
def test_unknown_version_is_404(seeded: TestClient) -> None:
|
||
|
|
assert seeded.get("/packages/practice/house-style@9.9.9").status_code == 404
|
||
|
|
|
||
|
|
|
||
|
|
def test_ambiguous_bare_id_is_409_not_a_guess(two_registries: TestClient) -> None:
|
||
|
|
"""§ 3.2: report the candidates, never choose for the caller."""
|
||
|
|
response = two_registries.get("/packages/practice/house-style")
|
||
|
|
assert response.status_code == 409
|
||
|
|
detail = response.json()["detail"]
|
||
|
|
assert "more than one registry" in detail
|
||
|
|
assert "house:practice/house-style" in detail
|
||
|
|
assert "local:practice/house-style" in detail
|
||
|
|
|
||
|
|
|
||
|
|
def test_qualifying_resolves_the_ambiguity(two_registries: TestClient) -> None:
|
||
|
|
body = two_registries.get("/packages/house:practice/house-style").json()
|
||
|
|
assert body["registry"] == "house"
|
||
|
|
|
||
|
|
|
||
|
|
def test_archive_returns_the_packaged_files(seeded: TestClient) -> None:
|
||
|
|
body = seeded.get("/archives/practice/pqrst-estimate@1.0.0").json()
|
||
|
|
assert set(body["files"]) == {
|
||
|
|
"LICENSE",
|
||
|
|
"README.md",
|
||
|
|
"evals/canonical-fidelity.yaml",
|
||
|
|
"examples/basic.yaml",
|
||
|
|
"examples/with-rationale.yaml",
|
||
|
|
"prompt.md",
|
||
|
|
"prompt.yaml",
|
||
|
|
}
|
||
|
|
assert "PQRST-Estimate" in body["files"]["prompt.md"]["text"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_archive_excludes_non_package_files(seeded: TestClient) -> None:
|
||
|
|
"""§ 2: only reserved paths and manifest-referenced files are stored."""
|
||
|
|
files = seeded.get("/archives/practice/pqrst-estimate@1.0.0").json()["files"]
|
||
|
|
assert not any(path.startswith(".") for path in files)
|
||
|
|
|
||
|
|
|
||
|
|
def test_index_records_arrival(seeded: TestClient) -> None:
|
||
|
|
body = seeded.get("/index").json()
|
||
|
|
assert body["count"] == 2
|
||
|
|
entry = next(e for e in body["entries"] if e["id"] == "practice/pqrst-estimate")
|
||
|
|
assert entry["method"] == "publish"
|
||
|
|
assert entry["source"] == "examples/pqrst-estimate"
|
||
|
|
assert entry["declared_source"] == "~/pqrst-practice/PqrstPrompt.md"
|
||
|
|
assert entry["included_at"] is not None
|