Store: pruning rechecks each APK before deleting and spares ones being installed

Deletion re-stats under a lock shared with touch() (F-Droid cache reuse) and
claim()/release() (held by the store around install), so a reused or
installing APK is never removed from an out-of-date scan.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
saphidandClaude Opus 5.5 committed 2026-09-28 22:29:39 +10:00
1 parent 4fd8bb79af
commit a7261b1601
5 files changed
+91 -13

No files matched your search

+17
View File
@@ -33,6 +33,12 @@ class SettingsTest(unittest.TestCase):
self.addCleanup(p.stop)
for state in (search._running, search._pending, search._status, search._game_data):
state.clear()
from apk_sources import _web
self.claims = []
for name in ('claim', 'release'): # fake downloads aren't real files
p = patch.object(_web, name, side_effect=lambda path, name=name: self.claims.append((name, path)))
p.start()
self.addCleanup(p.stop)
class SearchTests(SettingsTest):
@@ -204,6 +210,17 @@ class SearchTests(SettingsTest):
search.install('one', 'brush')
install.assert_not_called()
def test_downloaded_apk_is_protected_from_pruning_while_installing(self):
mod = fake()
def install(apk, **kwargs):
self.assertEqual(self.claims, [('claim', '/fake.apk')])
raise server.frame_android.FrameError('adb failed')
with patch.object(search, 'modules', return_value=([mod], [])), \
patch.object(server.frame_android, 'install', install):
with self.assertRaises(server.frame_android.FrameError):
search.install('one', 'brush')
self.assertEqual(self.claims, [('claim', '/fake.apk'), ('release', '/fake.apk')])
def test_listing_cannot_download(self):
mod = fake()
mod.details = lambda s, i: dict(ENTRIES[0], downloadable=False)