169 lines
6.2 KiB
Python
169 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from govoplan_core.core.modules import ModuleManifest
|
|
from govoplan_core.core.provider_governance import (
|
|
ExternalProviderDeclaration,
|
|
ModuleArchitectureDeclaration,
|
|
ModuleMaturityEvidence,
|
|
ProviderBehaviorDeclaration,
|
|
ProviderObjectDeclaration,
|
|
)
|
|
|
|
|
|
META_ROOT = Path(__file__).resolve().parents[1]
|
|
RELEASE_ROOT = META_ROOT / "tools" / "release"
|
|
if str(RELEASE_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(RELEASE_ROOT))
|
|
|
|
from govoplan_release.catalog_entry_synthesis import ( # noqa: E402
|
|
manifest_catalog_entry,
|
|
validate_initial_entry_closure,
|
|
)
|
|
from govoplan_release.selective_catalog import apply_repo_updates # noqa: E402
|
|
|
|
|
|
class ReleaseCatalogEntrySynthesisTests(unittest.TestCase):
|
|
def test_catalog_entry_preserves_architecture_and_provider_declarations(
|
|
self,
|
|
) -> None:
|
|
provider = ExternalProviderDeclaration(
|
|
id="example.records",
|
|
module_id="example",
|
|
label="Example records",
|
|
maturity="read",
|
|
operations=("read",),
|
|
objects=(
|
|
ProviderObjectDeclaration(
|
|
object_type="record",
|
|
field_groups=("identity", "content"),
|
|
authority_modes=("external_mirror",),
|
|
default_authority_mode="external_mirror",
|
|
),
|
|
),
|
|
behavior=ProviderBehaviorDeclaration(
|
|
freshness="Reports the acquisition timestamp.",
|
|
health="Reports source and parser health.",
|
|
max_read_items=100,
|
|
classifications=("internal",),
|
|
purposes=("release contract test",),
|
|
retention="The owning package retention policy applies.",
|
|
),
|
|
)
|
|
architecture = ModuleArchitectureDeclaration(
|
|
layer="data_reporting_integration",
|
|
kind="integration",
|
|
maturity="vertical_slice",
|
|
evidence=(
|
|
ModuleMaturityEvidence(
|
|
kind="test",
|
|
reference="tests/test_release_catalog_entry_synthesis.py",
|
|
summary="Proves catalog metadata preservation.",
|
|
),
|
|
ModuleMaturityEvidence(
|
|
kind="documentation",
|
|
reference="docs/INSTITUTIONAL_GOVERNANCE_TARGET_ARCHITECTURE.md",
|
|
summary="Defines the provider declaration contract.",
|
|
),
|
|
),
|
|
known_limits=("Test-only provider.",),
|
|
supported_authority_modes=("external_mirror",),
|
|
owned_concepts=("example transport",),
|
|
target_tested_providers=(provider.id,),
|
|
)
|
|
|
|
entry = manifest_catalog_entry(
|
|
manifest=ModuleManifest(
|
|
id="example",
|
|
name="Example",
|
|
version="1.2.3",
|
|
architecture=architecture,
|
|
external_providers=(provider,),
|
|
),
|
|
repo="govoplan-example",
|
|
package="govoplan-example",
|
|
version="1.2.3",
|
|
description=None,
|
|
root=META_ROOT,
|
|
repository_base="git+ssh://git@git.add-ideas.de/GovOPlaN",
|
|
)
|
|
|
|
self.assertEqual("vertical_slice", entry["architecture"]["maturity"])
|
|
self.assertEqual(
|
|
"external_mirror",
|
|
entry["external_providers"][0]["objects"][0][
|
|
"default_authority_mode"
|
|
],
|
|
)
|
|
|
|
def test_selective_update_synthesizes_initial_entries_from_package_manifests(self) -> None:
|
|
payload: dict[str, object] = {
|
|
"core_release": {},
|
|
"release": {},
|
|
"modules": [
|
|
{
|
|
"module_id": "access",
|
|
"version": "0.1.11",
|
|
"python_package": "govoplan-access",
|
|
"python_ref": "govoplan-access @ git+ssh://git@git.add-ideas.de/GovOPlaN/govoplan-access.git@v0.1.11",
|
|
}
|
|
],
|
|
}
|
|
|
|
changes = apply_repo_updates(
|
|
payload,
|
|
repo_versions={
|
|
"govoplan-addresses": "0.1.9",
|
|
"govoplan-poll": "0.1.11",
|
|
"govoplan-scheduling": "0.1.11",
|
|
},
|
|
repo_contracts={},
|
|
repository_base="git+ssh://git@git.add-ideas.de/GovOPlaN",
|
|
workspace=META_ROOT.parent,
|
|
)
|
|
|
|
modules = {
|
|
item["module_id"]: item
|
|
for item in payload["modules"] # type: ignore[index]
|
|
}
|
|
self.assertEqual({"access", "addresses", "poll", "scheduling"}, set(modules))
|
|
self.assertEqual("@govoplan/addresses-webui", modules["addresses"]["webui_package"])
|
|
self.assertIn(
|
|
{"name": "addresses.people_search", "version": "0.1.0"},
|
|
modules["addresses"]["provides_interfaces"],
|
|
)
|
|
self.assertEqual("govoplan-poll", modules["poll"]["python_package"])
|
|
self.assertEqual(["poll"], modules["scheduling"]["dependencies"])
|
|
self.assertEqual("@govoplan/scheduling-webui", modules["scheduling"]["webui_package"])
|
|
self.assertEqual("requires_review", modules["scheduling"]["migration_safety"])
|
|
self.assertTrue(
|
|
any(
|
|
item["name"] == "poll.governed_participation" and item["optional"] is False
|
|
for item in modules["scheduling"]["requires_interfaces"]
|
|
)
|
|
)
|
|
self.assertEqual(
|
|
{"govoplan-addresses", "govoplan-poll", "govoplan-scheduling"},
|
|
{change.repo for change in changes},
|
|
)
|
|
self.assertEqual({"catalog_entry"}, {change.field for change in changes})
|
|
|
|
def test_initial_required_dependency_must_be_represented(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "requires catalog module 'poll'"):
|
|
validate_initial_entry_closure(
|
|
catalog_modules=[
|
|
{
|
|
"module_id": "scheduling",
|
|
"dependencies": ["poll"],
|
|
}
|
|
],
|
|
initial_module_ids={"scheduling"},
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|