初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
from app.ota.diagnostics import DiagnosticLog, MAX_FAILURE_LOG_BYTES
|
||||
from scripts import ota_components as component
|
||||
|
||||
|
||||
def test_directory_loss_restores_recent_diagnostics(tmp_path):
|
||||
path = tmp_path / 'run/log'
|
||||
log = DiagnosticLog(path)
|
||||
log.reset();log.write('before stop')
|
||||
shutil.rmtree(path.parent)
|
||||
log.write('after stop')
|
||||
assert 'before stop' in path.read_text(encoding='utf-8')
|
||||
assert 'after stop' in path.read_text(encoding='utf-8')
|
||||
|
||||
|
||||
def test_unwritable_log_does_not_mask_command_failure_or_prevent_persistence(tmp_path, monkeypatch, capsys):
|
||||
path = tmp_path / 'run/log'
|
||||
log = DiagnosticLog(path)
|
||||
log.reset()
|
||||
original = Path.open
|
||||
def broken(self, *args, **kwargs):
|
||||
if self == path:
|
||||
raise PermissionError('do not print confidential OS details')
|
||||
return original(self, *args, **kwargs)
|
||||
monkeypatch.setattr(Path, 'open', broken)
|
||||
monkeypatch.setattr(subprocess, 'run', lambda *a, **k: subprocess.CompletedProcess(a, 9, b'original failure'))
|
||||
with pytest.raises(RuntimeError, match='original failure'):
|
||||
log.run(['example'])
|
||||
log.write('rollback executed')
|
||||
target = log.persist(tmp_path/'data')
|
||||
assert 'rollback executed' in target.read_text(encoding='utf-8')
|
||||
assert 'confidential' not in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_fallback_buffer_is_bounded(tmp_path):
|
||||
log = DiagnosticLog(tmp_path/'log')
|
||||
log.write('x' * (MAX_FAILURE_LOG_BYTES * 2))
|
||||
assert len(log._recent) <= MAX_FAILURE_LOG_BYTES
|
||||
|
||||
|
||||
def test_runtime_guard_verified_and_does_not_overwrite_user_configuration(tmp_path, monkeypatch):
|
||||
path = tmp_path/'dropin/guard.conf'
|
||||
monkeypatch.setattr(component, 'RUNTIME_GUARD', path)
|
||||
monkeypatch.setattr(component, 'sync_directory', lambda p: None)
|
||||
commands=[]
|
||||
def run(args, **kwargs):
|
||||
commands.append(args)
|
||||
return subprocess.CompletedProcess(args, 0, b'yes\n')
|
||||
monkeypatch.setattr(component, 'run', run)
|
||||
component.protect_runtime()
|
||||
assert path.read_bytes() == component.RUNTIME_GUARD_BODY
|
||||
assert commands[-1][1] == 'show'
|
||||
component.release_runtime_guard()
|
||||
assert not path.exists()
|
||||
path.parent.mkdir();path.write_bytes(b'user setting')
|
||||
with pytest.raises(RuntimeError, match='overwrite'):
|
||||
component.protect_runtime()
|
||||
with pytest.raises(RuntimeError, match='modified'):
|
||||
component.release_runtime_guard()
|
||||
assert path.read_bytes() == b'user setting'
|
||||
|
||||
|
||||
def test_ineffective_guard_refuses_to_proceed(tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(component, 'RUNTIME_GUARD', tmp_path/'guard')
|
||||
monkeypatch.setattr(component, 'sync_directory', lambda p: None)
|
||||
monkeypatch.setattr(component, 'run', lambda a, **k: subprocess.CompletedProcess(a,0,b'restart\n'))
|
||||
with pytest.raises(RuntimeError, match='refusing to stop'):
|
||||
component.protect_runtime()
|
||||
|
||||
|
||||
def test_component_validation_accepts_current_transaction_runtime_guard(tmp_path, monkeypatch):
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from types import SimpleNamespace
|
||||
source = tmp_path/'source'
|
||||
(source/'systemd').mkdir(parents=True)
|
||||
(source/'systemd/matrix-screen-frpc.service').write_bytes(b'unit')
|
||||
(source/'UPGRADE_POLICY.json').write_text(json.dumps({'checkpoints':[
|
||||
{'version':'1.1.0','components':{'frpc':{'version':'0.71.0',
|
||||
'sha256':hashlib.sha256(b'binary').hexdigest()}}}]}),encoding='utf-8')
|
||||
files={name:tmp_path/name for name in ('frpc','frpc-unit','frpc-dropin')}
|
||||
for name,body in [('frpc',b'binary'),('frpc-unit',b'unit'),
|
||||
('frpc-dropin',b'[Service]\nUser=maintainer\nGroup=maintainer\n')]:
|
||||
files[name].write_bytes(body)
|
||||
data=tmp_path/'data';(data/'frp/profiles').mkdir(parents=True)
|
||||
guard=tmp_path/'guard';guard.write_bytes(component.RUNTIME_GUARD_BODY)
|
||||
monkeypatch.setattr(component,'FILES',files)
|
||||
monkeypatch.setattr(component,'DATA',data)
|
||||
monkeypatch.setattr(component,'RUNTIME_GUARD',guard)
|
||||
monkeypatch.setattr(component,'account',lambda:'maintainer')
|
||||
monkeypatch.setitem(sys.modules,'pwd',SimpleNamespace(getpwnam=lambda u:SimpleNamespace(pw_gid=1000)))
|
||||
monkeypatch.setitem(sys.modules,'grp',SimpleNamespace(getgrgid=lambda g:SimpleNamespace(gr_name='maintainer')))
|
||||
monkeypatch.setattr(component,'run',lambda a,**k:subprocess.CompletedProcess(a,0,b'0.71.0\n'))
|
||||
monkeypatch.setattr(component,'metadata',lambda p:{'mode':0o755 if p==files['frpc'] else 0o2750 if p.is_relative_to(data) else 0o644,
|
||||
'uid':0,'gid':1000 if p.is_relative_to(data) else 0})
|
||||
original=Path.stat
|
||||
def normalized_stat(self,*a,**k):
|
||||
value=original(self,*a,**k)
|
||||
fields=list(value)
|
||||
if self==data:fields[0]=(fields[0]&~0o7777)|0o711
|
||||
if self==files['frpc']:fields[4]=fields[5]=0
|
||||
return os.stat_result(fields)
|
||||
monkeypatch.setattr(Path,'stat',normalized_stat)
|
||||
component.check_installed(source,'1.1.0')
|
||||
assert guard.read_bytes()==component.RUNTIME_GUARD_BODY
|
||||
Reference in New Issue
Block a user