"""Isolated protocol regression runner; never contact/send to a live client.""" import contextlib import json import os from pathlib import Path import socket import sys import tempfile import threading import time import unittest from unittest import mock TARGET = Path(sys.argv[1]) OUT = Path(__file__).resolve().parent MODULES = sys.argv[2:] or [ 'test_native_protocol_pipeline', 'test_protocol_features', 'test_protocol_cross_machine', 'test_wecom_native_protocol', 'test_protocol_knowledge_integration', ] os.environ['QT_QPA_PLATFORM'] = 'offscreen' sys.path.insert(0, str(TARGET)) def blocked(*args, **kwargs): raise AssertionError('Audit disallows real network and native process access') internal = threading.local() original_pair = socket.socketpair original_connect = socket.socket.connect def socketpair(*args, **kwargs): # Windows asyncio needs a private socket pair only for its wakeup pipe. internal.wakeup = True try: return original_pair(*args, **kwargs) finally: internal.wakeup = False def connect(sock, address): if getattr(internal, 'wakeup', False): return original_connect(sock, address) return blocked() with tempfile.TemporaryDirectory(prefix='protocol-audit-') as folder, contextlib.ExitStack() as stack: import runtime_paths stack.enter_context(mock.patch.object(runtime_paths, 'application_data_dir', return_value=Path(folder))) stack.enter_context(mock.patch.object(socket, 'socketpair', new=socketpair)) stack.enter_context(mock.patch.object(socket.socket, 'connect', new=connect)) stack.enter_context(mock.patch.object(socket.socket, 'connect_ex', side_effect=blocked)) if (TARGET/'wecom_native_sender.py').is_file(): import wecom_native_sender stack.enter_context(mock.patch.object(wecom_native_sender, 'kernel', side_effect=blocked)) import send_lock send_lock._MUTEX_NAME = 'Local\\ProtocolAudit_' + str(os.getpid()) import test_support test_support.local_state_redirect.start() stack.callback(test_support.local_state_redirect.stop) test_support.queue_log_redirect.start() stack.callback(test_support.queue_log_redirect.stop) suite = unittest.defaultTestLoader.loadTestsFromNames(MODULES) started = time.monotonic() suffix = os.environ.get('AUDIT_OUTPUT_TAG') or ('boundary' if 'test_protocol_audit_boundaries' in MODULES else 'baseline') with (OUT / f'protocol-{suffix}.log').open('w', encoding='utf-8') as log: result = unittest.TextTestRunner(stream=log, verbosity=2).run(suite) summary = {'target': str(TARGET), 'modules': MODULES, 'tests': result.testsRun, 'failures': len(result.failures), 'errors': len(result.errors), 'skipped': len(result.skipped), 'seconds': round(time.monotonic()-started, 3), 'success': result.wasSuccessful()} (OUT / f'protocol-{suffix}.json').write_text(json.dumps(summary, indent=2, ensure_ascii=False), encoding='utf-8') print(json.dumps(summary, ensure_ascii=False)) for _, details in result.failures + result.errors: print(details) raise SystemExit(0 if result.wasSuccessful() else 1)