110 lines
5.9 KiB
Python
110 lines
5.9 KiB
Python
"""Launch/check the independently extracted package; native input is separate."""
|
|
import argparse
|
|
import datetime
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
|
|
root = Path(__file__).resolve().parents[1]
|
|
trial = root / '.local/contextual-prerelease-gui-20260911-v2'
|
|
base = root / 'harness/fixtures/staged-source-authoring/base'
|
|
oracle = root / '.local/staged-source-oracle-20260911/staged-source-authoring-contract.exe'
|
|
expected = {
|
|
'arcadia-studio.exe': '5657bab5c841939b66f901efe6c0ffb2d7cbbe8cc5f111a0ca3de8073d3846ce',
|
|
'arcadia-server.exe': 'efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665',
|
|
'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4',
|
|
}
|
|
def sha(p):
|
|
return hashlib.sha256(p.read_bytes()).hexdigest()
|
|
def inventory(folder):
|
|
found = {}
|
|
for p in folder.rglob('*'):
|
|
assert not p.is_symlink() and not (getattr(p.lstat(), 'st_file_attributes', 0) & 0x400), str(p)
|
|
if p.is_file():
|
|
found[p.relative_to(folder).as_posix()] = sha(p)
|
|
return found
|
|
def record(path, value):
|
|
with path.open('x', encoding='utf-8', newline='\n') as f:
|
|
json.dump(value, f, indent=2)
|
|
f.write('\n')
|
|
def now():
|
|
return datetime.datetime.now(datetime.timezone.utc).isoformat()
|
|
def minimal_environment(package):
|
|
parent = {key.upper(): value for key, value in os.environ.items()}
|
|
names = ('SystemRoot', 'SystemDrive', 'ProgramData', 'ALLUSERSPROFILE', 'PUBLIC')
|
|
assert all(parent.get(name.upper()) for name in names), 'Required standard Windows path is missing'
|
|
standard = {name: parent[name.upper()] for name in names}
|
|
assert all('%' not in value for value in standard.values()), 'Unexpanded standard Windows path'
|
|
system = standard['SystemRoot']
|
|
return {**standard, 'WINDIR': system,
|
|
'PATH': system + '\\System32;' + system,
|
|
'USERPROFILE': str(trial / 'profile'),
|
|
'LOCALAPPDATA': str(trial / 'profile/local'),
|
|
'APPDATA': str(trial / 'profile/roaming'),
|
|
'TEMP': str(trial / 'tmp'), 'TMP': str(trial / 'tmp')}
|
|
def run_oracle(package, args, label):
|
|
assert sha(oracle) == '967d9ba3c6fb3a7efb410833903ec94556ca2d48a67d5072c8bb160f40a00f9c'
|
|
env = minimal_environment(package)
|
|
env['PATH'] = str(package) + ';' + env['PATH']
|
|
result = subprocess.run([str(oracle), *args], env=env, capture_output=True)
|
|
(trial / (label + '.stdout.log')).write_bytes(result.stdout)
|
|
(trial / (label + '.stderr.log')).write_bytes(result.stderr)
|
|
record(trial / (label + '.json'), {'atUtc': now(), 'args': args, 'exitCode': result.returncode,
|
|
'oracleSha256': sha(oracle)})
|
|
assert result.returncode == 0, result.stdout.decode(errors='replace') + result.stderr.decode(errors='replace')
|
|
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('action', choices=['launch', 'saved', 'closed'])
|
|
parser.add_argument('--package', type=Path)
|
|
args = parser.parse_args()
|
|
if args.action == 'launch':
|
|
assert args.package and args.package.is_dir()
|
|
package = args.package.resolve()
|
|
assert package.name == 'ArcadiaStudio-0.2.0-preview.contextual.20260911-x86_64-pc-windows-gnullvm'
|
|
assert package == (root / '.local/contextual-prerelease-extraction2-20260911' / package.name).resolve()
|
|
review_path = root / '.local/contextual-prerelease-review-20260911/artifact-result.json'
|
|
review = json.loads(review_path.read_bytes())
|
|
assert review['status'] == 'PASS'
|
|
before = inventory(package)
|
|
assert before == review['archive']['files']
|
|
assert all(before[p] == h for p, h in expected.items())
|
|
trial.mkdir(exist_ok=False)
|
|
for folder in ('profile/local', 'profile/roaming', 'profile/Desktop', 'tmp'):
|
|
(trial / folder).mkdir(parents=True)
|
|
assert inventory(base) == {
|
|
'project.arcadia': 'aa844950ec4fb86f262a257e1fc370a26557ea7978d8a4cab78265037660234c',
|
|
'notes.arcadia': 'ad9de02963c20d1f43856455a797deb05ca674659e45f2c4b96b52783024f8bd'}
|
|
shutil.copytree(base, trial / 'work')
|
|
run_oracle(package, ['same', str(base / 'project.arcadia'), str(trial / 'work/project.arcadia')], 'baseline')
|
|
env = minimal_environment(package)
|
|
startup = subprocess.STARTUPINFO()
|
|
startup.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
startup.wShowWindow = 0
|
|
with (trial / 'stdout.log').open('xb') as out, (trial / 'stderr.log').open('xb') as err:
|
|
process = subprocess.Popen([str(package / 'arcadia-studio.exe')], cwd=package,
|
|
env=env, stdout=out, stderr=err, startupinfo=startup)
|
|
record(trial / 'package-before.json', before)
|
|
launch = {'atUtc': now(), 'pid': process.pid, 'package': str(package), 'environment': env,
|
|
'reviewSha256': sha(review_path), 'archiveSha256': review['archive']['sha256'],
|
|
'source': str(trial / 'work/project.arcadia'), 'scope': 'Fresh extracted package; native acceptance pending'}
|
|
record(trial / 'launch.json', launch)
|
|
print(json.dumps(launch, indent=2))
|
|
else:
|
|
launch = json.loads((trial / 'launch.json').read_bytes())
|
|
package = Path(launch['package'])
|
|
assert inventory(package) == json.loads((trial / 'package-before.json').read_bytes())
|
|
if args.action == 'saved':
|
|
destination = trial / 'checkpoint-first'
|
|
assert not destination.exists()
|
|
shutil.copytree(trial / 'work', destination)
|
|
run_oracle(package, ['check', 'lifeline', str(base / 'project.arcadia'),
|
|
str(destination / 'project.arcadia'), str(destination / 'project.arcadia')], 'saved')
|
|
record(trial / 'saved-files.json', inventory(destination))
|
|
else:
|
|
record(trial / 'package-after-close.json', {'atUtc': now(), 'files': len(inventory(package)),
|
|
'completeInventoryUnchanged': True})
|
|
print(json.dumps({'action': args.action, 'result': 'PASS', 'packageFiles': len(inventory(package))}))
|