This commit is contained in:
@@ -184,6 +184,12 @@ class DatabaseMigrationTests(unittest.TestCase):
|
||||
system_settings_count = connection.execute(
|
||||
text("SELECT COUNT(*) FROM core_system_settings WHERE id = 'global'"),
|
||||
).scalar_one()
|
||||
default_locale = connection.execute(
|
||||
text(
|
||||
"SELECT default_locale FROM core_system_settings "
|
||||
"WHERE id = 'global'"
|
||||
),
|
||||
).scalar_one()
|
||||
current = database_migration_heads(connection)
|
||||
|
||||
self.assertEqual(
|
||||
@@ -204,6 +210,7 @@ class DatabaseMigrationTests(unittest.TestCase):
|
||||
self.assertIn("file_assets", tables)
|
||||
self.assertIn("mail_server_profiles", tables)
|
||||
self.assertEqual(system_settings_count, 1)
|
||||
self.assertEqual(default_locale, "de")
|
||||
self.assertEqual(
|
||||
role_flags,
|
||||
{"system_owner": True, "system_admin": False, "system_auditor": False},
|
||||
@@ -211,6 +218,42 @@ class DatabaseMigrationTests(unittest.TestCase):
|
||||
finally:
|
||||
engine.dispose()
|
||||
|
||||
def test_german_reference_migration_preserves_explicit_english(self) -> None:
|
||||
with tempfile.TemporaryDirectory(prefix="govoplan-locale-migration-test-") as directory:
|
||||
database = Path(directory) / "locale.db"
|
||||
url = f"sqlite:///{database}"
|
||||
config = alembic_config(database_url=url, enabled_modules=())
|
||||
command.upgrade(config, "f25c9d3e7a01")
|
||||
|
||||
engine = create_engine(url)
|
||||
try:
|
||||
with engine.begin() as connection:
|
||||
connection.execute(
|
||||
text(
|
||||
"UPDATE core_system_settings "
|
||||
"SET default_locale = 'en', "
|
||||
"updated_at = '2040-01-01 00:00:00' "
|
||||
"WHERE id = 'global'"
|
||||
)
|
||||
)
|
||||
finally:
|
||||
engine.dispose()
|
||||
|
||||
command.upgrade(config, "heads")
|
||||
|
||||
engine = create_engine(url)
|
||||
try:
|
||||
with engine.connect() as connection:
|
||||
default_locale = connection.execute(
|
||||
text(
|
||||
"SELECT default_locale FROM core_system_settings "
|
||||
"WHERE id = 'global'"
|
||||
)
|
||||
).scalar_one()
|
||||
self.assertEqual(default_locale, "en")
|
||||
finally:
|
||||
engine.dispose()
|
||||
|
||||
def test_default_module_baselines_apply_to_fresh_database(self) -> None:
|
||||
with tempfile.TemporaryDirectory(prefix="govoplan-default-baseline-test-") as directory:
|
||||
database = Path(directory) / "default.db"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.i18n import (
|
||||
REFERENCE_LANGUAGE_CODE,
|
||||
normalize_enabled_language_codes,
|
||||
normalize_language_packages,
|
||||
preferred_language_code,
|
||||
system_i18n_payload,
|
||||
)
|
||||
|
||||
|
||||
class I18nReferenceLanguageTests(unittest.TestCase):
|
||||
def test_german_is_the_new_installation_reference_default(self) -> None:
|
||||
packages = normalize_language_packages()
|
||||
|
||||
self.assertEqual("de", REFERENCE_LANGUAGE_CODE)
|
||||
self.assertEqual(["de", "en"], [item["code"] for item in packages])
|
||||
self.assertEqual(
|
||||
["de", "en"],
|
||||
normalize_enabled_language_codes(None, packages),
|
||||
)
|
||||
self.assertEqual("de", system_i18n_payload(None)["default_language"])
|
||||
self.assertEqual("de", preferred_language_code(None, ()))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,68 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.information_governance import (
|
||||
InformationGovernanceDeclarationError,
|
||||
InformationGovernanceDimension,
|
||||
ModuleInformationGovernance,
|
||||
information_governance_from_mapping,
|
||||
information_governance_maturity_issues,
|
||||
)
|
||||
|
||||
|
||||
class InformationGovernanceTests(unittest.TestCase):
|
||||
def test_default_applies_contract_without_claiming_enforcement(self) -> None:
|
||||
declaration = ModuleInformationGovernance()
|
||||
|
||||
self.assertTrue(declaration.current_authorization_for_historical_reads)
|
||||
self.assertEqual(
|
||||
{"contract_only"},
|
||||
{item.adoption for item in declaration.dimensions.values()},
|
||||
)
|
||||
self.assertEqual("1", declaration.to_dict()["contract_version"])
|
||||
|
||||
def test_enforced_adoption_requires_evidence(self) -> None:
|
||||
with self.assertRaisesRegex(
|
||||
InformationGovernanceDeclarationError,
|
||||
"requires evidence",
|
||||
):
|
||||
InformationGovernanceDimension(adoption="enforced")
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
InformationGovernanceDeclarationError,
|
||||
"covered object types",
|
||||
):
|
||||
InformationGovernanceDimension(
|
||||
adoption="enforced",
|
||||
evidence=("tests/test_information_governance.py",),
|
||||
)
|
||||
|
||||
def test_catalog_shape_round_trips(self) -> None:
|
||||
declaration = ModuleInformationGovernance()
|
||||
|
||||
self.assertEqual(
|
||||
declaration,
|
||||
information_governance_from_mapping(declaration.to_dict()),
|
||||
)
|
||||
|
||||
def test_reference_ready_rejects_unproved_dimensions(self) -> None:
|
||||
issues = information_governance_maturity_issues(
|
||||
ModuleInformationGovernance(),
|
||||
maturity="reference_ready",
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(issues))
|
||||
self.assertIn("temporal_browsing", issues[0])
|
||||
self.assertIn("purpose_aware_access", issues[0])
|
||||
self.assertEqual(
|
||||
(),
|
||||
information_governance_maturity_issues(
|
||||
ModuleInformationGovernance(),
|
||||
maturity="vertical_slice",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -106,6 +106,7 @@ from govoplan_core.core.module_package_catalog import (
|
||||
sign_module_package_catalog,
|
||||
validate_module_package_catalog,
|
||||
)
|
||||
from govoplan_core.core.information_governance import ModuleInformationGovernance
|
||||
from govoplan_core.core.modules import DocumentationTopic, FrontendModule, FrontendRoute, MigrationRetirementPlan, ModuleCompatibility, ModuleMigrationTask, ModuleMigrationTaskContext, ModuleMigrationTaskResult, ModuleUninstallGuardResult, PublicFrontendRoute
|
||||
from govoplan_core.core.module_guards import drop_table_retirement_provider
|
||||
from govoplan_core.core.modules import MigrationSpec, ModuleInterfaceProvider, ModuleInterfaceRequirement, ModuleManifest, PermissionDefinition, RoleTemplate
|
||||
@@ -119,7 +120,8 @@ from govoplan_core.security.module_permissions import scopes_grant_compatible
|
||||
from govoplan_core.security.permissions import scope_grants
|
||||
from govoplan_core.server.app import create_app
|
||||
from govoplan_core.server.config import GovoplanServerConfig
|
||||
from govoplan_core.server.platform import create_platform_router
|
||||
from govoplan_core.server.platform import _documentation_help_contexts, create_platform_router
|
||||
from govoplan_core.core.views import ViewSurface
|
||||
from govoplan_core.server.registry import available_module_manifests, build_platform_registry
|
||||
from govoplan_core.server.route_validation import RouteCollisionError
|
||||
from govoplan_core.tenancy.scope import Tenant, create_scope_tables
|
||||
@@ -597,6 +599,70 @@ class ModuleSystemTests(unittest.TestCase):
|
||||
[item["path"] for item in public_module["frontend"]["public_routes"]],
|
||||
)
|
||||
|
||||
def test_declared_surfaces_receive_static_documentation_fallbacks(self) -> None:
|
||||
manifest = ModuleManifest(
|
||||
id="example",
|
||||
name="Example",
|
||||
version="test",
|
||||
documentation=(
|
||||
DocumentationTopic(
|
||||
id="example.user",
|
||||
title="Example user guide",
|
||||
summary="User guide.",
|
||||
documentation_types=("user",),
|
||||
order=20,
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="example.admin",
|
||||
title="Example administrator guide",
|
||||
summary="Administrator guide.",
|
||||
documentation_types=("admin",),
|
||||
order=10,
|
||||
),
|
||||
),
|
||||
frontend=FrontendModule(
|
||||
module_id="example",
|
||||
routes=(
|
||||
FrontendRoute(
|
||||
path="/example",
|
||||
component="ExamplePage",
|
||||
surface_id="example.workspace",
|
||||
),
|
||||
),
|
||||
settings_routes=(
|
||||
FrontendRoute(
|
||||
path="/admin?section=example",
|
||||
component="ExampleAdmin",
|
||||
surface_id="example.admin.settings",
|
||||
),
|
||||
),
|
||||
view_surfaces=(
|
||||
ViewSurface(
|
||||
id="example.workspace",
|
||||
module_id="example",
|
||||
kind="route",
|
||||
label="Example workspace",
|
||||
),
|
||||
ViewSurface(
|
||||
id="example.admin.settings",
|
||||
module_id="example",
|
||||
kind="section",
|
||||
label="Example settings",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
contexts = {
|
||||
item["id"]: item for item in _documentation_help_contexts(manifest)
|
||||
}
|
||||
|
||||
self.assertEqual("example.user", contexts["example.workspace"]["topic_id"])
|
||||
self.assertEqual(
|
||||
"example.admin",
|
||||
contexts["example.admin.settings"]["topic_id"],
|
||||
)
|
||||
|
||||
def test_registry_rejects_duplicate_public_frontend_routes(self) -> None:
|
||||
registry = PlatformRegistry()
|
||||
for module_id in ("first", "second"):
|
||||
@@ -3300,6 +3366,7 @@ finally:
|
||||
"recovery_notes": "Restore rehearsal completed for the release candidate.",
|
||||
"provides_interfaces": [{"name": "files.spaces", "version": "1.2.0"}],
|
||||
"requires_interfaces": [{"name": "access.directory", "version_min": "1.0.0", "optional": True}],
|
||||
"information_governance": ModuleInformationGovernance().to_dict(),
|
||||
"artifact_integrity": {
|
||||
"python": {
|
||||
"ref": "govoplan-files==0.1.4",
|
||||
@@ -3345,6 +3412,12 @@ finally:
|
||||
[{"name": "access.directory", "optional": True, "version_min": "1.0.0"}],
|
||||
catalog[0]["requires_interfaces"],
|
||||
)
|
||||
self.assertEqual(
|
||||
"contract_only",
|
||||
catalog[0]["information_governance"]["dimensions"]["retention"][
|
||||
"adoption"
|
||||
],
|
||||
)
|
||||
self.assertEqual("0" * 64, catalog[0]["artifact_integrity"]["python"]["sha256"])
|
||||
|
||||
validation = validate_module_package_catalog(catalog_path)
|
||||
|
||||
@@ -40,6 +40,22 @@ class _Consumer:
|
||||
self.added.append(queue)
|
||||
|
||||
|
||||
def test_api_runtime_identity_uses_the_installed_distribution_version(
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
from govoplan_core.server import default_config
|
||||
|
||||
monkeypatch.setattr(
|
||||
default_config,
|
||||
"version",
|
||||
lambda distribution: "0.1.15"
|
||||
if distribution == "govoplan-core"
|
||||
else "unexpected",
|
||||
)
|
||||
|
||||
assert default_config._core_distribution_version() == "0.1.15"
|
||||
|
||||
|
||||
def test_api_runtime_agent_fails_readiness_on_heartbeat_error() -> None:
|
||||
agent = RuntimeNodeAgent(
|
||||
settings=SimpleNamespace(
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from govoplan_core.commands.wait_for_database import main
|
||||
from govoplan_core.db.migrations import configured_migration_heads
|
||||
|
||||
|
||||
class WaitForDatabaseTests(unittest.TestCase):
|
||||
def test_configured_heads_resolve_cross_branch_dependencies(self) -> None:
|
||||
scripts = MagicMock()
|
||||
scripts.get_revisions.return_value = (
|
||||
SimpleNamespace(revision="head-b"),
|
||||
SimpleNamespace(revision="head-a"),
|
||||
)
|
||||
|
||||
with (
|
||||
patch("govoplan_core.db.migrations.alembic_config"),
|
||||
patch(
|
||||
"govoplan_core.db.migrations.ScriptDirectory.from_config",
|
||||
return_value=scripts,
|
||||
),
|
||||
):
|
||||
heads = configured_migration_heads("sqlite://")
|
||||
|
||||
self.assertEqual(("head-a", "head-b"), heads)
|
||||
scripts.get_revisions.assert_called_once_with("heads")
|
||||
scripts.get_heads.assert_not_called()
|
||||
|
||||
def test_waits_until_exact_configured_heads_are_visible(self) -> None:
|
||||
with (
|
||||
patch(
|
||||
|
||||
Reference in New Issue
Block a user