Files
hermes-relay/scripts/tests/android_release_artifacts_test.py

104 lines
3.7 KiB
Python

from __future__ import annotations
import importlib.util
import io
import json
import tempfile
import unittest
from argparse import Namespace
from contextlib import redirect_stdout
from pathlib import Path
SCRIPT = Path(__file__).parents[1] / "android_release_artifacts.py"
SPEC = importlib.util.spec_from_file_location("android_release_artifacts", SCRIPT)
assert SPEC and SPEC.loader
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
class AndroidReleaseArtifactsTest(unittest.TestCase):
def setUp(self) -> None:
self.temp = tempfile.TemporaryDirectory()
self.root = Path(self.temp.name)
self.apk = self.root / "hermes-relay-1.15.1-sideload-release.apk"
self.aab = self.root / "hermes-relay-1.15.1-googlePlay-release.aab"
self.sideload_mapping = self.root / "sideload-mapping.txt"
self.play_mapping = self.root / "play-mapping.txt"
for path, payload in (
(self.apk, b"apk"),
(self.aab, b"aab"),
(self.sideload_mapping, b"sideload mapping"),
(self.play_mapping, b"play mapping"),
):
path.write_bytes(payload)
self.output = self.root / "output"
self.package_args = Namespace(
version="1.15.1",
version_code="54",
commit="a" * 40,
tree="b" * 40,
sideload_apk=self.apk,
google_play_aab=self.aab,
sideload_mapping=self.sideload_mapping,
google_play_mapping=self.play_mapping,
output=self.output,
)
self.verify_args = Namespace(
version="1.15.1",
version_code="54",
tree="b" * 40,
directory=self.output,
)
def tearDown(self) -> None:
self.temp.cleanup()
def package(self) -> None:
with redirect_stdout(io.StringIO()):
MODULE.package_artifacts(self.package_args)
def test_package_and_verify_round_trip(self) -> None:
self.package()
with redirect_stdout(io.StringIO()):
MODULE.verify_artifacts(self.verify_args)
manifest = json.loads(
(self.output / MODULE.MANIFEST_NAME).read_text(encoding="utf-8")
)
self.assertEqual(
set(MODULE.EXPECTED_ROLES),
{item["role"] for item in manifest["artifacts"]},
)
checksums = (self.output / MODULE.CHECKSUMS_NAME).read_text(encoding="utf-8")
self.assertIn(self.apk.name, checksums)
self.assertIn(self.aab.name, checksums)
self.assertNotIn("mapping", checksums)
def test_verify_rejects_tampered_binary(self) -> None:
self.package()
(self.output / self.apk.name).write_bytes(b"tampered")
with self.assertRaisesRegex(MODULE.ArtifactError, "SHA-256 mismatch"):
MODULE.verify_artifacts(self.verify_args)
def test_verify_rejects_wrong_tree(self) -> None:
self.package()
self.verify_args.tree = "c" * 40
with self.assertRaisesRegex(MODULE.ArtifactError, "tree mismatch"):
MODULE.verify_artifacts(self.verify_args)
def test_verify_rejects_extra_file(self) -> None:
self.package()
(self.output / "unexpected.bin").write_bytes(b"unexpected")
with self.assertRaisesRegex(MODULE.ArtifactError, "artifact set mismatch"):
MODULE.verify_artifacts(self.verify_args)
def test_package_requires_canonical_public_names(self) -> None:
self.package_args.sideload_apk = self.root / "wrong.apk"
self.package_args.sideload_apk.write_bytes(b"wrong")
with self.assertRaisesRegex(MODULE.ArtifactError, "must be named"):
MODULE.package_artifacts(self.package_args)
if __name__ == "__main__":
unittest.main()