644 lines
17 KiB
Python
644 lines
17 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
from scripts.release_lib import verify_signature
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
MOCK_CURL = r'''#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
METHOD="GET"
|
|
OUTPUT=""
|
|
FORM=""
|
|
DATA_FILE=""
|
|
URL=""
|
|
while (( $# > 0 ))
|
|
do
|
|
case "$1" in
|
|
--request)
|
|
METHOD="$2"
|
|
shift 2
|
|
;;
|
|
--output)
|
|
OUTPUT="$2"
|
|
shift 2
|
|
;;
|
|
--form)
|
|
FORM="$2"
|
|
shift 2
|
|
;;
|
|
--data-binary)
|
|
DATA_FILE="${2#@}"
|
|
shift 2
|
|
;;
|
|
--connect-timeout|--max-time|--header|--write-out)
|
|
shift 2
|
|
;;
|
|
--silent|--show-error)
|
|
shift
|
|
;;
|
|
*)
|
|
URL="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
release_json()
|
|
{
|
|
local assets
|
|
assets="$(jq -s '.' "${MOCK_STATE_DIR}"/asset-*.json)"
|
|
jq -n \
|
|
--arg html_url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${RELEASE_TAG}" \
|
|
--arg published_at "2026-09-08T12:00:00Z" \
|
|
--arg tag "$RELEASE_TAG" \
|
|
--arg name "PristonTale EU Launcher ${MOCK_VERSION}" \
|
|
--arg target_commitish "$RELEASE_COMMIT" \
|
|
--argjson assets "$assets" \
|
|
--argjson prerelease "$RELEASE_PRERELEASE" \
|
|
'{id:71,tag_name:$tag,name:$name,draft:false,prerelease:$prerelease,target_commitish:$target_commitish,published_at:$published_at,created_at:$published_at,html_url:$html_url,assets:$assets}'
|
|
}
|
|
|
|
case "${METHOD} ${URL}" in
|
|
"GET "*"/releases/tags/"*)
|
|
if [[ "${MOCK_TIMEOUT_STAGE:-}" == "existing" ]]
|
|
then
|
|
printf 'curl: (28) simulated release lookup timeout\n' >&2
|
|
exit 28
|
|
fi
|
|
if [[ -n "${MOCK_EXISTING_STATUS:-}" ]]
|
|
then
|
|
printf '%s\n' '{"message":"simulated release lookup failure"}' > "$OUTPUT"
|
|
printf '%s' "$MOCK_EXISTING_STATUS"
|
|
exit 0
|
|
fi
|
|
if [[ -f "${MOCK_STATE_DIR}/created" ]]
|
|
then
|
|
release_json > "$OUTPUT"
|
|
printf '200'
|
|
else
|
|
printf '%s\n' '{"message":"not found"}' > "$OUTPUT"
|
|
printf '404'
|
|
fi
|
|
;;
|
|
"POST "*"/releases")
|
|
if [[ "${MOCK_TIMEOUT_STAGE:-}" == "create" ]]
|
|
then
|
|
printf 'curl: (28) simulated release creation timeout\n' >&2
|
|
exit 28
|
|
fi
|
|
if [[ -n "${MOCK_CREATE_STATUS:-}" ]]
|
|
then
|
|
printf '%s\n' '{"message":"simulated release creation failure"}' > "$OUTPUT"
|
|
printf '%s' "$MOCK_CREATE_STATUS"
|
|
exit 0
|
|
fi
|
|
cp -- "$DATA_FILE" "${MOCK_STATE_DIR}/release-payload.json"
|
|
: > "${MOCK_STATE_DIR}/created"
|
|
printf '%s\n' '{"id":71}' > "$OUTPUT"
|
|
printf '201'
|
|
;;
|
|
"POST "*"/assets?name="*)
|
|
if [[ "${MOCK_TIMEOUT_STAGE:-}" == "asset" ]]
|
|
then
|
|
printf 'curl: (28) simulated attachment timeout\n' >&2
|
|
exit 28
|
|
fi
|
|
if [[ -n "${MOCK_ASSET_STATUS:-}" ]]
|
|
then
|
|
printf '%s\n' '{"message":"simulated attachment failure"}' > "$OUTPUT"
|
|
printf '%s' "$MOCK_ASSET_STATUS"
|
|
exit 0
|
|
fi
|
|
name="${URL##*?name=}"
|
|
file="${FORM#attachment=@}"
|
|
file="${file%%;*}"
|
|
size="$(stat -c '%s' -- "$file")"
|
|
jq -n \
|
|
--arg name "$name" \
|
|
--arg url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/download/${RELEASE_TAG}/${name}" \
|
|
--argjson size "$size" \
|
|
'{name:$name,size:$size,browser_download_url:$url}' > "$OUTPUT"
|
|
cp -- "$OUTPUT" "${MOCK_STATE_DIR}/asset-${name}.json"
|
|
printf '201'
|
|
;;
|
|
"GET "*"/releases?limit=100&page=1")
|
|
if [[ "${MOCK_RELEASE_PAGINATION:-}" == "1" ]]
|
|
then
|
|
jq -n '[range(0;100) as $index | {draft:true,tag_name:("ignored-" + ($index|tostring))}]' > "$OUTPUT"
|
|
else
|
|
release_json | jq -s '.' > "$OUTPUT"
|
|
fi
|
|
printf '200'
|
|
;;
|
|
"GET "*"/releases?limit=100&page=2")
|
|
release_json | jq -s '.' > "$OUTPUT"
|
|
printf '200'
|
|
;;
|
|
"GET "*"/contents/"*)
|
|
printf '%s\n' '{"message":"not found"}' > "$OUTPUT"
|
|
printf '404'
|
|
;;
|
|
"POST "*"/contents")
|
|
cp -- "$DATA_FILE" "${MOCK_STATE_DIR}/channel-payload.json"
|
|
printf '%s\n' '{"commit":{"sha":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}}' > "$OUTPUT"
|
|
printf '201'
|
|
;;
|
|
*)
|
|
printf 'Unexpected mock curl request: %s %s\n' "$METHOD" "$URL" >&2
|
|
exit 90
|
|
;;
|
|
esac
|
|
'''
|
|
|
|
|
|
MOCK_HISTORY_CURL = r'''#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
METHOD="GET"
|
|
OUTPUT=""
|
|
DATA_FILE=""
|
|
URL=""
|
|
while (( $# > 0 ))
|
|
do
|
|
case "$1" in
|
|
--request)
|
|
METHOD="$2"
|
|
shift 2
|
|
;;
|
|
--output)
|
|
OUTPUT="$2"
|
|
shift 2
|
|
;;
|
|
--data-binary)
|
|
DATA_FILE="${2#@}"
|
|
shift 2
|
|
;;
|
|
--connect-timeout|--max-time|--header|--write-out)
|
|
shift 2
|
|
;;
|
|
--silent|--show-error)
|
|
shift
|
|
;;
|
|
*)
|
|
URL="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
case "${METHOD} ${URL}" in
|
|
"GET "*"/releases?limit=100&page=1")
|
|
cp -- "$MOCK_RELEASES" "$OUTPUT"
|
|
printf '200'
|
|
;;
|
|
"GET "*"/manifest.json.sig")
|
|
cp -- "$MOCK_MANIFEST_SIGNATURE" "$OUTPUT"
|
|
printf '200'
|
|
;;
|
|
"GET "*"/manifest.json")
|
|
cp -- "$MOCK_MANIFEST" "$OUTPUT"
|
|
printf '200'
|
|
;;
|
|
"GET "*"/contents/"*)
|
|
printf '%s\n' '{"message":"not found"}' > "$OUTPUT"
|
|
printf '404'
|
|
;;
|
|
"POST "*"/contents")
|
|
cp -- "$DATA_FILE" "$MOCK_HISTORY_PAYLOAD"
|
|
printf '%s\n' '{"commit":{"sha":"cccccccccccccccccccccccccccccccccccccccc"}}' > "$OUTPUT"
|
|
printf '201'
|
|
;;
|
|
*)
|
|
printf 'Unexpected history mock request: %s %s\n' "$METHOD" "$URL" >&2
|
|
exit 90
|
|
;;
|
|
esac
|
|
'''
|
|
|
|
|
|
def _publisher_manifest(version: str = "1.8.0") -> bytes:
|
|
archive_name = f"PristonTale-EU-{version}.tar.gz"
|
|
archive_url = (
|
|
f"https://gitea.example.test/owner/project/releases/download/"
|
|
f"v{version}/{archive_name}"
|
|
)
|
|
return (
|
|
json.dumps(
|
|
{
|
|
"application": "PristonTale-EU",
|
|
"archive": {
|
|
"name": archive_name,
|
|
"sha256": "a" * 64,
|
|
"size": 123,
|
|
"url": archive_url,
|
|
},
|
|
"archive_sha256": "a" * 64,
|
|
"archive_size": 123,
|
|
"archive_url": archive_url,
|
|
"channel": "stable",
|
|
"compatibility": {
|
|
"config_schema": 1,
|
|
"manifest_schema": 1,
|
|
"minimum_config_schema": 1,
|
|
"minimum_updater_version": "0.5.0",
|
|
},
|
|
"minimum_updater_version": "0.5.0",
|
|
"notes_url": (
|
|
f"https://gitea.example.test/owner/project/releases/tag/v{version}"
|
|
),
|
|
"published_at": "2026-09-08T12:00:00Z",
|
|
"schema": 1,
|
|
"status": "active",
|
|
"tag": f"v{version}",
|
|
"version": version,
|
|
},
|
|
indent=2,
|
|
sort_keys=True,
|
|
)
|
|
+ "\n"
|
|
).encode()
|
|
|
|
|
|
class GiteaPublisherTests(unittest.TestCase):
|
|
def test_publishes_assets_and_updates_only_the_selected_channel(self) -> None:
|
|
openssl = shutil.which("openssl")
|
|
jq = shutil.which("jq")
|
|
if openssl is None or jq is None:
|
|
self.skipTest("OpenSSL and jq are required")
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
root = Path(temporary)
|
|
output = root / "dist"
|
|
state = root / "state"
|
|
fake_bin = root / "bin"
|
|
for directory in (output, state, fake_bin):
|
|
directory.mkdir()
|
|
archive = output / "PristonTale-EU-0.9.8.tar.gz"
|
|
archive.write_bytes(b"archive fixture")
|
|
(output / f"{archive.name}.sha256").write_text(
|
|
f"{'a' * 64} {archive.name}\n",
|
|
encoding="ascii",
|
|
)
|
|
(output / "manifest.json").write_text('{"schema":1}\n', encoding="utf-8")
|
|
(output / "manifest.json.sig").write_bytes(b"manifest signature")
|
|
(output / "release-notes.md").write_text("Release notes.\n", encoding="utf-8")
|
|
private_key = root / "private.pem"
|
|
public_key = root / "public.pem"
|
|
subprocess.run(
|
|
[
|
|
openssl,
|
|
"genpkey",
|
|
"-quiet",
|
|
"-algorithm",
|
|
"RSA",
|
|
"-pkeyopt",
|
|
"rsa_keygen_bits:2048",
|
|
"-out",
|
|
str(private_key),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
openssl,
|
|
"pkey",
|
|
"-in",
|
|
str(private_key),
|
|
"-pubout",
|
|
"-out",
|
|
str(public_key),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
fake_curl = fake_bin / "curl"
|
|
fake_curl.write_text(MOCK_CURL, encoding="utf-8")
|
|
fake_curl.chmod(0o755)
|
|
summary = root / "summary.md"
|
|
environment = {
|
|
**os.environ,
|
|
"PATH": f"{fake_bin}:{os.environ['PATH']}",
|
|
"GITHUB_API_URL": "https://gitea.example.test/api/v1",
|
|
"GITHUB_REPOSITORY": "owner/project",
|
|
"GITHUB_SERVER_URL": "https://gitea.example.test",
|
|
"GITHUB_STEP_SUMMARY": str(summary),
|
|
"MOCK_STATE_DIR": str(state),
|
|
"MOCK_RELEASE_PAGINATION": "1",
|
|
"MOCK_VERSION": "0.9.8",
|
|
"PTLINUX_PYTHON": sys.executable,
|
|
"PTLINUX_SIGNING_KEY": str(private_key),
|
|
"PTLINUX_UPDATE_PUBLIC_KEY": str(public_key),
|
|
"RELEASE_BRANCH": "main",
|
|
"RELEASE_COMMIT": "a" * 40,
|
|
"RELEASE_PRERELEASE": "false",
|
|
"RELEASE_TAG": "v0.9.8",
|
|
"RELEASE_TOKEN": "mock-release-token",
|
|
}
|
|
result = subprocess.run(
|
|
[
|
|
str(PROJECT_ROOT / "scripts/publish-gitea-release.sh"),
|
|
"0.9.8",
|
|
"stable",
|
|
str(output),
|
|
str(output / "release-notes.md"),
|
|
],
|
|
cwd=PROJECT_ROOT,
|
|
env=environment,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
release_payload = json.loads(
|
|
(state / "release-payload.json").read_text(encoding="utf-8")
|
|
)
|
|
self.assertFalse(release_payload["draft"])
|
|
self.assertFalse(release_payload["prerelease"])
|
|
self.assertEqual(release_payload["tag_name"], "v0.9.8")
|
|
self.assertEqual(release_payload["body"], "Release notes.\n")
|
|
self.assertEqual(len(list(state.glob("asset-*.json"))), 5)
|
|
channel_payload = json.loads(
|
|
(state / "channel-payload.json").read_text(encoding="utf-8")
|
|
)
|
|
paths = {operation["path"] for operation in channel_payload["files"]}
|
|
self.assertIn("updates/stable.json", paths)
|
|
self.assertIn("updates/stable.json.sig", paths)
|
|
self.assertNotIn("updates/prerelease.json", paths)
|
|
self.assertIn("updates/history.json", paths)
|
|
self.assertIn("Status | Published", summary.read_text(encoding="utf-8"))
|
|
self.assertNotIn("mock-release-token", result.stdout + result.stderr)
|
|
|
|
second = subprocess.run(
|
|
[
|
|
str(PROJECT_ROOT / "scripts/publish-gitea-release.sh"),
|
|
"0.9.8",
|
|
"stable",
|
|
str(output),
|
|
str(output / "release-notes.md"),
|
|
],
|
|
cwd=PROJECT_ROOT,
|
|
env=environment,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
self.assertNotEqual(second.returncode, 0)
|
|
self.assertIn("already exists", second.stderr)
|
|
|
|
def test_status_publication_rebuilds_signed_channel_metadata(self) -> None:
|
|
openssl = shutil.which("openssl")
|
|
jq = shutil.which("jq")
|
|
if openssl is None or jq is None:
|
|
self.skipTest("OpenSSL and jq are required")
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
root = Path(temporary)
|
|
fake_bin = root / "bin"
|
|
fake_bin.mkdir()
|
|
private_key = root / "private.pem"
|
|
public_key = root / "public.pem"
|
|
subprocess.run(
|
|
[
|
|
openssl,
|
|
"genpkey",
|
|
"-quiet",
|
|
"-algorithm",
|
|
"RSA",
|
|
"-pkeyopt",
|
|
"rsa_keygen_bits:2048",
|
|
"-out",
|
|
str(private_key),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
subprocess.run(
|
|
[
|
|
openssl,
|
|
"pkey",
|
|
"-in",
|
|
str(private_key),
|
|
"-pubout",
|
|
"-out",
|
|
str(public_key),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
manifest = root / "manifest.json"
|
|
manifest.write_bytes(_publisher_manifest())
|
|
manifest_signature = root / "manifest.json.sig"
|
|
subprocess.run(
|
|
[
|
|
openssl,
|
|
"dgst",
|
|
"-sha256",
|
|
"-sign",
|
|
str(private_key),
|
|
"-out",
|
|
str(manifest_signature),
|
|
str(manifest),
|
|
],
|
|
check=True,
|
|
capture_output=True,
|
|
)
|
|
releases = root / "releases.json"
|
|
releases.write_text(
|
|
json.dumps(
|
|
[
|
|
{
|
|
"assets": [
|
|
{
|
|
"browser_download_url": (
|
|
"https://gitea.example.test/owner/project/"
|
|
"releases/download/v1.8.0/manifest.json"
|
|
),
|
|
"name": "manifest.json",
|
|
},
|
|
{
|
|
"browser_download_url": (
|
|
"https://gitea.example.test/owner/project/"
|
|
"releases/download/v1.8.0/manifest.json.sig"
|
|
),
|
|
"name": "manifest.json.sig",
|
|
},
|
|
],
|
|
"draft": False,
|
|
"html_url": (
|
|
"https://gitea.example.test/owner/project/releases/tag/v1.8.0"
|
|
),
|
|
"id": 71,
|
|
"name": "PristonTale EU Launcher 1.8.0",
|
|
"prerelease": False,
|
|
"published_at": "2026-09-08T12:00:00Z",
|
|
"tag_name": "v1.8.0",
|
|
}
|
|
]
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
statuses = root / "statuses.json"
|
|
statuses.write_text(
|
|
(
|
|
'{"releases":{"v1.8.0":{"config_schema":2,'
|
|
'"minimum_config_schema":1,"status":"withdrawn"}},"schema":1}\n'
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
mock_curl = fake_bin / "curl"
|
|
mock_curl.write_text(MOCK_HISTORY_CURL, encoding="utf-8")
|
|
mock_curl.chmod(0o755)
|
|
payload = root / "history-payload.json"
|
|
summary = root / "summary.md"
|
|
environment = {
|
|
**os.environ,
|
|
"PATH": f"{fake_bin}:{os.environ['PATH']}",
|
|
"GITHUB_API_URL": "https://gitea.example.test/api/v1",
|
|
"GITHUB_REPOSITORY": "owner/project",
|
|
"GITHUB_SERVER_URL": "https://gitea.example.test",
|
|
"GITHUB_STEP_SUMMARY": str(summary),
|
|
"MOCK_HISTORY_PAYLOAD": str(payload),
|
|
"MOCK_MANIFEST": str(manifest),
|
|
"MOCK_MANIFEST_SIGNATURE": str(manifest_signature),
|
|
"MOCK_RELEASES": str(releases),
|
|
"PTLINUX_PYTHON": sys.executable,
|
|
"PTLINUX_SIGNING_KEY": str(private_key),
|
|
"PTLINUX_UPDATE_PUBLIC_KEY": str(public_key),
|
|
"RELEASE_BRANCH": "main",
|
|
"RELEASE_STATUS_FILE": str(statuses),
|
|
"RELEASE_TOKEN": "mock-release-token",
|
|
}
|
|
result = subprocess.run(
|
|
[str(PROJECT_ROOT / "scripts/publish-release-history.sh"), str(root / "dist")],
|
|
cwd=PROJECT_ROOT,
|
|
env=environment,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
published = json.loads(payload.read_text(encoding="utf-8"))
|
|
files = {item["path"]: item for item in published["files"]}
|
|
self.assertEqual(
|
|
set(files),
|
|
{
|
|
"updates/history.json",
|
|
"updates/history.json.sig",
|
|
"updates/stable.json",
|
|
"updates/stable.json.sig",
|
|
},
|
|
)
|
|
stable = json.loads(base64.b64decode(files["updates/stable.json"]["content"]))
|
|
history = json.loads(base64.b64decode(files["updates/history.json"]["content"]))
|
|
self.assertEqual(stable["status"], "withdrawn")
|
|
self.assertEqual(history["releases"][0]["status"], "withdrawn")
|
|
self.assertEqual(
|
|
history["releases"][0]["compatibility"],
|
|
{"config_schema": 2, "minimum_config_schema": 1},
|
|
)
|
|
self.assertEqual(
|
|
stable["compatibility"]["config_schema"],
|
|
2,
|
|
)
|
|
published_stable = root / "published-stable.json"
|
|
published_stable_signature = root / "published-stable.json.sig"
|
|
published_stable.write_bytes(
|
|
base64.b64decode(files["updates/stable.json"]["content"])
|
|
)
|
|
published_stable_signature.write_bytes(
|
|
base64.b64decode(files["updates/stable.json.sig"]["content"])
|
|
)
|
|
verify_signature(published_stable, published_stable_signature, public_key)
|
|
self.assertIn("stable channel: `1.8.0`", summary.read_text(encoding="utf-8"))
|
|
self.assertNotIn("mock-release-token", result.stdout + result.stderr)
|
|
|
|
def test_api_failures_never_report_publication_success(self) -> None:
|
|
if shutil.which("jq") is None:
|
|
self.skipTest("jq is required")
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
root = Path(temporary)
|
|
output = root / "dist"
|
|
state = root / "state"
|
|
fake_bin = root / "bin"
|
|
for directory in (output, state, fake_bin):
|
|
directory.mkdir()
|
|
archive = output / "PristonTale-EU-0.9.8.tar.gz"
|
|
archive.write_bytes(b"archive fixture")
|
|
(output / f"{archive.name}.sha256").write_text(
|
|
f"{'a' * 64} {archive.name}\n",
|
|
encoding="ascii",
|
|
)
|
|
for name in ("manifest.json", "manifest.json.sig", "release-notes.md"):
|
|
(output / name).write_text("fixture\n", encoding="utf-8")
|
|
fake_curl = fake_bin / "curl"
|
|
fake_curl.write_text(MOCK_CURL, encoding="utf-8")
|
|
fake_curl.chmod(0o755)
|
|
base_environment = {
|
|
**os.environ,
|
|
"PATH": f"{fake_bin}:{os.environ['PATH']}",
|
|
"GITHUB_API_URL": "https://gitea.example.test/api/v1",
|
|
"GITHUB_REPOSITORY": "owner/project",
|
|
"GITHUB_SERVER_URL": "https://gitea.example.test",
|
|
"MOCK_STATE_DIR": str(state),
|
|
"MOCK_VERSION": "0.9.8",
|
|
"RELEASE_BRANCH": "main",
|
|
"RELEASE_COMMIT": "a" * 40,
|
|
"RELEASE_PRERELEASE": "false",
|
|
"RELEASE_TAG": "v0.9.8",
|
|
"RELEASE_TOKEN": "mock-release-token",
|
|
}
|
|
command = [
|
|
str(PROJECT_ROOT / "scripts/publish-gitea-release.sh"),
|
|
"0.9.8",
|
|
"stable",
|
|
str(output),
|
|
str(output / "release-notes.md"),
|
|
]
|
|
|
|
cases = [
|
|
("MOCK_EXISTING_STATUS", "401"),
|
|
("MOCK_EXISTING_STATUS", "403"),
|
|
("MOCK_EXISTING_STATUS", "500"),
|
|
("MOCK_CREATE_STATUS", "404"),
|
|
("MOCK_CREATE_STATUS", "409"),
|
|
("MOCK_CREATE_STATUS", "422"),
|
|
("MOCK_CREATE_STATUS", "500"),
|
|
("MOCK_ASSET_STATUS", "500"),
|
|
("MOCK_TIMEOUT_STAGE", "existing"),
|
|
("MOCK_TIMEOUT_STAGE", "create"),
|
|
("MOCK_TIMEOUT_STAGE", "asset"),
|
|
]
|
|
for variable, value in cases:
|
|
with self.subTest(variable=variable, value=value):
|
|
(state / "created").unlink(missing_ok=True)
|
|
environment = {**base_environment, variable: value}
|
|
result = subprocess.run(
|
|
command,
|
|
cwd=PROJECT_ROOT,
|
|
env=environment,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
self.assertNotEqual(result.returncode, 0)
|
|
self.assertNotIn("Published stable release", result.stdout)
|
|
self.assertNotIn("mock-release-token", result.stdout + result.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|