mirror of
https://github.com/Gathin23/cleanyourtv.git
synced 2026-10-27 19:54:45 +00:00
tools/manage.py: stop when the TV doesn't answer instead of reporting an empty TV
A nonzero exit from tv.py now ends the command with its diagnostic, so status never says "launcher: not installed" for a TV it couldn't read. Tests cover a failed package query, partial output then failure, a failed config query, a failure with no diagnostic, a genuinely empty TV and an installed launcher with a theme. Reported by @SaviorOneZero.
This commit is contained in:
1 parent
5726f765d7
commit
2b62fb6a68
2 files changed
+43
No files matched your search
@@ -1,7 +1,12 @@
|
||||
"""tools/manage.py reads the add-ons, themes and switches from the repo's own READMEs; check it finds them all, and
|
||||
that every add-on has a way in: its own install script or the steps in addons/README.md."""
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
@@ -43,5 +48,40 @@ class ManageTest(unittest.TestCase):
|
||||
manage.cmd_set("columns", "6", str(ROOT / "themes" / "aurora"))
|
||||
|
||||
|
||||
def status(self, *answers):
|
||||
"""Runs `status` with tv.py's answers (stdout, returncode, stderr) in order; returns what it printed."""
|
||||
replies = iter(subprocess.CompletedProcess([], code, out, err) for out, code, err in answers)
|
||||
out = io.StringIO()
|
||||
with mock.patch.dict(os.environ, {"TV_HOST": "192.0.2.1"}), \
|
||||
mock.patch.object(manage, "tv_python", return_value="python3"), \
|
||||
mock.patch.object(manage.subprocess, "run", side_effect=lambda *a, **k: next(replies)), \
|
||||
contextlib.redirect_stdout(out):
|
||||
code = manage.main(["status"])
|
||||
return code, out.getvalue()
|
||||
|
||||
def test_status_stops_when_the_tv_does_not_answer(self):
|
||||
for answers, message in [
|
||||
([("", 1, "failed to connect")], "failed to connect"),
|
||||
([("package:com.a\n", 1, "")], "package:com.a"),
|
||||
([("", 255, "")], "tv.py exited with status 255"),
|
||||
([("", 0, ""), ("", 1, "unauthorized")], "unauthorized"),
|
||||
]:
|
||||
with self.subTest(message=message), self.assertRaises(SystemExit) as stop:
|
||||
self.status(*answers)
|
||||
self.assertEqual(stop.exception.code, message)
|
||||
|
||||
def test_status_reads_an_empty_tv(self):
|
||||
code, out = self.status(("", 0, ""), ("", 0, ""))
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("launcher: not installed", out)
|
||||
self.assertIn("theme: none", out)
|
||||
|
||||
def test_status_finds_the_launcher_and_a_theme(self):
|
||||
theme = ROOT / "themes" / manage.themes()[0]["id"] / "config.json"
|
||||
code, out = self.status(("package:" + manage.LAUNCHER_PKG + "\n", 0, ""), (theme.read_text(encoding="utf-8"), 0, ""))
|
||||
self.assertEqual(code, 0)
|
||||
self.assertIn("launcher: installed", out)
|
||||
self.assertIn("theme: " + manage.themes()[0]["id"], out)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -147,6 +147,9 @@ def tv(command):
|
||||
if not os.environ.get("TV_HOST"):
|
||||
sys.exit("set TV_HOST to the TV IP address")
|
||||
r = subprocess.run([tv_python(), "-I", str(TOOLS / "tv.py"), command], capture_output=True, text=True)
|
||||
# A failed read is unknown, not empty: never report "not installed" for a TV that didn't answer.
|
||||
if r.returncode:
|
||||
sys.exit(r.stderr.strip() or r.stdout.strip() or f"tv.py exited with status {r.returncode}")
|
||||
return r.stdout
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user