Files
metin-release-cli/tests/test_publish_composite.py
Jan Nedbal d2dd2c88b6 tests: cover phase 1 commands end to end
Pytest suite with a tiny_client fixture, an ephemeral Ed25519 keypair
fixture, and a threaded HTTPServer helper. Exercises cli dispatch,
inspect (including excluded-path handling), build-manifest and sign
against the real m2dev-client scripts, diff-remote via a local server,
and the full release publish composite against a local rsync target.
2026-04-14 18:59:50 +02:00

84 lines
2.7 KiB
Python

from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).parent / "fixtures"))
from http_server import serve_dir # noqa: E402
from metin_release.commands import publish # noqa: E402
from metin_release.workspace import Context # noqa: E402
MAKE_MANIFEST = Path("/home/jann/metin/repos/m2dev-client/scripts/make-manifest.py")
SIGN_MANIFEST = Path("/home/jann/metin/repos/m2dev-client/scripts/sign-manifest.py")
@pytest.mark.skipif(
not (MAKE_MANIFEST.is_file() and SIGN_MANIFEST.is_file()),
reason="reference scripts not available",
)
def test_publish_end_to_end_local(tiny_client: Path, tmp_path: Path, test_keypair):
key_path, pub_hex = test_keypair
out_dir = tmp_path / "release"
rsync_target_dir = tmp_path / "remote"
rsync_target_dir.mkdir()
rsync_target = str(rsync_target_dir) + "/"
ctx = Context(make_manifest_script=MAKE_MANIFEST, sign_manifest_script=SIGN_MANIFEST)
# We need verify-public to hit the rsync target as an HTTP server.
# Start HTTP server pointing at rsync target BEFORE publish runs verify-public.
with serve_dir(rsync_target_dir) as base_url:
args = argparse.Namespace(
source=tiny_client,
version="2026.04.14-1",
out=out_dir,
key=key_path,
rsync_target=rsync_target,
base_url=base_url,
public_key=pub_hex,
previous=None,
notes=None,
launcher="Metin2Launcher.exe",
created_at="2026-04-14T00:00:00Z",
sample_blobs=2,
yes=True,
force=False,
dry_run_upload=False,
)
result = publish.run(ctx, args)
assert result.ok is True
assert result.status == "published"
stages = result.data["stages"]
names = [s["name"] for s in stages]
assert names == [
"build-manifest",
"sign",
"stage-blobs",
"upload-blobs",
"promote",
"verify-public",
]
for s in stages:
assert "error" not in s
# Verify that the rsync target now contains manifest + blobs.
assert (rsync_target_dir / "manifest.json").is_file()
assert (rsync_target_dir / "manifest.json.sig").is_file()
assert (rsync_target_dir / "files").is_dir()
blobs = list((rsync_target_dir / "files").rglob("*"))
blob_files = [b for b in blobs if b.is_file()]
assert len(blob_files) >= 3
# Verify sample-blobs count reflected
verify_stats = result.data["stats"]["verify"]
assert verify_stats["signature_valid"] is True
assert verify_stats["sampled_blob_count"] == 2
assert verify_stats["sampled_blob_failures"] == []