Files
docview/tests/portal/record_validation.py
T
2026-09-21 13:41:40 +09:00

113 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""Verify the URL-fix evidence and publish a current index with explicit history."""
from datetime import datetime, timezone
import hashlib
import json
from pathlib import Path
import xml.etree.ElementTree as ET
ROOT = Path(__file__).resolve().parents[2]
RESULTS = ROOT / 'tests/results/portal'
def sha(path):
with path.open('rb') as stream:
return hashlib.file_digest(stream, 'sha256').hexdigest()
def read(name):
return json.loads((RESULTS / name).read_text())
def main():
builds = {name: read(name + '-build-record.json') for name in ('arch', 'ubuntu')}
current_sources = {str(path.relative_to(ROOT)): sha(path) for directory in ('src', 'qml', 'cmake', 'resources')
for path in (ROOT / directory).rglob('*') if path.is_file() and '__pycache__' not in path.parts}
current_sources.update({name: sha(ROOT / name) for name in ('CMakeLists.txt', 'resources.qrc')})
for name, value in builds.items():
assert all(value['sourceSha256'].get(path) == digest for path, digest in current_sources.items())
for path in ('tests/test_web_qml.cpp', 'tests/webqml/tst_reader.qml'):
assert value['sourceSha256'][path] == sha(ROOT / path)
ctest = RESULTS / (name + '-ctest')
assert sha(ctest / 'tests.xml') == value['ctest']['junitSha256']
assert sha(ctest / 'LastTest.log') == value['ctest']['logSha256']
cases = ET.parse(ctest / 'tests.xml').findall('.//testcase')
assert len(cases) == 22 and all(row.find('failure') is None and row.find('skipped') is None for row in cases)
assert all(sha(ROOT / 'build' / name) == digest for name, digest in builds['arch']['binaries'].items())
package = read('ubuntu-package/report.json')
repeated = read('ubuntu-package/repeat-report.json')
verified = read('ubuntu-package/verification.json')
archive = ROOT / 'build-ubuntu-vm/packages' / package['archive']
assert package['success'] and repeated['success'] and verified['success']
assert package['archiveSha256'] == repeated['archiveSha256'] == sha(archive)
assert verified['archiveSha256'] == package['archiveSha256']
assert verified['allSizesModesAndHashesMatch'] and verified['rootOwnership']
assert verified['filesVerified'] == package['payloadFiles']
assert package['packagerSha256'] == sha(ROOT / 'tools/package_ubuntu.py')
assert package['executableSha256'] == builds['ubuntu']['installedBinaries']
assert package['manifestSha256'] == sha(RESULTS / 'ubuntu-package/package-manifest.json')
portal = {}
for platform, directory in {'x11': 'portal-x11-final', 'wayland': 'portal-wayland-fixed-keymap'}.items():
report = read(directory + '/report.json')
assert report['success'] and report['executablesUnchanged'] and not report['remainingTaggedChildren']
assert report['executables'] == package['executableSha256']
assert report['packageManifestSha256'] == package['manifestSha256']
assert report['runnerSha256'] == sha(RESULTS / directory / 'runner-at-start.py')
assert report['portalResponses'] == ['2', '0', '0', '0', '0']
assert [row['case'] for row in report['cases']] == ['cancel', 'pdf', 'html', 'htmlzip', 'epub']
assert all(row['focusRestored'] for row in report['cases'])
portal[platform] = {key: report[key] for key in ('success', 'platform', 'executables', 'portalResponses', 'cases', 'scope')}
lifecycle = {phase: read('package-vm/' + phase + '/report.json') for phase in ('install', 'smoke', 'remove')}
assert all(row['success'] and row['archiveSha256'] == package['archiveSha256'] for row in lifecycle.values())
assert lifecycle['install']['executables'] == package['executableSha256']
assert lifecycle['install']['installationMode'] == 'upgrade'
assert lifecycle['install']['runnerSha256'] == sha(ROOT / 'tests/ubuntu_vm/clean_package.py')
assert lifecycle['smoke']['smokeConditions'] == 12
assert lifecycle['remove']['payloadRemoved'] and lifecycle['remove']['kernelRestrictionUnchanged']
performance = read('performance-suite/summary.json')
assert performance['success'] and len(performance['cases']) == 10
assert all(builds['arch']['binaries'][name] == digest for name, digest in performance['buildSha256'].items())
for row in performance['cases']:
assert sha(RESULTS / 'performance-suite' / row['record']) == row['recordSha256']
assert performance['interactionRecordSha256'] == sha(RESULTS / 'performance-suite/interaction/record.json')
assert performance['stressRecordSha256'] == sha(RESULTS / 'performance-suite/stress/report.json')
prior = read('prior-validation-record.json')
record = {
'schemaVersion': 2, 'recordedAtUtc': datetime.now(timezone.utc).isoformat(),
'scope': 'Current URL-fix build: Arch/Ubuntu full CTest, Ubuntu package and XDG/GTK file chooser integration; Arch ten-condition performance, interaction and 1 GiB PDF stress',
'ctestSkipScope': 'All 22 CTest groups pass. Each App group explicitly skips its opt-in performance case; Ubuntu Python 3.12 skips 5 zstd provenance cases. These are not counted as executed acceptance tests.',
'goalComplete': False, 'sourceSha256': current_sources,
'validationToolsSha256': {name: sha(ROOT / name) for name in (
'tests/portal/record_build.py', 'tests/portal/record_validation.py', 'tests/portal/run.py',
'tests/portal/run_performance.py', 'tests/portal/summarize_performance.py', 'tests/ubuntu_vm/clean_package.py')},
'executables': {name: builds['arch']['binaries'][name] for name in package['executableSha256']},
'builds': builds, 'ubuntuPackage': package, 'portal': portal,
'packageLifecycle': lifecycle,
'performance': performance,
'historicalEvidence': {
'record': 'tests/results/portal/prior-validation-record.json',
'sha256': sha(RESULTS / 'prior-validation-record.json'),
'changedCompiledSources': [name for name, digest in current_sources.items() if prior['sourceSha256'].get(name) != digest],
'unchangedArchWorkers': [name for name in ('docview-pdf-worker', 'docview-archive-worker')
if prior['executables'][name] == builds['arch']['binaries'][name]],
'scope': 'Prior full-app performance, GPU, IME, high-density PDF and package measurements are versioned history. Current ten-condition performance and 1 GiB stress are recorded separately above.',
},
'remainingAcceptance': [
'Windows 11 native MSVC/Qt build, LPAC/pipe/PE execution and installer',
'Target-OS physical GPU/display/input, reference hardware and long-duration acceptance',
'Human G-RENDER reference-image approval',
'Complete notices/corresponding sources, public license and release distribution decision',
],
'evidenceSha256': {str(path.relative_to(ROOT)): sha(path) for path in sorted(RESULTS.rglob('*'))
if path.is_file() and path.suffix != '.pyc' and path != RESULTS / 'record.json'},
}
encoded = json.dumps(record, ensure_ascii=False, indent=2) + '\n'
(RESULTS / 'record.json').write_text(encoded)
(ROOT / 'docs/validation-record.json').write_text(encoded)
print(json.dumps({'archCtestGroups': 22, 'ubuntuCtestGroups': 22, 'portalCases': 10,
'packageSmokeConditions': 12, 'performanceConditions': 10, 'goalComplete': False}))
if __name__ == '__main__':
main()