| # Copyright 2015 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from recipe_engine.recipe_api import Property |
| |
| DEPS = [ |
| 'chromium', |
| 'depot_tools/bot_update', |
| 'depot_tools/depot_tools', |
| 'depot_tools/gclient', |
| 'recipe_engine/context', |
| 'recipe_engine/file', |
| 'recipe_engine/path', |
| 'recipe_engine/platform', |
| 'recipe_engine/properties', |
| 'recipe_engine/python', |
| 'recipe_engine/step', |
| 'test_utils', |
| ] |
| |
| |
| def _GetHostToolSuffix(platform): |
| if platform.is_linux: |
| if platform.bits == 64: |
| return 'linux64' |
| elif platform.is_mac: |
| return 'mac' |
| elif platform.is_win: |
| return 'win32' |
| raise ValueError('unknown platform') # pragma: no cover |
| |
| |
| def _GetHostExeSuffix(platform): |
| if platform.is_win: |
| return '.exe' |
| return '' |
| |
| |
| def _WindowsCMakeWorkaround(path): |
| # CMake does not allow backslashes in several path variables. It writes the |
| # string out to a cmake file with configure_file() and fails to escape it |
| # correctly. See https://gitlab.kitware.com/cmake/cmake/issues/16254. |
| return str(path).replace('\\', '/') |
| |
| |
| def _GetHostCMakeArgs(platform, bot_utils): |
| args = {} |
| if platform.is_win: |
| args['CMAKE_ASM_NASM_COMPILER'] = _WindowsCMakeWorkaround( |
| bot_utils.join('yasm-win32.exe')) |
| args['PERL_EXECUTABLE'] = bot_utils.join('perl-win32', 'perl', 'bin', |
| 'perl.exe') |
| return args |
| |
| |
| def _HasToken(buildername, token): |
| # Builder names are a sequence of tokens separated by underscores. |
| return '_' + token + '_' in '_' + buildername + '_' |
| |
| |
| def _AppendFlags(args, key, flags): |
| if key in args: |
| args[key] += ' ' + flags |
| else: |
| args[key] = flags |
| |
| |
| def _GetBuilderEnv(buildername): |
| env = {} |
| if _HasToken(buildername, 'vs2017'): |
| env['GYP_MSVS_VERSION'] = '2017' |
| return env |
| |
| |
| def _UsesClang(buildername): |
| return any( |
| _HasToken(buildername, token) for token in ('asan', 'clang', 'fuzz')) |
| |
| |
| def _GetGclientVars(buildername): |
| ret = {} |
| if _UsesClang(buildername): |
| ret['checkout_clang'] = 'True' |
| if _HasToken(buildername, 'sde'): |
| ret['checkout_sde'] = 'True' |
| if _HasToken(buildername, 'fuzz'): |
| ret['checkout_fuzzer'] = 'True' |
| return ret |
| |
| |
| def _GetTargetCMakeArgs(buildername, checkout, ninja_path, platform): |
| bot_utils = checkout.join('util', 'bot') |
| args = {'CMAKE_MAKE_PROGRAM': ninja_path} |
| if _HasToken(buildername, 'shared'): |
| args['BUILD_SHARED_LIBS'] = '1' |
| if _HasToken(buildername, 'rel'): |
| args['CMAKE_BUILD_TYPE'] = 'Release' |
| # 32-bit builds are cross-compiled on the 64-bit bots. |
| if _HasToken(buildername, 'win32') and _UsesClang(buildername): |
| args['CMAKE_SYSTEM_NAME'] = 'Windows' |
| args['CMAKE_SYSTEM_PROCESSOR'] = 'x86' |
| _AppendFlags(args, 'CMAKE_CXX_FLAGS', '-m32 -msse2') |
| _AppendFlags(args, 'CMAKE_C_FLAGS', '-m32 -msse2') |
| if _HasToken(buildername, 'linux32'): |
| args['CMAKE_SYSTEM_NAME'] = 'Linux' |
| args['CMAKE_SYSTEM_PROCESSOR'] = 'x86' |
| _AppendFlags(args, 'CMAKE_CXX_FLAGS', '-m32 -msse2') |
| _AppendFlags(args, 'CMAKE_C_FLAGS', '-m32 -msse2') |
| _AppendFlags(args, 'CMAKE_ASM_FLAGS', '-m32 -msse2') |
| if _HasToken(buildername, 'noasm'): |
| args['OPENSSL_NO_ASM'] = '1' |
| if _UsesClang(buildername): |
| if platform.is_win: |
| args['CMAKE_C_COMPILER'] = _WindowsCMakeWorkaround( |
| bot_utils.join('llvm-build', 'bin', 'clang-cl.exe')) |
| args['CMAKE_CXX_COMPILER'] = _WindowsCMakeWorkaround( |
| bot_utils.join('llvm-build', 'bin', 'clang-cl.exe')) |
| else: |
| args['CMAKE_C_COMPILER'] = bot_utils.join('llvm-build', 'bin', 'clang') |
| args['CMAKE_CXX_COMPILER'] = bot_utils.join('llvm-build', 'bin', |
| 'clang++') |
| if _HasToken(buildername, 'asan'): |
| args['ASAN'] = '1' |
| if _HasToken(buildername, 'cfi'): |
| args['CFI'] = '1' |
| if _HasToken(buildername, 'small'): |
| _AppendFlags(args, 'CMAKE_CXX_FLAGS', '-DOPENSSL_SMALL=1') |
| _AppendFlags(args, 'CMAKE_C_FLAGS', '-DOPENSSL_SMALL=1') |
| if _HasToken(buildername, 'nothreads'): |
| _AppendFlags(args, 'CMAKE_CXX_FLAGS', '-DOPENSSL_NO_THREADS=1') |
| _AppendFlags(args, 'CMAKE_C_FLAGS', '-DOPENSSL_NO_THREADS=1') |
| if _HasToken(buildername, 'android'): |
| args['CMAKE_TOOLCHAIN_FILE'] = checkout.join('third_party', 'android-cmake', |
| 'android.toolchain.cmake') |
| args['ANDROID_NDK'] = bot_utils.join('android_tools', 'ndk') |
| if _HasToken(buildername, 'arm'): |
| args['ANDROID_ABI'] = 'armeabi-v7a' |
| args['ANDROID_NATIVE_API_LEVEL'] = 16 |
| elif _HasToken(buildername, 'aarch64'): |
| args['ANDROID_ABI'] = 'arm64-v8a' |
| args['ANDROID_NATIVE_API_LEVEL'] = 21 |
| if _HasToken(buildername, 'fips'): |
| args['FIPS'] = '1' |
| if _HasToken(buildername, 'ios'): |
| args['CMAKE_OSX_SYSROOT'] = 'iphoneos' |
| args['CMAKE_OSX_ARCHITECTURES'] = 'armv7' |
| if _HasToken(buildername, 'ios64'): |
| args['CMAKE_OSX_SYSROOT'] = 'iphoneos' |
| args['CMAKE_OSX_ARCHITECTURES'] = 'arm64' |
| if _HasToken(buildername, 'fuzz'): |
| args['FUZZ'] = '1' |
| args['LIBFUZZER_FROM_DEPS'] = '1' |
| # Pick one builder to build with the C++ runtime allowed. The default |
| # configuration does not compile-check pure virtuals. |
| if buildername == 'linux': |
| args['BORINGSSL_ALLOW_CXX_RUNTIME'] = '1' |
| return args |
| |
| |
| def _GetTargetMSVCPrefix(buildername, bot_utils): |
| if _HasToken(buildername, 'win32'): |
| return ['python', bot_utils.join('vs_env.py'), 'x86'] |
| if _HasToken(buildername, 'win64'): |
| return ['python', bot_utils.join('vs_env.py'), 'x64'] |
| return [] |
| |
| |
| def _GetTargetEnv(buildername, bot_utils): |
| env = {} |
| if _HasToken(buildername, 'asan'): |
| env['ASAN_OPTIONS'] = 'detect_stack_use_after_return=1' |
| env['ASAN_SYMBOLIZER_PATH'] = bot_utils.join('llvm-build', 'bin', |
| 'llvm-symbolizer') |
| return env |
| |
| |
| def _LogFailingTests(api, deferred): |
| if not deferred.is_ok: |
| error = deferred.get_error() |
| if hasattr(error.result, 'test_utils'): |
| r = error.result.test_utils.test_results |
| p = error.result.presentation |
| p.step_text += api.test_utils.format_step_text([ |
| ['unexpected_failures:', r.unexpected_failures.keys()], |
| ]) |
| |
| |
| PROPERTIES = { |
| 'buildername': Property(), |
| } |
| |
| |
| def RunSteps(api, buildername): |
| with api.context(env=_GetBuilderEnv(buildername)): |
| # Sync and pull in everything. |
| api.gclient.set_config('boringssl') |
| if _HasToken(buildername, 'android'): |
| api.gclient.c.target_os.add('android') |
| api.gclient.c.solutions[0].custom_vars = _GetGclientVars(buildername) |
| api.bot_update.ensure_checkout() |
| api.gclient.runhooks() |
| |
| # Set up paths. |
| bot_utils = api.path['checkout'].join('util', 'bot') |
| go_env = bot_utils.join('go', 'env.py') |
| adb_path = bot_utils.join('android_tools', 'sdk', 'platform-tools', 'adb') |
| sde_path = bot_utils.join('sde-' + _GetHostToolSuffix(api.platform)) |
| build_dir = api.path['checkout'].join('build') |
| runner_dir = api.path['checkout'].join('ssl', 'test', 'runner') |
| |
| # CMake is stateful, so do a clean build. BoringSSL builds quickly enough |
| # that this isn't a concern. |
| api.file.rmtree('clean', build_dir) |
| api.file.ensure_directory('mkdir', build_dir) |
| |
| # If building with MSVC, all commands must run with an environment wrapper. |
| # This is necessary both to find the toolchain and the runtime dlls. Rather |
| # than copy the runtime to every directory where a binary is installed, just |
| # run the tests with the toolchain prefix as well. |
| msvc_prefix = _GetTargetMSVCPrefix(buildername, bot_utils) |
| |
| # Build BoringSSL itself. |
| cmake = bot_utils.join('cmake-' + _GetHostToolSuffix(api.platform), 'bin', |
| 'cmake' + _GetHostExeSuffix(api.platform)) |
| cmake_args = _GetHostCMakeArgs(api.platform, bot_utils) |
| cmake_args.update( |
| _GetTargetCMakeArgs(buildername, api.path['checkout'], |
| api.depot_tools.ninja_path, api.platform)) |
| with api.context(cwd=build_dir): |
| api.python( |
| 'cmake', go_env, msvc_prefix + [cmake, '-GNinja'] + |
| ['-D%s=%s' % (k, v) |
| for (k, v) in sorted(cmake_args.items())] + [api.path['checkout']]) |
| api.python('ninja', go_env, |
| msvc_prefix + [api.depot_tools.ninja_path, '-C', build_dir]) |
| |
| if _HasToken(buildername, 'compile'): |
| return |
| |
| with api.step.defer_results(): |
| # The default Linux build may not depend on the C++ runtime. This is easy |
| # to check when building shared libraries. |
| if buildername == 'linux_shared': |
| api.python('check imported libraries', go_env, [ |
| 'go', 'run', |
| api.path['checkout'].join('util', 'check_imported_libraries.go'), |
| build_dir.join('crypto', 'libcrypto.so'), |
| build_dir.join('ssl', 'libssl.so') |
| ]) |
| |
| env = _GetTargetEnv(buildername, bot_utils) |
| |
| # Run the unit tests. |
| with api.context(cwd=api.path['checkout'], env=env): |
| all_tests_args = [] |
| if _HasToken(buildername, 'sde'): |
| all_tests_args += ['-sde', '-sde-path', sde_path.join('sde')] |
| if _HasToken(buildername, 'android'): |
| deferred = api.python('unit tests', go_env, [ |
| 'go', 'run', |
| api.path.join('util', 'run_android_tests.go'), '-build-dir', |
| build_dir, '-adb', adb_path, '-suite', 'unit', '-all-tests-args', |
| ' '.join(all_tests_args), '-json-output', |
| api.test_utils.test_results() |
| ]) |
| else: |
| deferred = api.python('unit tests', go_env, msvc_prefix + [ |
| 'go', 'run', |
| api.path.join('util', 'all_tests.go'), '-json-output', |
| api.test_utils.test_results() |
| ] + all_tests_args) |
| _LogFailingTests(api, deferred) |
| |
| # Run the SSL tests. |
| if not _HasToken(buildername, 'sde'): |
| runner_args = ['-pipe'] |
| if _HasToken(buildername, 'fuzz'): |
| runner_args += ['-fuzzer', '-shim-config', 'fuzzer_mode.json'] |
| # Limit the number of workers on Android and Mac, to avoid flakiness. |
| # https://crbug.com/boringssl/192 |
| # https://crbug.com/boringssl/199 |
| if api.platform.is_mac or _HasToken(buildername, 'android'): |
| runner_args += ['-num-workers', '1'] |
| if _HasToken(buildername, 'android'): |
| with api.context(cwd=api.path['checkout'], env=env): |
| deferred = api.python('ssl tests', go_env, [ |
| 'go', 'run', |
| api.path.join('util', 'run_android_tests.go'), '-build-dir', |
| build_dir, '-adb', adb_path, '-suite', 'ssl', '-runner-args', |
| ' '.join(runner_args), '-json-output', |
| api.test_utils.test_results() |
| ]) |
| else: |
| with api.context(cwd=runner_dir, env=env): |
| deferred = api.python( |
| 'ssl tests', go_env, msvc_prefix + |
| ['go', 'test', '-json-output', |
| api.test_utils.test_results()] + runner_args) |
| _LogFailingTests(api, deferred) |
| |
| |
| def GenTests(api): |
| tests = [ |
| # To ensure full test coverage, add a test for each builder configuration. |
| ('linux', api.platform('linux', 64)), |
| ('linux_shared', api.platform('linux', 64)), |
| ('linux32', api.platform('linux', 64)), |
| ('linux_noasm_asan', api.platform('linux', 64)), |
| ('linux_small', api.platform('linux', 64)), |
| ('linux_nothreads', api.platform('linux', 64)), |
| ('linux_rel', api.platform('linux', 64)), |
| ('linux32_rel', api.platform('linux', 64)), |
| ('linux_clang_rel', api.platform('linux', 64)), |
| ('linux_clang_cfi', api.platform('linux', 64)), |
| ('linux_fuzz', api.platform('linux', 64)), |
| ('linux_fips', api.platform('linux', 64)), |
| ('linux_fips_rel', api.platform('linux', 64)), |
| ('linux_fips_clang', api.platform('linux', 64)), |
| ('linux_fips_clang_rel', api.platform('linux', 64)), |
| ('linux_fips_noasm_asan', api.platform('linux', 64)), |
| ('mac', api.platform('mac', 64)), |
| ('mac_small', api.platform('mac', 64)), |
| ('mac_rel', api.platform('mac', 64)), |
| ('win32', api.platform('win', 64)), |
| ('win32_small', api.platform('win', 64)), |
| ('win32_rel', api.platform('win', 64)), |
| ('win32_vs2017', api.platform('win', 64)), |
| ('win32_vs2017_clang', api.platform('win', 64)), |
| ('win64', api.platform('win', 64)), |
| ('win64_small', api.platform('win', 64)), |
| ('win64_rel', api.platform('win', 64)), |
| ('win64_vs2017', api.platform('win', 64)), |
| ('win64_vs2017_clang', api.platform('win', 64)), |
| ('android_arm', api.platform('linux', 64)), |
| ('android_arm_rel', api.platform('linux', 64)), |
| ('android_aarch64', api.platform('linux', 64)), |
| ('android_aarch64_rel', api.platform('linux', 64)), |
| # This is not a builder configuration, but it ensures _AppendFlags handles |
| # appending to CMAKE_CXX_FLAGS when there is already a value in there. |
| ('linux_nothreads_small', api.platform('linux', 64)), |
| ] |
| for (buildername, host_platform) in tests: |
| yield ( |
| api.test(buildername) + |
| host_platform + |
| api.properties.generic(mastername='client.boringssl', |
| buildername=buildername, bot_id='bot_id') + |
| api.override_step_data('unit tests', |
| api.test_utils.canned_test_output(True)) + |
| api.override_step_data('ssl tests', |
| api.test_utils.canned_test_output(True)) |
| ) |
| |
| compile_only_tests = [ |
| ('ios_compile', api.platform('mac', 64)), |
| ('ios64_compile', api.platform('mac', 64)), |
| ] |
| for (buildername, host_platform) in compile_only_tests: |
| yield ( |
| api.test(buildername) + |
| host_platform + |
| api.properties.generic(mastername='client.boringssl', |
| buildername=buildername, bot_id='bot_id') |
| ) |
| |
| unit_test_only_tests = [ |
| ('linux_sde', api.platform('linux', 64)), |
| ('linux32_sde', api.platform('linux', 64)), |
| ] |
| for (buildername, host_platform) in unit_test_only_tests: |
| yield ( |
| api.test(buildername) + |
| host_platform + |
| api.properties.generic(mastername='client.boringssl', |
| buildername=buildername, bot_id='bot_id') + |
| api.override_step_data('unit tests', |
| api.test_utils.canned_test_output(True)) |
| ) |
| |
| yield ( |
| api.test('failed_imported_libraries') + |
| api.platform('linux', 64) + |
| api.properties.generic(mastername='client.boringssl', |
| buildername='linux_shared', bot_id='bot_id') + |
| api.override_step_data('check imported libraries', retcode=1) + |
| api.override_step_data('unit tests', |
| api.test_utils.canned_test_output(True)) + |
| api.override_step_data('ssl tests', |
| api.test_utils.canned_test_output(True)) |
| ) |
| |
| yield ( |
| api.test('failed_unit_tests') + |
| api.platform('linux', 64) + |
| api.properties.generic(mastername='client.boringssl', buildername='linux', |
| bot_id='bot_id') + |
| api.override_step_data('unit tests', |
| api.test_utils.canned_test_output(False)) + |
| api.override_step_data('ssl tests', |
| api.test_utils.canned_test_output(True)) |
| ) |
| |
| yield ( |
| api.test('failed_ssl_tests') + |
| api.platform('linux', 64) + |
| api.properties.generic(mastername='client.boringssl', buildername='linux', |
| bot_id='bot_id') + |
| api.override_step_data('unit tests', |
| api.test_utils.canned_test_output(True)) + |
| api.override_step_data('ssl tests', |
| api.test_utils.canned_test_output(False)) |
| ) |
| |
| yield ( |
| api.test('gerrit_cl') + |
| api.platform('linux', 64) + |
| api.properties.tryserver( |
| gerrit_project='boringssl', |
| gerrit_url='https://boringssl-review.googlesource.com', |
| mastername='actually-no-master', buildername='linux', |
| bot_id='swarming-slave') |
| ) |