diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_lsfg_v2_migration.py | 304 |
1 files changed, 302 insertions, 2 deletions
diff --git a/tests/test_lsfg_v2_migration.py b/tests/test_lsfg_v2_migration.py index 4909d8b..ee1fcba 100644 --- a/tests/test_lsfg_v2_migration.py +++ b/tests/test_lsfg_v2_migration.py @@ -1,3 +1,4 @@ +import asyncio import logging import sys import tempfile @@ -73,14 +74,38 @@ class ConfigurationMigrationTests(unittest.TestCase): self.assertIn("LSFGVK_PROFILE=decky-lsfg-vk", script) self.assertNotIn("LSFG_PROCESS", script) - def test_active_in_uses_native_v2_tracking_instead_of_forcing_a_profile(self): + def test_active_in_does_not_implicitly_override_the_selected_profile(self): config = ConfigurationManager.get_defaults() config["active_in"] = "Game.exe, GameThread" self.assertEqual( ConfigurationService._profile_selection_lines("decky-lsfg-vk", config), - ["# active_in is configured; lsfg-vk will select a matching profile automatically."], + ["export LSFGVK_PROFILE=decky-lsfg-vk"], ) + config["use_native_matching"] = True + self.assertEqual( + ConfigurationService._profile_selection_lines("decky-lsfg-vk", config), + ["# lsfg-vk will select a matching profile from Active In."], + ) + self.assertEqual( + ConfigurationManager.parse_script_content("export DECKY_LSFGVK_AUTO_PROFILE=1\n"), + {"use_native_matching": True}, + ) + + def test_cloned_profile_disables_native_matching_until_explicitly_enabled(self): + config = ConfigurationManager.get_defaults() + config["active_in"] = "Game.exe" + config["use_native_matching"] = True + profile_data = { + "current_profile": "decky-lsfg-vk", + "profiles": {"decky-lsfg-vk": config}, + "global_config": {"dll": "", "allow_fp16": True}, + } + + cloned = ConfigurationManager.create_profile(profile_data, "Other") + self.assertEqual(cloned["profiles"]["Other"]["active_in"], "Game.exe") + self.assertFalse(cloned["profiles"]["Other"]["use_native_matching"]) + class InstallerInfrastructureTests(unittest.TestCase): def test_layer_archive_selection_has_no_legacy_arm_override(self): @@ -137,6 +162,36 @@ class InstallerInfrastructureTests(unittest.TestCase): service._create_config_file() self.assertEqual(len(list(config_dir.glob("conf.toml.v1.bak*"))), 1) + def test_unrecognized_configuration_is_backed_up_before_reset(self): + from lsfg_vk.installation import InstallationService + + with tempfile.TemporaryDirectory() as directory: + home = Path(directory) + config_dir = home / ".config" / "lsfg-vk" + config_dir.mkdir(parents=True) + config_path = config_dir / "conf.toml" + unsupported_config = "version = 3\n" + config_path.write_text(unsupported_config, encoding="utf-8") + + service = InstallationService.__new__(InstallationService) + service.log = mock.Mock() + service.user_home = home + service.config_dir = config_dir + service.config_file_path = config_path + service.lsfg_script_path = home / "lsfg" + service.lsfg_launch_script_path = home / "lsfg" + + with mock.patch("lsfg_vk.dll_detection.DllDetectionService") as detection_service: + detection_service.return_value.check_lossless_scaling_dll.return_value = {"detected": False} + service._create_config_file() + + self.assertEqual( + (config_dir / "conf.toml.unrecognized.bak").read_text(encoding="utf-8"), + unsupported_config, + ) + self.assertIn("version = 2", config_path.read_text(encoding="utf-8")) + self.assertEqual(service._config_recovery_backup, config_dir / "conf.toml.unrecognized.bak") + def test_writes_replace_the_config_atomically(self): service = BaseService.__new__(BaseService) service.log = mock.Mock() @@ -152,5 +207,250 @@ class InstallerInfrastructureTests(unittest.TestCase): replace.assert_called_once() +class FlatpakMigrationTests(unittest.TestCase): + def test_install_uses_the_bundled_flatpak_asset(self): + from lsfg_vk.flatpak_service import FlatpakService + + with tempfile.TemporaryDirectory() as directory: + bundle_path = Path(directory) / "org.freedesktop.Platform.VulkanLayer.lsfg_vk_23.08.flatpak" + bundle_path.write_bytes(b"flatpak bundle") + + service = FlatpakService.__new__(FlatpakService) + service.log = mock.Mock() + service.check_flatpak_available = mock.Mock(return_value=True) + service._get_bundled_extension_path = mock.Mock(return_value=bundle_path) + service._run_flatpak_command = mock.Mock( + return_value=types.SimpleNamespace(returncode=0, stdout="", stderr="") + ) + + result = service.install_extension("23.08") + + self.assertTrue(result["success"]) + service._run_flatpak_command.assert_called_once_with( + [ + "install", + "--user", + "--or-update", + "--assumeyes", + "--noninteractive", + str(bundle_path), + ], + capture_output=True, + text=True, + ) + + def test_update_installed_extensions_only_updates_user_runtimes_and_migrates_apps(self): + from lsfg_vk.flatpak_service import FlatpakService + + service = FlatpakService.__new__(FlatpakService) + service.log = mock.Mock() + service.check_flatpak_available = mock.Mock(return_value=True) + service._get_installed_extension_versions = mock.Mock(return_value=["23.08", "25.08"]) + service.install_extension = mock.Mock( + side_effect=[{"success": True}, {"success": True}] + ) + service._migrate_legacy_app_overrides = mock.Mock( + return_value={ + "success": True, + "migrated_apps": ["org.example.Game"], + "failed_apps": [], + } + ) + + result = service.update_installed_extensions() + + self.assertTrue(result["success"]) + self.assertEqual(result["updated_versions"], ["23.08", "25.08"]) + self.assertEqual(result["migrated_apps"], ["org.example.Game"]) + self.assertEqual( + service.install_extension.call_args_list, + [mock.call("23.08"), mock.call("25.08")], + ) + service._migrate_legacy_app_overrides.assert_called_once_with() + + def test_installed_runtime_scan_is_scoped_to_user_installation(self): + from lsfg_vk.flatpak_service import FlatpakService + + service = FlatpakService.__new__(FlatpakService) + service._run_flatpak_command = mock.Mock( + return_value=types.SimpleNamespace( + returncode=0, + stdout=( + "lsfg-vk\torg.freedesktop.Platform.VulkanLayer.lsfgvk\t" + "2.0\t23.08\tx86_64\n" + ), + stderr="", + ) + ) + + self.assertEqual(service._get_installed_extension_versions(), ["23.08"]) + service._run_flatpak_command.assert_called_once_with( + ["list", "--user", "--runtime"], + capture_output=True, + text=True, + check=True, + ) + + def test_failed_runtime_update_leaves_legacy_overrides_untouched(self): + from lsfg_vk.flatpak_service import FlatpakService + + service = FlatpakService.__new__(FlatpakService) + service.log = mock.Mock() + service.check_flatpak_available = mock.Mock(return_value=True) + service._get_installed_extension_versions = mock.Mock(return_value=["24.08"]) + service.install_extension = mock.Mock( + return_value={"success": False, "error": "bundle unavailable"} + ) + service._migrate_legacy_app_overrides = mock.Mock() + + result = service.update_installed_extensions() + + self.assertFalse(result["success"]) + self.assertEqual(result["failed_versions"][0]["version"], "24.08") + service._migrate_legacy_app_overrides.assert_not_called() + + def test_native_install_runs_flatpak_migration_after_success(self): + from lsfg_vk.plugin import Plugin + + plugin = Plugin.__new__(Plugin) + plugin.installation_service = mock.Mock() + plugin.flatpak_service = mock.Mock() + plugin.installation_service.install.return_value = { + "success": True, + "message": "lsfg-vk v2 installed successfully", + "error": None, + } + plugin.flatpak_service.update_installed_extensions.return_value = { + "success": True, + "message": "Updated one Flatpak runtime", + "skipped": False, + "updated_versions": ["23.08"], + "failed_versions": [], + "migrated_apps": [], + "failed_apps": [], + } + + result = asyncio.run(plugin.install_lsfg_vk()) + + self.assertTrue(result["success"]) + self.assertIn("flatpak_update", result) + plugin.flatpak_service.update_installed_extensions.assert_called_once_with() + + def test_legacy_override_detection_does_not_match_v2_environment(self): + from lsfg_vk.flatpak_service import FlatpakService + + with tempfile.TemporaryDirectory() as directory: + home = Path(directory) + service = FlatpakService.__new__(FlatpakService) + service.user_home = home + service.config_dir = home / ".config/lsfg-vk" + service.config_file_path = service.config_dir / "conf.toml" + service.lsfg_launch_script_path = home / "lsfg" + service.log = mock.Mock() + + self.assertTrue( + service._has_legacy_app_override( + f"LSFG_CONFIG={service.config_file_path}\n" + ) + ) + self.assertFalse( + service._has_legacy_app_override( + f"LSFGVK_CONFIG={service.config_file_path}\n" + ) + ) + + def test_legacy_override_migration_only_touches_plugin_owned_apps(self): + from lsfg_vk.flatpak_service import FlatpakService + + with tempfile.TemporaryDirectory() as directory: + home = Path(directory) + service = FlatpakService.__new__(FlatpakService) + service.user_home = home + service.config_dir = home / ".config/lsfg-vk" + service.config_file_path = service.config_dir / "conf.toml" + service.lsfg_launch_script_path = home / "lsfg" + service.log = mock.Mock() + service._get_flatpak_app_ids = mock.Mock( + return_value=["org.example.Legacy", "org.example.V2", "org.example.Other"] + ) + service._get_app_override_output = mock.Mock( + side_effect=[ + f"LSFG_CONFIG={service.config_file_path}\n", + f"LSFGVK_CONFIG={service.config_file_path}\n", + "", + ] + ) + service.set_app_override = mock.Mock(return_value={"success": True}) + + result = service._migrate_legacy_app_overrides() + + self.assertTrue(result["success"]) + self.assertEqual(result["migrated_apps"], ["org.example.Legacy"]) + service.set_app_override.assert_called_once_with("org.example.Legacy") + + def test_v2_override_setup_and_removal_clean_legacy_overrides(self): + from lsfg_vk.flatpak_service import FlatpakService + + with tempfile.TemporaryDirectory() as directory: + home = Path(directory) + config_dir = home / ".config" / "lsfg-vk" + config_dir.mkdir(parents=True) + config_path = config_dir / "conf.toml" + config_path.write_text( + ConfigurationManager.generate_toml_content(ConfigurationManager.get_defaults()), + encoding="utf-8", + ) + + service = FlatpakService.__new__(FlatpakService) + service.log = mock.Mock() + service.user_home = home + service.config_dir = config_dir + service.config_file_path = config_path + service.lsfg_launch_script_path = home / "lsfg" + service.check_flatpak_available = mock.Mock(return_value=True) + service._run_flatpak_command = mock.Mock( + return_value=types.SimpleNamespace(returncode=0, stdout="", stderr="") + ) + + app_id = "org.example.Game" + result = service.set_app_override(app_id) + self.assertTrue(result["success"]) + setup_calls = [call.args[0] for call in service._run_flatpak_command.call_args_list] + self.assertIn( + ["override", "--user", f"--env=LSFGVK_CONFIG={config_path}", app_id], + setup_calls, + ) + self.assertIn( + ["override", "--user", "--unset-env=LSFG_CONFIG", app_id], + setup_calls, + ) + self.assertIn( + [ + "override", + "--user", + f"--nofilesystem={home / '.local/share/Steam/steamapps/common/Lossless Scaling/Lossless.dll'}", + app_id, + ], + setup_calls, + ) + self.assertIn( + ["override", "--user", f"--nofilesystem={home / 'lsfg'}", app_id], + setup_calls, + ) + + service._run_flatpak_command.reset_mock() + result = service.remove_app_override(app_id) + self.assertTrue(result["success"]) + removal_calls = [call.args[0] for call in service._run_flatpak_command.call_args_list] + self.assertIn( + ["override", "--user", "--unset-env=LSFG_CONFIG", app_id], + removal_calls, + ) + self.assertIn( + ["override", "--user", f"--nofilesystem={home / 'lsfg'}", app_id], + removal_calls, + ) + + if __name__ == "__main__": unittest.main() |
