Files
wild-pc/core/tests/test_kind_identity.py
Paul Payne 05b28cb584 Rename Castle -> Wild PC across the repo
Repo-side rename only (Phases 1-3 of the migration plan); the live box
(~/.castle, systemd units, /data/castle, domains) is a separate cutover.

- Slug `castle` -> `wildpc`: CLI command, module names (wildpc_core/cli/api),
  dist names, entry point `wildpc = wildpc_cli.main:main`.
- Identifiers: CastleConfig/NATSClient/DirError/MDNS -> Wildpc*.
- Env/constants: CASTLE_* -> WILDPC_*; ~/.castle -> ~/.wildpc, castle.yaml ->
  wildpc.yaml, /data/castle -> /data/wildpc.
- Systemd UNIT_PREFIX castle- -> wildpc-; own programs castle-api/gateway/etc.
- Display prose "Castle" -> "Wild PC" in docs, agent-guide files, README, frontend.
- Package dirs and bootstrap yaml renamed via git mv; lockfiles regenerated;
  redundant nested uv.lock files dropped (workspace root lock is authoritative).

Tests: core 273, cli 47, wildpc-api 120 all pass. Frontend type-checks + builds.
Fixed a stale test fixture (secret_env_path kind arg) broken pre-rename.
2026-07-18 22:55:08 -07:00

85 lines
3.4 KiB
Python

"""A deployment's identity is (name, kind): a tool, a service, and a job can all be
named the same. These lock the per-kind stores, the storage round-trip, distinct
unit names (job-suffix), and the subdomain-uniqueness guard."""
from __future__ import annotations
from pathlib import Path
import pytest
import yaml
from wildpc_core.config import load_config, save_config
from wildpc_core.deploy import _build_deployed, _desired_unit_files
from wildpc_core.registry import NodeConfig, NodeRegistry
def _write(root: Path, store: str, name: str, spec: dict) -> None:
d = root / "deployments" / store
d.mkdir(parents=True, exist_ok=True)
(d / f"{name}.yaml").write_text(yaml.dump(spec))
def _trio(root: Path) -> None:
(root / "wildpc.yaml").write_text(yaml.dump({"gateway": {"port": 9000}}))
_write(root, "services", "backup", {
"manager": "systemd", "run": {"launcher": "python", "program": "backup"},
})
_write(root, "jobs", "backup", {
"manager": "systemd", "run": {"launcher": "command", "argv": ["backup"]},
"schedule": "0 2 * * *",
})
_write(root, "tools", "backup", {"manager": "path", "program": "backup"})
def test_same_name_across_kinds_loads_into_distinct_stores(tmp_path: Path) -> None:
_trio(tmp_path)
config = load_config(tmp_path)
assert "backup" in config.services
assert "backup" in config.jobs
assert "backup" in config.tools
# all_deployments yields all three with their kinds
kinds = {kind for kind, name, _ in config.all_deployments() if name == "backup"}
assert kinds == {"service", "job", "tool"}
# deployments_named collects the trio
assert {k for k, _ in config.deployments_named("backup")} == {"service", "job", "tool"}
def test_trio_round_trips_through_per_kind_dirs(tmp_path: Path) -> None:
_trio(tmp_path)
config = load_config(tmp_path)
save_config(config)
# written under per-kind subdirs
assert (tmp_path / "deployments" / "services" / "backup.yaml").exists()
assert (tmp_path / "deployments" / "jobs" / "backup.yaml").exists()
assert (tmp_path / "deployments" / "tools" / "backup.yaml").exists()
reloaded = load_config(tmp_path)
assert "backup" in reloaded.services and "backup" in reloaded.jobs
assert "backup" in reloaded.tools
def test_service_and_job_get_distinct_units(tmp_path: Path) -> None:
_trio(tmp_path)
config = load_config(tmp_path)
registry = NodeRegistry(node=NodeConfig(hostname="h", gateway_port=9000))
for _kind, name, spec in config.all_deployments():
dep = _build_deployed(config, name, spec, [])
dep.name = name
registry.put(dep)
units = _desired_unit_files(registry)
# service keeps wildpc-<name>.service; job carries the -job marker; tool has none.
assert "wildpc-backup.service" in units
assert "wildpc-backup-job.service" in units
assert "wildpc-backup-job.timer" in units
def test_service_and_static_cannot_share_a_subdomain(tmp_path: Path) -> None:
(tmp_path / "wildpc.yaml").write_text(yaml.dump({"gateway": {"port": 9000}}))
_write(tmp_path, "services", "app", {
"manager": "systemd", "run": {"launcher": "python", "program": "app"},
"reach": "internal", "expose": {"http": {"internal": {"port": 9001}}},
})
_write(tmp_path, "statics", "app", {"manager": "caddy", "program": "app", "root": "dist"})
with pytest.raises(ValueError, match="subdomain 'app'"):
load_config(tmp_path)