2443909362
---ci--- project: nova-platform milestone: v1.0 status: complete requirements: covered: [REQ-01,REQ-02,REQ-03,REQ-04,REQ-05,REQ-06,REQ-07,REQ-08,REQ-09,REQ-10,REQ-11,REQ-12,REQ-13,REQ-14,REQ-15,REQ-16,REQ-17,REQ-18,REQ-19,REQ-20,REQ-21,REQ-22,REQ-23,REQ-24,REQ-25,REQ-26,REQ-27,REQ-28,REQ-29,REQ-30,REQ-31,REQ-32,REQ-33,REQ-34,REQ-35,REQ-36,REQ-37,REQ-38] partial: [] ---/ci--- v1.0 milestone complete: simplified infrastructure-delivery platform derived from Nova (acdl). 6 phases (P0-P5 + P6 final). 38 REQ-IDs. 38 decisions (D-001..D-038). 76 tests pass. Engine boundary holds. Happy paths green (check-only + CI). 13 L1 + 2 L2 modules. 5 terraform roots. Shell reproducibility. Zero OOS files. Tags: v0.1.0 (P0) → v0.1.1..v0.1.5 (P1..P5) → v0.1.6 (P6 = milestone release on v0.1 patch line).
118 lines
4.6 KiB
Python
118 lines
4.6 KiB
Python
"""Tests for core/contract_resolver.py — REQ-23."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import jsonschema
|
|
import pytest
|
|
|
|
from core.contract_resolver import (
|
|
resolve,
|
|
ModuleNotFoundError,
|
|
VersionNotFoundError,
|
|
)
|
|
|
|
|
|
def _contract(infra=None, env="dev", cid="stsi", name="Test"):
|
|
return {
|
|
"id": cid,
|
|
"name": name,
|
|
"environment": env,
|
|
"infrastructure": infra if infra is not None else [
|
|
{"module": "static-assets", "version": "1.0.0",
|
|
"inputs": {"bucket_name": "test-bucket", "index_document": "index.html"}},
|
|
],
|
|
}
|
|
|
|
|
|
class TestResolveHappyPath:
|
|
def test_resolves_static_assets(self, registry, repo_root):
|
|
contract = _contract()
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
assert stack["contract_id"] == "stsi"
|
|
assert stack["contract_name"] == "Test"
|
|
assert stack["environment"] == "dev"
|
|
assert len(stack["resources"]) == 1
|
|
r = stack["resources"][0]
|
|
assert r["module"] == "static-assets"
|
|
assert r["version"] == "1.0.0"
|
|
assert r["inputs"]["bucket_name"] == "test-bucket"
|
|
|
|
def test_stack_validates_against_schema(self, registry, repo_root, stack_schema):
|
|
contract = _contract()
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
jsonschema.validate(stack, stack_schema)
|
|
|
|
def test_no_source_field(self, registry, repo_root):
|
|
contract = _contract()
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
assert "source" not in stack["resources"][0]
|
|
|
|
|
|
class TestResolveInterpolation:
|
|
def test_env_token_expanded(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "static-assets", "version": "1.0.0",
|
|
"inputs": {"bucket_name": "${env.environment}-${contract.id}-assets",
|
|
"index_document": "index.html"}},
|
|
])
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
assert stack["resources"][0]["inputs"]["bucket_name"] == "dev-stsi-assets"
|
|
|
|
def test_env_dotted_token(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "static-assets", "version": "1.0.0",
|
|
"inputs": {"bucket_name": "${env.region}-bucket",
|
|
"index_document": "index.html"}},
|
|
])
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
assert stack["resources"][0]["inputs"]["bucket_name"] == "us-east-1-bucket"
|
|
|
|
def test_unresolved_token_raises(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "static-assets", "version": "1.0.0",
|
|
"inputs": {"bucket_name": "${env.nonexistent}-bucket",
|
|
"index_document": "index.html"}},
|
|
])
|
|
with pytest.raises(ValueError, match="unresolved interpolation token"):
|
|
resolve(contract, registry, repo_root / "modules", repo_root=repo_root)
|
|
|
|
|
|
class TestResolveVersioning:
|
|
def test_version_defaults_to_latest(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "static-assets", "inputs": {"bucket_name": "b",
|
|
"index_document": "index.html"}},
|
|
])
|
|
stack = resolve(contract, registry, repo_root / "modules",
|
|
repo_root=repo_root)
|
|
assert stack["resources"][0]["version"] == "1.0.0"
|
|
|
|
|
|
class TestResolveErrors:
|
|
def test_unknown_module(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "nope", "version": "1.0.0",
|
|
"inputs": {"x": "y"}},
|
|
])
|
|
with pytest.raises(ModuleNotFoundError):
|
|
resolve(contract, registry, repo_root / "modules", repo_root=repo_root)
|
|
|
|
def test_unknown_version(self, registry, repo_root):
|
|
contract = _contract(infra=[
|
|
{"module": "static-assets", "version": "9.9.9",
|
|
"inputs": {"bucket_name": "b", "index_document": "index.html"}},
|
|
])
|
|
with pytest.raises(VersionNotFoundError):
|
|
resolve(contract, registry, repo_root / "modules", repo_root=repo_root)
|
|
|
|
def test_invalid_contract_missing_id(self, registry, repo_root):
|
|
contract = {"name": "Test", "environment": "dev",
|
|
"infrastructure": [{"module": "s3", "inputs": {}}]}
|
|
with pytest.raises(jsonschema.ValidationError):
|
|
resolve(contract, registry, repo_root / "modules", repo_root=repo_root) |