mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 19:11:08 +00:00
124 lines
4.6 KiB
Python
124 lines
4.6 KiB
Python
import importlib.machinery
|
|
import importlib.util
|
|
import io
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import unittest
|
|
from contextlib import redirect_stdout
|
|
|
|
SCRIPT = Path(__file__).resolve().parents[1] / "linuxfs/overlay/usr/local/bin/droiddeck-flatpak"
|
|
|
|
|
|
class FakeInstallation:
|
|
def __init__(self, root):
|
|
self.root = root
|
|
|
|
def get_path(self):
|
|
return types.SimpleNamespace(get_path=lambda: self.root)
|
|
|
|
|
|
def load(root, ref, transactions):
|
|
repository = types.ModuleType("gi.repository")
|
|
repository.Flatpak = types.SimpleNamespace()
|
|
repository.Gio = types.SimpleNamespace()
|
|
repository.GLib = types.SimpleNamespace(Error=RuntimeError)
|
|
gi = types.ModuleType("gi")
|
|
gi.require_version = lambda *args: None
|
|
gi.repository = repository
|
|
saved = {name: sys.modules.get(name) for name in ("gi", "gi.repository")}
|
|
sys.modules["gi"] = gi
|
|
sys.modules["gi.repository"] = repository
|
|
try:
|
|
loader = importlib.machinery.SourceFileLoader("droiddeck_flatpak_uninstall", str(SCRIPT))
|
|
module = importlib.util.module_from_spec(importlib.util.spec_from_loader(loader.name, loader))
|
|
loader.exec_module(module)
|
|
finally:
|
|
for name, value in saved.items():
|
|
if value is None:
|
|
sys.modules.pop(name, None)
|
|
else:
|
|
sys.modules[name] = value
|
|
module.installation = lambda: FakeInstallation(root)
|
|
module.app_ref = lambda inst, app_id: ref
|
|
|
|
def transaction(inst):
|
|
transactions.append(inst)
|
|
raise AssertionError("an uninstalled app reached a transaction")
|
|
|
|
module.transaction = transaction
|
|
return module
|
|
|
|
|
|
class FlatpakUninstallTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.root = tempfile.mkdtemp()
|
|
self.addCleanup(shutil.rmtree, self.root, True)
|
|
self.apps = os.path.join(self.root, "app")
|
|
os.makedirs(self.apps)
|
|
|
|
def uninstall(self, app_id, ref=None):
|
|
transactions = []
|
|
module = load(self.root, ref, transactions)
|
|
out = io.StringIO()
|
|
with redirect_stdout(out):
|
|
rc = module.uninstall(app_id)
|
|
return rc, [json.loads(line) for line in out.getvalue().splitlines()], transactions
|
|
|
|
def test_an_app_folder_flatpak_no_longer_knows_is_removed(self):
|
|
stale = os.path.join(self.apps, "org.videolan.VLC")
|
|
os.makedirs(os.path.join(stale, "aarch64", "stable"))
|
|
os.symlink("missing-deploy", os.path.join(stale, "aarch64", "stable", "active"))
|
|
rc, events, transactions = self.uninstall("org.videolan.VLC")
|
|
self.assertEqual(rc, 0)
|
|
self.assertFalse(os.path.lexists(stale))
|
|
self.assertEqual(events, [{"e": "done", "note": "not installed"}])
|
|
self.assertEqual(transactions, [])
|
|
|
|
def test_other_apps_and_link_targets_are_left_alone(self):
|
|
outside = os.path.join(self.root, "outside")
|
|
os.makedirs(outside)
|
|
keep = os.path.join(outside, "keep")
|
|
open(keep, "w").close()
|
|
stale = os.path.join(self.apps, "com.google.Chrome")
|
|
os.makedirs(stale)
|
|
os.symlink(outside, os.path.join(stale, "linked"))
|
|
other = os.path.join(self.apps, "org.videolan.VLC")
|
|
os.makedirs(other)
|
|
rc, _, _ = self.uninstall("com.google.Chrome")
|
|
self.assertEqual(rc, 0)
|
|
self.assertFalse(os.path.lexists(stale))
|
|
self.assertTrue(os.path.isfile(keep))
|
|
self.assertTrue(os.path.isdir(other))
|
|
|
|
def test_a_linked_app_folder_is_not_followed(self):
|
|
target = os.path.join(self.root, "elsewhere")
|
|
os.makedirs(target)
|
|
open(os.path.join(target, "keep"), "w").close()
|
|
os.symlink(target, os.path.join(self.apps, "com.example.Linked"))
|
|
rc, _, _ = self.uninstall("com.example.Linked")
|
|
self.assertEqual(rc, 0)
|
|
self.assertTrue(os.path.isfile(os.path.join(target, "keep")))
|
|
|
|
def test_ids_that_leave_the_app_folder_are_refused(self):
|
|
for app_id in ("..", ".", "", "../app", "a/b"):
|
|
rc, events, _ = self.uninstall(app_id)
|
|
self.assertEqual(rc, 0)
|
|
self.assertEqual(events, [{"e": "done", "note": "not installed"}])
|
|
self.assertTrue(os.path.isdir(self.apps))
|
|
|
|
def test_an_installed_app_still_goes_through_flatpak(self):
|
|
os.makedirs(os.path.join(self.apps, "org.videolan.VLC"))
|
|
ref = types.SimpleNamespace(format_ref=lambda: "app/org.videolan.VLC/aarch64/stable")
|
|
with self.assertRaises(AssertionError):
|
|
self.uninstall("org.videolan.VLC", ref)
|
|
self.assertTrue(os.path.isdir(os.path.join(self.apps, "org.videolan.VLC")))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|