Test real installation ordering
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
import setup_tool_dynamic as dynamic
|
||||
|
||||
|
||||
class _Var:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
|
||||
class _Root:
|
||||
def configure(self, **_kwargs):
|
||||
return None
|
||||
|
||||
def update_idletasks(self):
|
||||
return None
|
||||
|
||||
|
||||
def _make_runtime_tool(target, events):
|
||||
"""Create the minimum state needed to execute the real base run_installation."""
|
||||
tool = object.__new__(dynamic.ModernWowSetupTool)
|
||||
tool._install_in_progress = False
|
||||
tool.wow_dir = _Var(target)
|
||||
tool.root = _Root()
|
||||
tool._close_download_progress = lambda: None
|
||||
|
||||
tool.validate_installation_dir = lambda value: (
|
||||
events.append(("validate_directory", value)) or True
|
||||
)
|
||||
tool.validate_limits = lambda: (
|
||||
events.append(("validate_limits", target)) or True
|
||||
)
|
||||
tool.validate_plugin_conflicts = lambda: (
|
||||
events.append(("preflight", target)) or True
|
||||
)
|
||||
|
||||
def record_target(name):
|
||||
return lambda value: events.append((name, value))
|
||||
|
||||
tool.copy_base_files = record_target("copy_base_files")
|
||||
tool.configure_dxvk = record_target("configure_dxvk")
|
||||
tool.configure_plugins = record_target("configure_plugins")
|
||||
tool.configure_autologin_encryption = lambda: events.append(
|
||||
("configure_autologin_encryption", target)
|
||||
)
|
||||
tool.configure_visual_audio = record_target("configure_visual_audio")
|
||||
tool.configure_script_memory = record_target("configure_script_memory")
|
||||
tool.configure_wdb_cache = record_target("configure_wdb_cache")
|
||||
tool.apply_process_mitigations = record_target("apply_process_mitigations")
|
||||
tool.create_launcher_shortcut = record_target("create_launcher_shortcut")
|
||||
tool.cleanup_legacy_outputs = record_target("cleanup_legacy_outputs")
|
||||
tool.save_settings = record_target("save_settings")
|
||||
return tool
|
||||
|
||||
|
||||
class RealInstallationOrderingTests(unittest.TestCase):
|
||||
def test_real_installation_runs_vanilla_tweaks_once_before_every_write(self):
|
||||
events = []
|
||||
|
||||
with tempfile.TemporaryDirectory() as target:
|
||||
initial_entries = set(os.listdir(target))
|
||||
tool = _make_runtime_tool(target, events)
|
||||
|
||||
def fake_clean(_instance, value):
|
||||
events.append(("clean_unselected_files", value))
|
||||
|
||||
def fake_vanilla_tweaks(_instance, value):
|
||||
events.append(("vanilla_tweaks", value))
|
||||
return os.path.join(value, "WoW_Modernized.exe")
|
||||
|
||||
with mock.patch.object(
|
||||
dynamic._ModernWowSetupToolCore,
|
||||
"clean_unselected_files",
|
||||
fake_clean,
|
||||
create=True,
|
||||
), mock.patch.object(
|
||||
dynamic._ModernWowSetupToolCore,
|
||||
"run_vanilla_tweaks",
|
||||
fake_vanilla_tweaks,
|
||||
create=True,
|
||||
), mock.patch(
|
||||
"setup_tool.messagebox.showinfo"
|
||||
) as showinfo, mock.patch(
|
||||
"setup_tool.messagebox.showerror"
|
||||
) as showerror:
|
||||
self.assertIsNone(tool.run_installation())
|
||||
|
||||
self.assertEqual(
|
||||
events,
|
||||
[
|
||||
("validate_directory", target),
|
||||
("validate_limits", target),
|
||||
("preflight", target),
|
||||
("vanilla_tweaks", target),
|
||||
("clean_unselected_files", target),
|
||||
("copy_base_files", target),
|
||||
("configure_dxvk", target),
|
||||
("configure_plugins", target),
|
||||
("configure_autologin_encryption", target),
|
||||
("configure_visual_audio", target),
|
||||
("configure_script_memory", target),
|
||||
("configure_wdb_cache", target),
|
||||
("apply_process_mitigations", target),
|
||||
("create_launcher_shortcut", target),
|
||||
("cleanup_legacy_outputs", target),
|
||||
("save_settings", target),
|
||||
],
|
||||
)
|
||||
showinfo.assert_called_once()
|
||||
showerror.assert_not_called()
|
||||
|
||||
# run_installation installs temporary instance wrappers. They
|
||||
# must be gone when Apply returns so a later Apply starts clean.
|
||||
self.assertNotIn("clean_unselected_files", tool.__dict__)
|
||||
self.assertNotIn("run_vanilla_tweaks", tool.__dict__)
|
||||
self.assertIs(tool.clean_unselected_files.__func__, fake_clean)
|
||||
self.assertIs(tool.run_vanilla_tweaks.__func__, fake_vanilla_tweaks)
|
||||
|
||||
# All real mutators above were replaced with record-only callbacks.
|
||||
# Any newly-added direct filesystem write in run_installation would
|
||||
# make this integration-style test visibly change the temp folder.
|
||||
self.assertEqual(set(os.listdir(target)), initial_entries)
|
||||
self.assertFalse(tool._install_in_progress)
|
||||
|
||||
def test_real_installation_vanilla_tweaks_failure_blocks_all_writes(self):
|
||||
events = []
|
||||
|
||||
with tempfile.TemporaryDirectory() as target:
|
||||
initial_entries = set(os.listdir(target))
|
||||
tool = _make_runtime_tool(target, events)
|
||||
|
||||
def fake_clean(_instance, value):
|
||||
events.append(("clean_unselected_files", value))
|
||||
|
||||
def failing_vanilla_tweaks(_instance, value):
|
||||
events.append(("vanilla_tweaks_failed", value))
|
||||
raise RuntimeError("patcher failed before install writes")
|
||||
|
||||
with mock.patch.object(
|
||||
dynamic._ModernWowSetupToolCore,
|
||||
"clean_unselected_files",
|
||||
fake_clean,
|
||||
create=True,
|
||||
), mock.patch.object(
|
||||
dynamic._ModernWowSetupToolCore,
|
||||
"run_vanilla_tweaks",
|
||||
failing_vanilla_tweaks,
|
||||
create=True,
|
||||
), mock.patch(
|
||||
"setup_tool.messagebox.showinfo"
|
||||
) as showinfo, mock.patch(
|
||||
"setup_tool.messagebox.showerror"
|
||||
) as showerror:
|
||||
self.assertIsNone(tool.run_installation())
|
||||
|
||||
self.assertEqual(
|
||||
events,
|
||||
[
|
||||
("validate_directory", target),
|
||||
("validate_limits", target),
|
||||
("preflight", target),
|
||||
("vanilla_tweaks_failed", target),
|
||||
],
|
||||
)
|
||||
showinfo.assert_not_called()
|
||||
showerror.assert_called_once()
|
||||
self.assertEqual(showerror.call_args.args[0], "Installation Error")
|
||||
self.assertIn(
|
||||
"patcher failed before install writes",
|
||||
showerror.call_args.args[1],
|
||||
)
|
||||
|
||||
# The temporary wrappers must also be restored on the error path.
|
||||
self.assertNotIn("clean_unselected_files", tool.__dict__)
|
||||
self.assertNotIn("run_vanilla_tweaks", tool.__dict__)
|
||||
self.assertIs(tool.clean_unselected_files.__func__, fake_clean)
|
||||
self.assertIs(
|
||||
tool.run_vanilla_tweaks.__func__,
|
||||
failing_vanilla_tweaks,
|
||||
)
|
||||
|
||||
self.assertEqual(set(os.listdir(target)), initial_entries)
|
||||
self.assertFalse(tool._install_in_progress)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user