同步移动端工程、设备控制改进与发布资料

This commit is contained in:
2026-09-26 19:21:12 +08:00
parent 912ba432cf
commit 98eadc5c8b
137 changed files with 9274 additions and 85 deletions
@@ -133,6 +133,31 @@ def test_failed_install_restores_system_bytes_and_running_state(host):
assert ['systemctl', 'start', c.FRP] in host
def test_mobile_rollback_restores_files_masks_and_running_state(host):
journal, record = make_journal()
record['mobile_services'] = {
'aw859-bluetooth.service': {'enabled_state': 'masked', 'active': False},
'bluetooth.service': {'enabled_state': 'enabled', 'active': True},
}
record['files']['bluetooth-original'] = None
for name in c.MOBILE_FILES:
c.FILES[name].write_bytes(b'changed-by-mobile-install')
c.restore_components(journal, record)
assert not c.FILES['bluetooth-original'].exists()
for name in set(c.MOBILE_FILES) - {'bluetooth-original'}:
assert c.FILES[name].read_bytes() == ('old-' + name).encode()
assert ['systemctl', 'mask', 'aw859-bluetooth.service'] in host
assert ['systemctl', 'enable', 'bluetooth.service'] in host
assert ['systemctl', 'start', 'bluetooth.service'] in host
assert ['systemctl', 'start', 'aw859-bluetooth.service'] not in host
def test_legacy_component_journal_does_not_touch_bluetooth(host):
journal, record = make_journal()
c.restore_components(journal, record)
assert not any(unit in args for args in host for unit in c.MOBILE_SERVICES)
def test_power_loss_between_data_renames_recovers_original(host):
journal, record = make_journal()
(c.DATA/'user-content').write_bytes(b'unchanged')
@@ -181,6 +206,35 @@ def test_normal_migration_does_not_touch_components(host):
assert host == []
def test_mobile_only_patch_enters_durable_component_transaction(host, monkeypatch):
from types import SimpleNamespace
source = c.RELEASES / '1.1.2-mobilepatch'
source.mkdir()
(source / 'VERSION').write_text('1.1.2', encoding='utf-8')
(source / 'scripts').mkdir()
(source / 'scripts/install_mobile_bluetooth.sh').write_text('# test fixture', encoding='utf-8')
candidate = c.DATA.with_name('matrix-screen-controller.ota.mobilepatch')
candidate.mkdir()
c.RUNTIME.mkdir(parents=True, exist_ok=True)
(c.RUNTIME / 'ota-request.json').write_text(json.dumps({
'job_id': 'mobilepatch', 'current_version': '1.1.1', 'target_version': '1.1.2'
}), encoding='utf-8')
monkeypatch.setattr(c.os, 'geteuid', lambda: 0, raising=False)
monkeypatch.setattr(c.os, 'uname', lambda: SimpleNamespace(machine='aarch64'), raising=False)
monkeypatch.setattr(c, 'check_installed', lambda *args: None)
monkeypatch.setattr(c, 'protect_runtime', lambda: None)
monkeypatch.setattr(c, 'mirror_permissions', lambda *args: None)
# Host test verifies transaction ordering; POSIX durability is covered by
# real Linux lifecycle checks, not Windows read-only descriptor fsync.
monkeypatch.setattr(c.os, 'fsync', lambda *args: None)
c.begin(source, candidate)
record = json.loads((c.DATA / c.JOURNAL / 'state.json').read_text(encoding='utf-8'))
assert set(record['mobile_services']) == set(c.MOBILE_SERVICES)
assert (candidate / c.JOURNAL / 'state.json').is_file()
assert ['/bin/sh', str(source / 'scripts/install_mobile_bluetooth.sh')] in host
assert not any('install_frpc_system.sh' in str(arg) for args in host for arg in args)
def release_project(tmp_path, monkeypatch):
from scripts import export_release as exporter
source = tmp_path / 'software'