Use Android build tools for APK validation

This commit is contained in:
2026-07-28 23:50:37 +02:00
parent 16e9eebc3d
commit ae4a95a337
4 changed files with 82 additions and 40 deletions

View File

@@ -1,4 +1,4 @@
"""Unit tests for sideload module — no network, ADB, or apkanalyzer required."""
"""Unit tests for sideload module — no network, ADB, or Android SDK required."""
from __future__ import annotations
@@ -243,14 +243,14 @@ class TestFdroidSource:
"org.example.test": {
"12345": {
"file": {
"name": "/repo/org.example.test_12345.apk",
"name": "/org.example.test_12345.apk",
"sha256": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
"size": 1234567,
}
},
"12344": {
"file": {
"name": "/repo/org.example.test_12344.apk",
"name": "/org.example.test_12344.apk",
"sha256": "0000000000000000000000000000000000000000000000000000000000000000",
}
},
@@ -310,6 +310,29 @@ class TestFdroidSource:
assert release.version == "12345"
assert release.download_url.endswith("/repo/org.example.test_12345.apk")
def test_get_latest_release_uses_manifest_version_code(self, app_entry: sideload.AppEntry):
index = {
"packages": {
"org.example.test": {
"versions": {
"sha256-of-version": {
"file": {"name": "/org.example.test_36.apk", "sha256": "a" * 64},
"manifest": {"versionCode": 36, "versionName": "5.1.1"},
},
"older-version": {
"file": {"name": "/org.example.test_34.apk", "sha256": "b" * 64},
"manifest": {"versionCode": 34, "versionName": "5.0.0"},
},
}
}
}
}
source = sideload.FdroidSource(app_entry)
with mock.patch("sideload._http_get", return_value=json.dumps(index).encode()):
release = source.get_latest_release()
assert release.version == "5.1.1"
assert release.download_url.endswith("/org.example.test_36.apk")
def test_missing_repo_url_raises(self):
entry = sideload.AppEntry(name="X", source="fdroid", app_id="x", config={})
with pytest.raises(ValueError, match="repo_url is required"):
@@ -471,7 +494,7 @@ class TestGitLabSource:
class TestApkValidator:
def test_validate_success(self, apk_file: Path):
validator = sideload.ApkValidator(apkanalyzer_bin="fake-apkanalyzer")
validator = sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt")
with mock.patch(
"sideload._run",
return_value=subprocess.CompletedProcess(
@@ -482,7 +505,7 @@ class TestApkValidator:
assert err is None
def test_validate_mismatch(self, apk_file: Path):
validator = sideload.ApkValidator(apkanalyzer_bin="fake-apkanalyzer")
validator = sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt")
with mock.patch(
"sideload._run",
return_value=subprocess.CompletedProcess(
@@ -493,12 +516,12 @@ class TestApkValidator:
assert err is not None
assert "mismatch" in err
def test_validate_apkanalyzer_fails(self, apk_file: Path):
validator = sideload.ApkValidator(apkanalyzer_bin="fake-apkanalyzer")
def test_validate_aapt_fails(self, apk_file: Path):
validator = sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt")
with mock.patch(
"sideload._run",
return_value=subprocess.CompletedProcess(
args=[], returncode=1, stdout="", stderr="command not found"
args=[], returncode=1, stdout="", stderr="invalid APK"
),
):
err = validator.validate(apk_file, "org.example.test")
@@ -662,7 +685,7 @@ class TestSideload:
with mock.patch("sideload._run", side_effect=mock_run):
result = sideload.sideload(
app_entry, config, dry_run=True,
validator=sideload.ApkValidator(apkanalyzer_bin="fake"),
validator=sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt"),
)
assert result == 0
@@ -700,7 +723,7 @@ class TestSideload:
with mock.patch("sideload._run", side_effect=mock_run):
result = sideload.sideload(
app_entry, config, dry_run=True,
validator=sideload.ApkValidator(apkanalyzer_bin="fake"),
validator=sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt"),
)
assert result == 1
@@ -744,7 +767,7 @@ class TestSideload:
with mock.patch("sideload._run", side_effect=mock_run):
result = sideload.sideload(
app_entry, config,
validator=sideload.ApkValidator(apkanalyzer_bin="fake"),
validator=sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt"),
adb_manager=sideload.AdbManager(binary="fake-adb"),
)
assert result == 1
@@ -790,7 +813,7 @@ class TestSideload:
result = sideload.sideload(
app_entry, config,
device_serial="NONEXISTENT",
validator=sideload.ApkValidator(apkanalyzer_bin="fake"),
validator=sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt"),
adb_manager=sideload.AdbManager(binary="fake-adb"),
)
assert result == 1
@@ -843,7 +866,7 @@ class TestSideload:
result = sideload.sideload(
app_entry, config,
device_serial="ABCD1234",
validator=sideload.ApkValidator(apkanalyzer_bin="fake"),
validator=sideload.ApkValidator(aapt2_bin="fake-aapt2", aapt_bin="fake-aapt"),
adb_manager=sideload.AdbManager(binary="fake-adb"),
)
assert result == 0