Files
UniXNU/scripts/test-fileset-reference.py
T

109 lines
5.1 KiB
Python

"""A cached comparison kernel must belong to the requested build inputs."""
import importlib.util
import json
import os
from pathlib import Path
import tempfile
from types import SimpleNamespace
import unittest
from unittest.mock import patch
spec = importlib.util.spec_from_file_location(
'reference', Path(__file__).with_name('build-fileset-release-reference.py'))
reference = importlib.util.module_from_spec(spec)
spec.loader.exec_module(reference)
class ReferenceCacheTests(unittest.TestCase):
def test_lto_filelist_paths_are_relative_to_the_object_directory(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
(root / 'nonltolink.filelist').write_text('lastkernelconstructor.o\nnonlto.o\n')
self.assertEqual(reference.linked_objects(root, True),
[str(root / name) for name in
('lastkernelconstructor.o', 'nonlto.o', 'justlto.o')])
def test_builder_rebuilds_snapshot_as_lto_then_reuses_matching_output(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
files = ['.cache/xnu-work/osfmk/arm64/sleh.c',
'.cache/xnu-work/config/Private.exports',
'.cache/xnu-work/config/Private.arm64.exports',
'.cache/fakeroot/usr/include/header.h',
'build/corecrypto-2023/libcorecrypto_kernel_noasm-namespaced.a',
'build/libpthread-kernel/libpthread_kernel.a',
'build/armdt-platform/libArmDTPlatform.a',
'build/armcpu/libArmCpu.a']
for name in files:
path = root / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text('')
builds = []
def make(command, **kwargs):
if command[:2] == ['xcrun', 'nm']:
return SimpleNamespace(returncode=0, stdout='')
values = dict(arg.split('=', 1) for arg in command if '=' in arg)
mode = values['BUILD_LTO']
builds.append(mode)
output = Path(values['OBJROOT']) / 'RELEASE_ARM64_BCM2837'
output.mkdir(parents=True, exist_ok=True)
if mode == '1':
(output / 'nonltolink.filelist').write_text('')
(output / 'justlto.o').write_bytes(b'object')
else:
(output / 'link.filelist').write_text('')
(output / 'mach.release.bcm2837.unstripped').write_text(mode)
return SimpleNamespace(returncode=0)
argv = ['reference', '--tree', str(root)]
with patch.object(reference.subprocess, 'run', side_effect=make), \
patch.object(reference.subprocess, 'check_output', return_value='compiler'), \
patch('sys.argv', argv):
reference.main()
self.assertEqual(builds, ['0', '0'])
argv.append('--lto')
reference.main()
self.assertEqual(builds, ['0', '0', '1', '1'])
reference.main()
self.assertEqual(builds, ['0', '0', '1', '1'])
final = root / 'build/xnu/fileset-reference/mach.release.bcm2837.unstripped.noctf'
self.assertEqual(final.read_text(), '1')
def test_old_snapshot_cannot_satisfy_lto_request(self):
with tempfile.TemporaryDirectory() as directory:
final = Path(directory) / 'reference'
record = Path(directory) / 'record.json'
final.write_bytes(b'comparison kernel')
snapshot = {'mode': 'snapshot', 'source': 'old'}
self.assertFalse(reference.reusable(final, record, snapshot))
record.write_text(json.dumps({'inputs': snapshot, 'sha256': reference.file_hash(final)}))
self.assertTrue(reference.reusable(final, record, snapshot))
self.assertFalse(reference.reusable(final, record, dict(snapshot, mode='lto')))
self.assertFalse(reference.reusable(final, record, dict(snapshot, source='changed')))
final.write_bytes(b'corrupt kernel')
self.assertFalse(reference.reusable(final, record, snapshot))
def test_source_content_and_linked_sdk_headers_invalidate_cache(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source = root / 'source'
source.mkdir()
header = source / 'header.h'
header.write_text('old')
timestamp = header.stat().st_mtime_ns
first = reference.tree_hash(source)
header.write_text('new')
os.utime(header, ns=(timestamp, timestamp))
self.assertNotEqual(first, reference.tree_hash(source))
sdk = root / 'sdk'
sdk.mkdir()
(sdk / 'include').symlink_to(source, target_is_directory=True)
first = reference.tree_hash(sdk)
header.write_text('next')
self.assertNotEqual(first, reference.tree_hash(sdk))
if __name__ == '__main__':
unittest.main()