#!/usr/bin/env python3 """Run corrected RI, transparency and original CMYK probes plus DocView CTest.""" import argparse import hashlib import json import os from pathlib import Path import platform import shutil import subprocess import sys import time ROOT = Path(__file__).resolve().parents[2] def sha(path): with path.open('rb') as stream: return hashlib.file_digest(stream, 'sha256').hexdigest() def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--library', type=Path, required=True) parser.add_argument('--build-dir', type=Path, required=True) parser.add_argument('--output', type=Path, required=True) args = parser.parse_args() library, build = args.library.resolve(), args.build_dir.resolve() binaries = [library, ROOT / '.deps/pdfium/lib/libpdfium.so'] + [build / name for name in ('docview', 'docview-pdf-worker', 'docview-archive-worker', 'pdf-worker-evidence')] identities = {str(path): sha(path) for path in binaries} environment = os.environ.copy() assert not environment.get('LD_PRELOAD') and not environment.get('LD_AUDIT') assert not environment.get('QTWEBENGINE_DISABLE_SANDBOX') environment.pop('WAYLAND_DISPLAY', None) environment.update(LD_LIBRARY_PATH=str(library.parent) + ( ':' + environment['LD_LIBRARY_PATH'] if environment.get('LD_LIBRARY_PATH') else ''), QT_QPA_PLATFORM='xcb', QT_QUICK_BACKEND='software', QTWEBENGINE_CHROMIUM_FLAGS='--disable-gpu', QT_SCALE_FACTOR='1', QT_AUTO_SCREEN_SCALE_FACTOR='0', XDG_SESSION_TYPE='x11') output = args.output.resolve() output.mkdir(parents=True, exist_ok=False) report = {'schemaVersion': 1, 'candidateTestsPass': False, 'acceptanceComplete': False, 'platform': platform.platform(), 'osRelease': platform.freedesktop_os_release(), 'inputs': identities, 'runnerSha256': sha(Path(__file__)), 'commands': [], 'productionDependencyReplaced': False, 'scope': 'Fixed candidate selected only for this test process tree. Generated fixtures and corrected stream-entry RI expectations; no physical display, Windows, human golden or release acceptance.'} def run(label, command): start = time.monotonic() log = output / (label + '.log') with log.open('w') as stream: result = subprocess.run(command, cwd=ROOT, env=environment, stdout=stream, stderr=subprocess.STDOUT, timeout=900) report['commands'].append({'name': label, 'command': command, 'exitCode': result.returncode, 'seconds': time.monotonic() - start, 'logSha256': sha(log)}) print(label, result.returncode, flush=True) return result.returncode try: linked = subprocess.run(['ldd', str(build / 'docview-pdf-worker')], env=environment, capture_output=True, text=True, check=True).stdout assert str(library) in linked and 'not found' not in linked (output / 'worker-ldd.txt').write_text(linked) run('cmyk', [sys.executable, str(ROOT / 'tests/cmyk_lut/run.py'), '--build-dir', str(build), '--output', str(output / 'cmyk')]) run('intents', [sys.executable, str(ROOT / 'tests/cmyk_lut/intents.py'), '--build-dir', str(build), '--pdfium-library', str(library), '--corpus', str(ROOT / 'tests/fixtures/pdf/rendering-intents-context'), '--scales', '.5', '1', '4', '--output', str(output / 'intents')]) run('transparency', [sys.executable, str(ROOT / 'tests/cmyk_lut/transparency.py'), '--build-dir', str(build), '--pdfium-library', str(library), '--scales', '.5', '1', '2', '--output', str(output / 'transparency')]) ctest_status = run('ctest', ['xvfb-run', '-a', '-s', '-screen 0 1100x760x24', 'dbus-run-session', '--', 'ctest', '--test-dir', str(build), '--output-on-failure', '--output-junit', str(output / 'tests.xml')]) shutil.copyfile(build / 'Testing/Temporary/LastTest.log', output / 'LastTest.log') reports = {name: json.loads((output / name / 'report.json').read_text()) for name in ('cmyk', 'intents', 'transparency')} report['cmykSuccess'] = reports['cmyk']['success'] report['correctedOracle'] = reports['intents']['oracleRevision'] == 2 and not reports['intents']['oracleKnownIssue'] for name in ('intents', 'transparency'): data = reports[name] report[name] = {key: data.get(key, False) for key in ('pdfiumSuccess', 'popplerSuccess', 'fixtureValidationSuccess', 'binariesUnchanged', 'originalUnchanged')} report[name]['probeCount'] = sum(len(row['probes']) for row in data['scales']) report['ctestSuccess'] = ctest_status == 0 report['allBinaryInputsUnchanged'] = all(sha(Path(path)) == value for path, value in identities.items()) report['candidateTestsPass'] = all((report['cmykSuccess'], report['correctedOracle'], report['ctestSuccess'], report['allBinaryInputsUnchanged'], *[ report[name][key] for name in ('intents', 'transparency') for key in ('pdfiumSuccess', 'fixtureValidationSuccess', 'binariesUnchanged', 'originalUnchanged')])) report['comparisonAgreement'] = all(report[name]['popplerSuccess'] for name in ('intents', 'transparency')) finally: report['evidenceSha256'] = {str(path.relative_to(output)): sha(path) for path in sorted(output.rglob('*')) if path.is_file()} (output / 'report.json').write_text(json.dumps(report, indent=2) + '\n') print(json.dumps({key: report.get(key) for key in ('candidateTestsPass', 'comparisonAgreement', 'allBinaryInputsUnchanged', 'acceptanceComplete')})) if not report['candidateTestsPass']: raise SystemExit('Candidate regression failed; all individual outcomes are retained.') if __name__ == '__main__': main()