mirror of
https://github.com/mvt-project/mvt.git
synced 2026-08-17 08:30:38 +02:00
Fix dumpsys battery daily downgrade detection (#805)
This commit is contained in:
@@ -50,13 +50,11 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
|
|||||||
def parse(self, output: str) -> None:
|
def parse(self, output: str) -> None:
|
||||||
daily = None
|
daily = None
|
||||||
daily_updates: list[dict[str, Any]] = []
|
daily_updates: list[dict[str, Any]] = []
|
||||||
package_versions: dict[
|
records: list[dict[str, Any]] = []
|
||||||
str, str
|
|
||||||
] = {} # Track package versions to detect downgrades
|
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
if line.startswith(" Daily from "):
|
if line.startswith(" Daily from "):
|
||||||
if len(daily_updates) > 0:
|
if len(daily_updates) > 0:
|
||||||
self.results.extend(daily_updates)
|
records.extend(daily_updates)
|
||||||
daily_updates = []
|
daily_updates = []
|
||||||
|
|
||||||
timeframe = line[13:].strip()
|
timeframe = line[13:].strip()
|
||||||
@@ -89,35 +87,53 @@ class DumpsysBatteryDailyArtifact(AndroidArtifact):
|
|||||||
"vers": vers_nr,
|
"vers": vers_nr,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check for uninstall (version 0)
|
|
||||||
if vers_nr == "0":
|
|
||||||
self.alertstore.medium(
|
|
||||||
f"Detected uninstall of package {package_name} (vers 0)",
|
|
||||||
daily["from"],
|
|
||||||
update_record,
|
|
||||||
)
|
|
||||||
# Check for downgrade
|
|
||||||
elif package_name in package_versions:
|
|
||||||
try:
|
|
||||||
current_vers = int(vers_nr)
|
|
||||||
previous_vers = int(package_versions[package_name])
|
|
||||||
if current_vers < previous_vers:
|
|
||||||
update_record["action"] = "downgrade"
|
|
||||||
update_record["previous_vers"] = str(previous_vers)
|
|
||||||
self.alertstore.medium(
|
|
||||||
f"Detected downgrade of package {package_name} "
|
|
||||||
f"from vers {previous_vers} to vers {current_vers}",
|
|
||||||
daily["from"],
|
|
||||||
update_record,
|
|
||||||
)
|
|
||||||
except ValueError:
|
|
||||||
# If version numbers aren't integers, skip comparison
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Update tracking dictionary
|
|
||||||
package_versions[package_name] = vers_nr
|
|
||||||
|
|
||||||
daily_updates.append(update_record)
|
daily_updates.append(update_record)
|
||||||
|
|
||||||
if len(daily_updates) > 0:
|
if len(daily_updates) > 0:
|
||||||
self.results.extend(daily_updates)
|
records.extend(daily_updates)
|
||||||
|
|
||||||
|
self._detect_uninstalls_and_downgrades(records)
|
||||||
|
self.results.extend(records)
|
||||||
|
|
||||||
|
def _detect_uninstalls_and_downgrades(
|
||||||
|
self, records: list[dict[str, Any]]
|
||||||
|
) -> None:
|
||||||
|
package_versions: dict[str, int] = {}
|
||||||
|
|
||||||
|
for record in sorted(
|
||||||
|
records,
|
||||||
|
key=lambda record: (
|
||||||
|
record["from"],
|
||||||
|
record["to"],
|
||||||
|
record["package_name"],
|
||||||
|
),
|
||||||
|
):
|
||||||
|
package_name = record["package_name"]
|
||||||
|
vers_nr = record["vers"]
|
||||||
|
|
||||||
|
if vers_nr == "0":
|
||||||
|
self.alertstore.medium(
|
||||||
|
f"Detected uninstall of package {package_name} (vers 0)",
|
||||||
|
record["from"],
|
||||||
|
record,
|
||||||
|
)
|
||||||
|
package_versions.pop(package_name, None)
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
current_vers = int(vers_nr)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
previous_vers = package_versions.get(package_name)
|
||||||
|
if previous_vers is not None and current_vers < previous_vers:
|
||||||
|
record["action"] = "downgrade"
|
||||||
|
record["previous_vers"] = str(previous_vers)
|
||||||
|
self.alertstore.medium(
|
||||||
|
f"Detected downgrade of package {package_name} "
|
||||||
|
f"from vers {previous_vers} to vers {current_vers}",
|
||||||
|
record["from"],
|
||||||
|
record,
|
||||||
|
)
|
||||||
|
|
||||||
|
package_versions[package_name] = current_vers
|
||||||
|
|||||||
@@ -69,3 +69,65 @@ class TestDumpsysBatteryDailyArtifact:
|
|||||||
assert downgrade_alert.event["package_name"] == "com.example.app"
|
assert downgrade_alert.event["package_name"] == "com.example.app"
|
||||||
assert downgrade_alert.event["action"] == "downgrade"
|
assert downgrade_alert.event["action"] == "downgrade"
|
||||||
assert downgrade_alert.event["previous_vers"] == "10"
|
assert downgrade_alert.event["previous_vers"] == "10"
|
||||||
|
|
||||||
|
def test_newest_first_update_is_not_reported_as_downgrade(self):
|
||||||
|
dba = DumpsysBatteryDailyArtifact()
|
||||||
|
dba.parse(
|
||||||
|
"""
|
||||||
|
Daily from 2026-01-10 to 2026-01-11:
|
||||||
|
Update com.example.app vers=102
|
||||||
|
Daily from 2026-01-05 to 2026-01-06:
|
||||||
|
Update com.example.app vers=101
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(dba.results) == 2
|
||||||
|
assert len(dba.alertstore.alerts) == 0
|
||||||
|
assert all(result["action"] == "update" for result in dba.results)
|
||||||
|
|
||||||
|
def test_newest_first_downgrade_creates_medium_alert(self):
|
||||||
|
dba = DumpsysBatteryDailyArtifact()
|
||||||
|
dba.parse(
|
||||||
|
"""
|
||||||
|
Daily from 2026-01-10 to 2026-01-11:
|
||||||
|
Update com.example.app vers=101
|
||||||
|
Daily from 2026-01-05 to 2026-01-06:
|
||||||
|
Update com.example.app vers=102
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(dba.results) == 2
|
||||||
|
assert len(dba.alertstore.alerts) == 1
|
||||||
|
|
||||||
|
downgrade_alert = dba.alertstore.alerts[0]
|
||||||
|
assert downgrade_alert.level == AlertLevel.MEDIUM
|
||||||
|
assert downgrade_alert.message == (
|
||||||
|
"Detected downgrade of package com.example.app from vers 102 to vers 101"
|
||||||
|
)
|
||||||
|
assert downgrade_alert.event_time == "2026-01-10"
|
||||||
|
assert downgrade_alert.event["package_name"] == "com.example.app"
|
||||||
|
assert downgrade_alert.event["action"] == "downgrade"
|
||||||
|
assert downgrade_alert.event["previous_vers"] == "102"
|
||||||
|
|
||||||
|
def test_reinstall_after_uninstall_is_not_reported_as_downgrade(self):
|
||||||
|
dba = DumpsysBatteryDailyArtifact()
|
||||||
|
dba.parse(
|
||||||
|
"""
|
||||||
|
Daily from 2026-01-15 to 2026-01-16:
|
||||||
|
Update com.example.app vers=10
|
||||||
|
Daily from 2026-01-10 to 2026-01-11:
|
||||||
|
Update com.example.app vers=0
|
||||||
|
Daily from 2026-01-05 to 2026-01-06:
|
||||||
|
Update com.example.app vers=102
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(dba.results) == 3
|
||||||
|
assert len(dba.alertstore.alerts) == 1
|
||||||
|
|
||||||
|
uninstall_alert = dba.alertstore.alerts[0]
|
||||||
|
assert uninstall_alert.level == AlertLevel.MEDIUM
|
||||||
|
assert uninstall_alert.message == (
|
||||||
|
"Detected uninstall of package com.example.app (vers 0)"
|
||||||
|
)
|
||||||
|
assert uninstall_alert.event_time == "2026-01-10"
|
||||||
|
|||||||
Reference in New Issue
Block a user