blob: 581762f38c76e2fd19224c9586ea0386a5f9bdd1 [file] [log] [blame]
# Copyright 2016 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Recipe for building Zircon."""
import re
from recipe_engine.config import Enum
from recipe_engine.recipe_api import Property, StepFailure
DEPS = [
'infra/cipd',
'infra/jiri',
'infra/qemu',
'recipe_engine/context',
'recipe_engine/file',
'recipe_engine/json',
'recipe_engine/path',
'recipe_engine/platform',
'recipe_engine/properties',
'recipe_engine/raw_io',
'recipe_engine/source_manifest',
'recipe_engine/step',
'recipe_engine/tempfile',
]
TARGETS = [
'zircon-qemu-arm64',
'zircon-pc-x86-64',
'zircon-rpi3-arm64',
'zircon-hikey960-arm64',
'pc-x86-64-test',
'qemu-virt-a53-test'
]
# toolchain: (['make', 'args'], 'builddir-suffix')
TOOLCHAINS = {
'gcc': ([], ''),
'clang': (['USE_CLANG=true'], '-clang'),
'asan': (['USE_ASAN=true'], '-asan'),
'lto': (['USE_LTO=true', 'USE_THINLTO=false'], '-lto'),
'thinlto': (['USE_LTO=true', 'USE_THINLTO=true'], '-thinlto'),
}
# Test summary from the core tests, which run directly from userboot.
CORE_TESTS_MATCH = r'CASES: +(\d+) +SUCCESS: +(\d+) +FAILED: +(?P<failed>\d+)'
# Test summary from the runtests command on a booted system.
BOOTED_TESTS_MATCH = r'SUMMARY: Ran (\d+) tests: (?P<failed>\d+) failed'
PROPERTIES = {
'category': Property(kind=str, help='Build category', default=None),
'patch_gerrit_url': Property(kind=str, help='Gerrit host', default=None),
'patch_project': Property(kind=str, help='Gerrit project', default=None),
'patch_ref': Property(kind=str, help='Gerrit patch ref', default=None),
'patch_storage': Property(kind=str, help='Patch location', default=None),
'patch_repository_url': Property(kind=str, help='URL to a Git repository',
default=None),
'project': Property(kind=str, help='Jiri remote manifest project', default=None),
'manifest': Property(kind=str, help='Jiri manifest to use'),
'remote': Property(kind=str, help='Remote manifest repository'),
'target': Property(kind=Enum(*TARGETS), help='Target to build'),
'toolchain': Property(kind=Enum(*(TOOLCHAINS.keys())),
help='Toolchain to use'),
'run_tests' : Property(kind=bool, help='Run tests in qemu after building', default=True)
}
def RunTests(api, name, build_dir, *args, **kwargs):
step_result = None
failure_reason = None
try:
step_result = api.qemu.run(name, *args, **kwargs)
except StepFailure as error:
step_result = error.result
if error.retcode == 2:
failure_reason = 'Test timed out'
else:
raise api.step.InfraFailure('QEMU failure')
qemu_log = step_result.stdout
step_result.presentation.logs['qemu.stdout'] = qemu_log.splitlines()
if failure_reason is None:
m = re.search(kwargs['shutdown_pattern'], qemu_log)
if not m:
raise api.step.InfraFailure('Test output missing')
elif int(m.group('failed')) > 0:
step_result.presentation.status = api.step.FAILURE
failure_reason = m.group(0)
if failure_reason is not None:
symbolize_cmd = [
api.path['start_dir'].join('zircon', 'scripts', 'symbolize'),
'--no-echo',
'--build-dir', build_dir,
]
symbolize_result = api.step('symbolize', symbolize_cmd,
stdin=api.raw_io.input(data=qemu_log),
stdout=api.raw_io.output(),
step_test_data=lambda: api.raw_io.test_api.stream_output(''))
symbolized_lines = symbolize_result.stdout.splitlines()
if symbolized_lines:
symbolize_result.presentation.logs['symbolized backtrace'] = symbolized_lines
symbolize_result.presentation.status = api.step.FAILURE
raise api.step.StepFailure(failure_reason)
def RunSteps(api, category, patch_gerrit_url, patch_project, patch_ref,
patch_storage, patch_repository_url, project, manifest, remote,
target, toolchain, run_tests):
api.jiri.ensure_jiri()
with api.context(infra_steps=True):
api.jiri.checkout(manifest, remote, patch_ref, patch_gerrit_url, project)
revision = api.jiri.project(['zircon']).json.output[0]['revision']
api.step.active_result.presentation.properties['got_revision'] = revision
if patch_ref:
api.jiri.update(gc=True, local_manifest=True)
tmp_dir = api.path['tmp_base'].join('zircon_tmp')
api.file.ensure_directory('makedirs tmp', tmp_dir)
path = tmp_dir.join('autorun')
autorun = ['msleep 500', 'runtests']
api.file.write_text('write autorun', path, '\n'.join(autorun))
api.step.active_result.presentation.logs['autorun.sh'] = autorun
tc_args, tc_suffix = TOOLCHAINS[toolchain]
build_args = [
'make',
'-j%s' % api.platform.cpu_count,
target
] + tc_args
if toolchain == 'thinlto':
build_args.append('THINLTO_CACHE_DIR=' +
str(api.path['cache'].join('thinlto')))
with api.context(cwd=api.path['start_dir'].join('zircon'),
env={'USER_AUTORUN': path}):
api.step('build', build_args)
if run_tests:
api.qemu.ensure_qemu()
arch = {
'zircon-hikey960-arm64': 'aarch64',
'zircon-rpi3-arm64': 'aarch64',
'zircon-qemu-arm64': 'aarch64',
'zircon-pc-x86-64': 'x86_64',
'pc-x86-64-test': 'x86_64',
'qemu-virt-a53-test': 'aarch64',
}[target]
build_dir = api.path['start_dir'].join('zircon', 'build-%s' % target + tc_suffix)
bootdata_path = build_dir.join('bootdata.bin')
image_path = build_dir.join({
'aarch64': 'zircon.elf',
'x86_64': 'zircon.bin',
}[arch])
if run_tests:
# Run core tests with userboot.
RunTests(api, 'run core tests', build_dir, arch, image_path, kvm=True,
initrd=bootdata_path, cmdline='userboot=bin/core-tests',
shutdown_pattern=CORE_TESTS_MATCH, timeout=300, step_test_data=lambda:
api.raw_io.test_api.stream_output('CASES: 1 SUCCESS: 1 FAILED: 0'))
# Boot and run tests.
RunTests(api, 'run booted tests', build_dir, arch, image_path, kvm=True,
initrd=bootdata_path, shutdown_pattern=BOOTED_TESTS_MATCH, timeout=1200,
step_test_data=lambda:
api.raw_io.test_api.stream_output('SUMMARY: Ran 2 tests: 1 failed'))
def GenTests(api):
yield (api.test('ci') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='gcc') +
api.step_data('run booted tests',
api.raw_io.stream_output('SUMMARY: Ran 2 tests: 0 failed')))
yield (api.test('asan') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='asan') +
api.step_data('run booted tests',
api.raw_io.stream_output('SUMMARY: Ran 2 tests: 0 failed')))
yield (api.test('lto') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='lto') +
api.step_data('run booted tests',
api.raw_io.stream_output('SUMMARY: Ran 2 tests: 0 failed')))
yield (api.test('thinlto') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='thinlto') +
api.step_data('run booted tests',
api.raw_io.stream_output('SUMMARY: Ran 2 tests: 0 failed')))
yield (api.test('cq_try') +
api.properties.tryserver(
gerrit_project='zircon',
patch_gerrit_url='fuchsia-review.googlesource.com',
project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='clang'))
yield (api.test('no_run_tests') +
api.properties.tryserver(
project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='clang',
run_tests=False))
yield (api.test('build_rpi') +
api.properties.tryserver(
project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-rpi3-arm64',
toolchain='clang',
run_tests=False))
yield (api.test('failed_qemu') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='gcc') +
api.step_data('run booted tests', retcode=1))
yield (api.test('qemu_timeout') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='gcc') +
api.step_data('run booted tests', retcode=2))
yield (api.test('test_ouput') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='gcc') +
api.step_data('run booted tests', api.raw_io.stream_output('')))
yield (api.test('symbolized_output') +
api.properties(project='zircon',
manifest='manifest',
remote='https://fuchsia.googlesource.com/zircon',
target='zircon-pc-x86-64',
toolchain='gcc') +
api.step_data('symbolize', api.raw_io.stream_output('bt1\nbt2\n')))