svcforge: reference implementation
ci / lint (push) Successful in 1m19s
ci / unit (push) Failing after 1m2s
ci / integration (push) Has been skipped
ci / types (push) Successful in 1m37s
ci / security (push) Failing after 38s
ci / dockerfile (push) Successful in 14s
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
ci / lint (push) Successful in 1m19s
ci / unit (push) Failing after 1m2s
ci / integration (push) Has been skipped
ci / types (push) Successful in 1m37s
ci / security (push) Failing after 38s
ci / dockerfile (push) Successful in 14s
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped
Complete working build of the system learn-python/ teaches. 164 tests, mypy --strict clean, domain coverage 99%.
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
"""Unit tests for catalog loading and validation."""
|
||||
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from svcforge_core.domain.catalog import CatalogError, load_catalog
|
||||
from svcforge_core.domain.models import CatalogEntry
|
||||
|
||||
VALID_YAML = textwrap.dedent("""
|
||||
services:
|
||||
redis:
|
||||
chart: bitnamilegacy/redis
|
||||
chart_version: 20.6.2
|
||||
sizes:
|
||||
small:
|
||||
replicas: 1
|
||||
resources:
|
||||
requests: {cpu: 100m, memory: 256Mi}
|
||||
medium:
|
||||
replicas: 3
|
||||
resources:
|
||||
requests: {cpu: 500m, memory: 1Gi}
|
||||
postgres:
|
||||
chart: bitnamilegacy/postgresql
|
||||
chart_version: 16.4.5
|
||||
sizes:
|
||||
small:
|
||||
replicas: 1
|
||||
resources:
|
||||
requests: {cpu: 250m, memory: 512Mi}
|
||||
""")
|
||||
|
||||
MISSING_CHART_VERSION_YAML = textwrap.dedent("""
|
||||
services:
|
||||
redis:
|
||||
chart: bitnamilegacy/redis
|
||||
sizes:
|
||||
small:
|
||||
replicas: 1
|
||||
resources: {}
|
||||
""")
|
||||
|
||||
ZERO_REPLICAS_YAML = textwrap.dedent("""
|
||||
services:
|
||||
redis:
|
||||
chart: bitnamilegacy/redis
|
||||
chart_version: 20.6.2
|
||||
sizes:
|
||||
small:
|
||||
replicas: 0
|
||||
resources: {}
|
||||
""")
|
||||
|
||||
|
||||
def _write(tmp_path: Path, body: str) -> Path:
|
||||
path = tmp_path / "catalog.yaml"
|
||||
path.write_text(body)
|
||||
return path
|
||||
|
||||
|
||||
def test_valid_yaml_loads_to_catalog_entries(tmp_path: Path) -> None:
|
||||
catalog = load_catalog(_write(tmp_path, VALID_YAML))
|
||||
|
||||
assert set(catalog) == {"redis", "postgres"}
|
||||
assert all(isinstance(entry, CatalogEntry) for entry in catalog.values())
|
||||
redis = catalog["redis"]
|
||||
assert redis.service_type == "redis"
|
||||
assert redis.chart_version == "20.6.2"
|
||||
assert set(redis.sizes) == {"small", "medium"}
|
||||
assert redis.sizes["medium"].replicas == 3
|
||||
|
||||
|
||||
def test_missing_chart_version_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError) as excinfo:
|
||||
load_catalog(_write(tmp_path, MISSING_CHART_VERSION_YAML))
|
||||
|
||||
assert excinfo.value.key == "redis"
|
||||
assert "redis" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_zero_replicas_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError) as excinfo:
|
||||
load_catalog(_write(tmp_path, ZERO_REPLICAS_YAML))
|
||||
|
||||
assert excinfo.value.key == "redis"
|
||||
|
||||
|
||||
def test_missing_file_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError, match="cannot read catalog"):
|
||||
load_catalog(tmp_path / "nope.yaml")
|
||||
|
||||
|
||||
def test_unparseable_yaml_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError, match="not valid YAML"):
|
||||
load_catalog(_write(tmp_path, "services: [unclosed\n"))
|
||||
|
||||
|
||||
def test_scalar_root_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError, match="must be a mapping"):
|
||||
load_catalog(_write(tmp_path, "just-a-string\n"))
|
||||
|
||||
|
||||
def test_non_mapping_services_raises_catalog_error(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError, match="'services' must be a mapping"):
|
||||
load_catalog(_write(tmp_path, "services:\n - redis\n"))
|
||||
|
||||
|
||||
def test_non_mapping_entry_raises_catalog_error_naming_the_key(tmp_path: Path) -> None:
|
||||
with pytest.raises(CatalogError) as excinfo:
|
||||
load_catalog(_write(tmp_path, "services:\n redis: just-a-string\n"))
|
||||
|
||||
assert excinfo.value.key == "redis"
|
||||
assert "must be a mapping" in str(excinfo.value)
|
||||
|
||||
|
||||
def test_non_string_field_key_raises_catalog_error_naming_the_key(tmp_path: Path) -> None:
|
||||
"""A non-string YAML key inside an entry breaks `**body`; it must surface as CatalogError."""
|
||||
body = textwrap.dedent("""
|
||||
services:
|
||||
redis:
|
||||
1: oops
|
||||
chart: bitnamilegacy/redis
|
||||
chart_version: 20.6.2
|
||||
sizes: {}
|
||||
""")
|
||||
with pytest.raises(CatalogError) as excinfo:
|
||||
load_catalog(_write(tmp_path, body))
|
||||
|
||||
assert excinfo.value.key == "redis"
|
||||
|
||||
|
||||
def test_bare_mapping_without_services_key_is_accepted(tmp_path: Path) -> None:
|
||||
"""The top-level `services:` wrapper is optional; a bare service_type mapping also loads."""
|
||||
body = textwrap.dedent("""
|
||||
redis:
|
||||
chart: bitnamilegacy/redis
|
||||
chart_version: 20.6.2
|
||||
sizes:
|
||||
small:
|
||||
replicas: 1
|
||||
resources: {}
|
||||
""")
|
||||
catalog = load_catalog(_write(tmp_path, body))
|
||||
|
||||
assert set(catalog) == {"redis"}
|
||||
|
||||
|
||||
def test_repo_catalog_yaml_is_valid() -> None:
|
||||
catalog = load_catalog(Path(__file__).parents[2] / "catalog.yaml")
|
||||
|
||||
assert set(catalog) == {"elasticsearch", "redis", "postgres"}
|
||||
for entry in catalog.values():
|
||||
assert set(entry.sizes) == {"small", "medium"}
|
||||
Reference in New Issue
Block a user