public site and containers for that.
Build and Publish Container / Publish Linux container (push) Failing after 1m52s
Build and Publish Container / Publish Linux container (push) Failing after 1m52s
This commit is contained in:
@@ -0,0 +1,256 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import tempfile
|
||||
import unittest
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from progression_backend.app import create_app
|
||||
from progression_backend.app import latest_windows_release_url
|
||||
from progression_backend.config import Settings
|
||||
from progression_backend.database import Database
|
||||
from progression_backend.modlist import (
|
||||
ModListItem,
|
||||
core_items,
|
||||
generate_rml,
|
||||
parse_active_mods,
|
||||
workshop_items,
|
||||
)
|
||||
from progression_backend.refresh import RefreshService
|
||||
from progression_backend.steam_api import WorkshopDetails
|
||||
from progression_backend.workshop import SteamCmdBatchResult, parse_about_xml, utc_now
|
||||
|
||||
|
||||
class FakeSteam:
|
||||
def get_collections(self, collection_ids: list[str]) -> dict[str, list[str]]:
|
||||
return {collection_id: ["123456"] for collection_id in collection_ids}
|
||||
|
||||
def get_item_details(self, workshop_ids: list[str]) -> dict[str, WorkshopDetails]:
|
||||
return {
|
||||
workshop_id: WorkshopDetails(
|
||||
workshop_id=workshop_id,
|
||||
title="Test & Mod",
|
||||
time_updated=123,
|
||||
file_size=456,
|
||||
consumer_app_id=294100,
|
||||
result=1,
|
||||
)
|
||||
for workshop_id in workshop_ids
|
||||
}
|
||||
|
||||
|
||||
class FakeRunner:
|
||||
def __init__(self, content_dir: Path):
|
||||
self.content_dir = content_dir
|
||||
|
||||
def available(self) -> bool:
|
||||
return True
|
||||
|
||||
def run_batch(self, workshop_ids: list[str]) -> SteamCmdBatchResult:
|
||||
for workshop_id in workshop_ids:
|
||||
about = self.content_dir / workshop_id / "About"
|
||||
about.mkdir(parents=True)
|
||||
(about / "About.xml").write_text(
|
||||
"<ModMetaData><name>Test & Mod</name>"
|
||||
"<packageId>Author.Test</packageId>"
|
||||
"<steamAppId>294100</steamAppId></ModMetaData>",
|
||||
encoding="utf-8",
|
||||
)
|
||||
timestamp = utc_now()
|
||||
return SteamCmdBatchResult(
|
||||
workshop_ids=workshop_ids,
|
||||
started_at=timestamp,
|
||||
finished_at=timestamp,
|
||||
elapsed_seconds=0.1,
|
||||
exit_code=0,
|
||||
status="completed",
|
||||
failed_ids=set(),
|
||||
output_tail="Success",
|
||||
)
|
||||
|
||||
|
||||
class BackendTests(unittest.TestCase):
|
||||
@patch("progression_backend.app.requests.get")
|
||||
def test_latest_windows_release_includes_prereleases(self, get: Mock) -> None:
|
||||
response = Mock()
|
||||
response.json.return_value = [
|
||||
{
|
||||
"tag_name": "0.2.2",
|
||||
"published_at": "2026-06-13T02:37:15Z",
|
||||
"draft": False,
|
||||
"prerelease": True,
|
||||
"assets": [
|
||||
{
|
||||
"name": "ProgressionLoader.exe",
|
||||
"browser_download_url": "https://git.hudsonriggs.systems/HRiggs/ProgressionMods/releases/download/0.2.2/ProgressionLoader.exe",
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
get.return_value = response
|
||||
|
||||
self.assertEqual(
|
||||
latest_windows_release_url(),
|
||||
"https://git.hudsonriggs.systems/HRiggs/ProgressionMods/releases/download/0.2.2/ProgressionLoader.exe",
|
||||
)
|
||||
response.raise_for_status.assert_called_once_with()
|
||||
|
||||
@patch("progression_backend.app.requests.get")
|
||||
def test_latest_windows_release_prefers_stable_build(self, get: Mock) -> None:
|
||||
response = Mock()
|
||||
response.json.return_value = [
|
||||
{
|
||||
"published_at": "2026-07-01T00:00:00Z",
|
||||
"draft": False,
|
||||
"prerelease": True,
|
||||
"assets": [
|
||||
{
|
||||
"name": "ProgressionLoader.exe",
|
||||
"browser_download_url": "https://git.hudsonriggs.systems/HRiggs/ProgressionMods/releases/download/0.3.0-rc1/ProgressionLoader.exe",
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
"published_at": "2026-06-30T00:00:00Z",
|
||||
"draft": False,
|
||||
"prerelease": False,
|
||||
"assets": [
|
||||
{
|
||||
"name": "ProgressionLoader.exe",
|
||||
"browser_download_url": "https://git.hudsonriggs.systems/HRiggs/ProgressionMods/releases/download/0.2.3/ProgressionLoader.exe",
|
||||
}
|
||||
],
|
||||
},
|
||||
]
|
||||
get.return_value = response
|
||||
|
||||
self.assertEqual(
|
||||
latest_windows_release_url(),
|
||||
"https://git.hudsonriggs.systems/HRiggs/ProgressionMods/releases/download/0.2.3/ProgressionLoader.exe",
|
||||
)
|
||||
|
||||
def test_about_parser_normalizes_package_id(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
about = Path(directory) / "About"
|
||||
about.mkdir()
|
||||
(about / "About.xml").write_text(
|
||||
"<ModMetaData><name>A & B</name><packageId>Author.Mod</packageId></ModMetaData>",
|
||||
encoding="utf-8",
|
||||
)
|
||||
parsed = parse_about_xml(Path(directory))
|
||||
self.assertEqual(parsed.package_id, "author.mod")
|
||||
self.assertEqual(parsed.display_name, "A & B")
|
||||
|
||||
def test_rml_uses_workshop_id_and_escapes_names(self) -> None:
|
||||
payload = generate_rml(
|
||||
[
|
||||
*core_items(["royalty"]),
|
||||
ModListItem("author.mod", "123456", "A & B"),
|
||||
],
|
||||
"1.6",
|
||||
)
|
||||
root = ET.fromstring(payload)
|
||||
self.assertEqual(root.findtext("meta/gameVersion"), "1.6")
|
||||
self.assertEqual(
|
||||
[node.text for node in root.findall("meta/modSteamIds/li")],
|
||||
["0", "0", "123456"],
|
||||
)
|
||||
self.assertIn(b"A & B", payload)
|
||||
|
||||
def test_homebrew_parser_reads_active_mods(self) -> None:
|
||||
items = parse_active_mods(
|
||||
b"<ModsConfigData><activeMods><li>ludeon.rimworld</li>"
|
||||
b"<li>author.mod</li></activeMods></ModsConfigData>"
|
||||
)
|
||||
self.assertEqual(
|
||||
[item.package_id for item in items], ["ludeon.rimworld", "author.mod"]
|
||||
)
|
||||
|
||||
def test_refresh_persists_download_analytics(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
settings = Settings(
|
||||
host="127.0.0.1",
|
||||
port=8000,
|
||||
database_path=root / "progression.db",
|
||||
steamcmd_path="steamcmd",
|
||||
workshop_content_dir=root / "workshop" / "294100",
|
||||
steamcmd_batch_size=25,
|
||||
steamcmd_timeout_seconds=60,
|
||||
refresh_interval_seconds=3600,
|
||||
refresh_on_startup=False,
|
||||
game_version="1.6",
|
||||
admin_token=None,
|
||||
collections={"Core": "1", "Content": "2", "Cosmetics": "3"},
|
||||
static_dir=root,
|
||||
)
|
||||
database = Database(settings.database_path)
|
||||
database.initialize()
|
||||
service = RefreshService(
|
||||
settings,
|
||||
database,
|
||||
steam=FakeSteam(),
|
||||
runner=FakeRunner(settings.workshop_content_dir),
|
||||
)
|
||||
service.refresh("test-run", "test")
|
||||
|
||||
run = database.fetch_one(
|
||||
"SELECT * FROM refresh_runs WHERE id = ?", ("test-run",)
|
||||
)
|
||||
self.assertIsNotNone(run)
|
||||
self.assertEqual(run["status"], "completed", run)
|
||||
self.assertEqual(run["unique_items"], 1)
|
||||
self.assertEqual(run["downloads_succeeded"], 1)
|
||||
mod = database.fetch_one("SELECT * FROM mods WHERE workshop_id = '123456'")
|
||||
self.assertEqual(mod["package_id"], "author.test")
|
||||
self.assertEqual(mod["steam_app_id"], "294100")
|
||||
generated = workshop_items([mod])
|
||||
self.assertEqual(generated[0].workshop_id, "123456")
|
||||
|
||||
def test_api_serves_dashboard_and_reports_empty_modlist(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
project_root = Path(__file__).resolve().parents[1]
|
||||
settings = Settings(
|
||||
host="127.0.0.1",
|
||||
port=8000,
|
||||
database_path=root / "progression.db",
|
||||
steamcmd_path="missing-steamcmd",
|
||||
workshop_content_dir=root / "workshop" / "294100",
|
||||
steamcmd_batch_size=25,
|
||||
steamcmd_timeout_seconds=60,
|
||||
refresh_interval_seconds=3600,
|
||||
refresh_on_startup=False,
|
||||
game_version="1.6",
|
||||
admin_token=None,
|
||||
collections={"Core": "1", "Content": "2", "Cosmetics": "3"},
|
||||
static_dir=project_root / "progression_backend" / "static",
|
||||
)
|
||||
with TestClient(create_app(settings)) as client:
|
||||
self.assertEqual(client.get("/").status_code, 200)
|
||||
self.assertEqual(client.get("/art/GameTitle.png").status_code, 200)
|
||||
self.assertEqual(client.get("/api/health").json()["status"], "ok")
|
||||
self.assertIn("rml_updated_at", client.get("/api/status").json())
|
||||
response = client.get("/api/modlists/vanilla")
|
||||
self.assertEqual(response.status_code, 409)
|
||||
|
||||
release_url = (
|
||||
"https://git.hudsonriggs.systems/HRiggs/ProgressionMods/"
|
||||
"releases/download/0.2.2/ProgressionLoader.exe"
|
||||
)
|
||||
with patch(
|
||||
"progression_backend.app.latest_windows_release_url",
|
||||
return_value=release_url,
|
||||
):
|
||||
response = client.get(
|
||||
"/api/downloads/windows", follow_redirects=False
|
||||
)
|
||||
self.assertEqual(response.status_code, 307)
|
||||
self.assertEqual(response.headers["location"], release_url)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user