75 lines
3.4 KiB
Python
75 lines
3.4 KiB
Python
import os
|
|
import sys
|
|
import subprocess
|
|
from proxydoctor import routes, worker
|
|
from proxydoctor.geo import GeoLocator
|
|
from proxydoctor.console import Console, clean, width
|
|
|
|
|
|
def test_interrupt_during_first_fsync_preserves_cancelled_report(tmp_path, monkeypatch):
|
|
import json
|
|
import pytest
|
|
from proxydoctor.session import ScanSession
|
|
from proxydoctor.reports import recover_latest
|
|
from proxydoctor import worker
|
|
path = tmp_path/'startup.json'
|
|
session = ScanSession('route', path, 'en')
|
|
original = os.fsync
|
|
calls = []
|
|
def interrupt_once(fd):
|
|
original(fd)
|
|
if not calls:
|
|
calls.append(True)
|
|
raise KeyboardInterrupt
|
|
monkeypatch.setattr(os, 'fsync', interrupt_once)
|
|
try:
|
|
with pytest.raises(KeyboardInterrupt):
|
|
with session:
|
|
raise AssertionError('Operation must not begin')
|
|
assert json.loads(path.read_text())['result'] == 'cancelled'
|
|
assert recover_latest(str(path)+'.events.jsonl')['result'] == 'cancelled'
|
|
assert session.store.stream.closed
|
|
finally:worker.reset()
|
|
|
|
|
|
def test_real_command_error_is_classified_without_leaking_stderr():
|
|
code, text, error = worker.local_command([sys.executable, '-B', '-c',
|
|
'import sys;sys.stderr.write("socket: Operation not permitted: synthetic-secret");sys.exit(1)'])
|
|
assert code == 1 and not text and error == 'PERMISSION_DENIED'
|
|
|
|
|
|
def test_trace_preserves_permission_and_missing_dependency(monkeypatch):
|
|
monkeypatch.setattr(routes.sys, 'platform', 'linux')
|
|
monkeypatch.setattr(routes.shutil, 'which', lambda *a, **k: '/usr/bin/traceroute')
|
|
monkeypatch.setattr(worker, 'local_command', lambda *a, **k: (1, '', 'PERMISSION_DENIED'))
|
|
result = {}; rows = []
|
|
assert routes.trace_method('127.0.0.1', lambda *a, **k: None, method='tcp', records=rows, summary=result) == 1
|
|
assert result == {'state': 'permission_denied', 'error_code': 'PERMISSION_DENIED'} and not rows
|
|
monkeypatch.setattr(routes.shutil, 'which', lambda *a, **k: None)
|
|
routes.trace_method('127.0.0.1', lambda *a, **k: None, method='tcp', summary=result)
|
|
assert result['state'] == 'dependency_missing'
|
|
|
|
|
|
def test_geo_metadata_bounded_validated_and_terminal_safe(monkeypatch):
|
|
locator = GeoLocator('en')
|
|
location = locator.remember('8.8.8.8', {'country': 'US', 'connection': {'asn': 15169, 'isp': '\x1b[31mGoogle\u202e'}})
|
|
locator.cache['8.8.8.8'] = location
|
|
result = locator.details('8.8.8.8')
|
|
assert result['asn'] == 15169 and result['source'] == 'https://ipwho.is/'
|
|
assert result['geography'] == 'database_estimate' and result['observed_at']
|
|
assert '\x1b' not in result['operator'] and '\u202e' not in result['operator']
|
|
assert locator.details('127.0.0.1')['asn'] is None
|
|
locator.lookups = 12
|
|
assert locator.details('1.1.1.1')['asn'] is None
|
|
|
|
|
|
def test_narrow_terminal_frame_preserves_all_text(monkeypatch, capsys):
|
|
monkeypatch.setattr(sys.stdout, 'isatty', lambda: True)
|
|
monkeypatch.setattr('proxydoctor.console.shutil.get_terminal_size', lambda: os.terminal_size((32, 24)))
|
|
out = Console('zh', 'never')
|
|
out.frame_open('公测版'); out.frame_keyvalue('字段', '位置数据'*25); out.frame_close()
|
|
lines = capsys.readouterr().out.splitlines()
|
|
assert all(width(line) == 32 for line in lines)
|
|
assert '位置数据'*25 in ''.join(line[1:-1].strip() for line in lines if line.startswith('║'))
|
|
assert clean('\u202eevil\u2069\x1b') == 'evil'
|