blob: 71c09507b69618485a5b1558bbb115bc586994c2 [file] [log] [blame]
#!/usr/bin/env python2
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# This script runs on the distributed-test slave and acts
# as a wrapper around run-test.sh.
#
# The distributed testing system can't pass in environment variables
# to commands, so this takes some parameters, turns them into environment
# variables, and then executes the test wrapper.
#
# We also 'cat' the test log upon completion so that the test logs are
# uploaded by the test slave back.
import optparse
import os
import re
import shutil
import subprocess
import sys
ME = os.path.abspath(__file__)
ROOT = os.path.abspath(os.path.join(os.path.dirname(ME), ".."))
def is_elf_binary(path):
""" Determine if the given path is an ELF binary (executable or shared library) """
if not os.path.isfile(path) or os.path.islink(path):
return False
try:
with file(path, "rb") as f:
magic = f.read(4)
return magic == "\x7fELF"
except:
# Ignore unreadable files
return False
def fix_rpath_component(bin_path, path):
"""
Given an RPATH component 'path' of the binary located at 'bin_path',
fix the thirdparty dir to be relative to the binary rather than absolute.
"""
rel_tp = os.path.relpath(os.path.join(ROOT, "thirdparty/"),
os.path.dirname(bin_path))
path = re.sub(r".*thirdparty/", "$ORIGIN/"+rel_tp + "/", path)
return path
def fix_rpath(path):
"""
Fix the RPATH/RUNPATH of the binary located at 'path' so that
the thirdparty/ directory is properly found, even though we will
run the binary at a different path than it was originally built.
"""
# Fetch the original rpath.
p = subprocess.Popen(["chrpath", path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
return
rpath = re.search("R(?:UN)?PATH=(.+)", stdout.strip()).group(1)
# Fix it to be relative.
new_path = ":".join(fix_rpath_component(path, c) for c in rpath.split(":"))
# Write the new rpath back into the binary.
subprocess.check_call(["chrpath", "-r", new_path, path])
def fixup_rpaths(root):
"""
Recursively walk the directory tree 'root' and fix the RPATH for any
ELF files (binaries/libraries) that are found.
"""
for dirpath, dirnames, filenames in os.walk(root):
for f in filenames:
p = os.path.join(dirpath, f)
if is_elf_binary(p):
fix_rpath(p)
def main():
p = optparse.OptionParser(usage="usage: %prog [options] <test-name>")
p.add_option("-e", "--env", dest="env", type="string", action="append",
help="key=value pairs for environment variables",
default=[])
options, args = p.parse_args()
if len(args) < 1:
p.print_help(sys.stderr)
sys.exit(1)
test_exe = args[0]
test_name, _ = os.path.splitext(os.path.basename(test_exe))
test_dir = os.path.dirname(test_exe)
env = os.environ.copy()
for env_pair in options.env:
(k, v) = env_pair.split("=", 1)
env[k] = v
# Fix the RPATHs of any binaries. During the build, we end up with
# absolute paths from the build machine. This fixes the paths to be
# binary-relative so that we can run it on the new location.
#
# It's important to do this rather than just putting all of the thirdparty
# lib directories into $LD_LIBRARY_PATH below because we need to make sure
# that non-TSAN-instrumented runtime tools (like 'llvm-symbolizer') do _NOT_
# pick up the TSAN-instrumented libraries, whereas TSAN-instrumented test
# binaries (like 'foo_test' or 'kudu-tserver') _DO_ pick them up.
fixup_rpaths(os.path.join(ROOT, "build"))
fixup_rpaths(os.path.join(ROOT, "thirdparty"))
env['LD_LIBRARY_PATH'] = ":".join(
[os.path.join(ROOT, "build/dist-test-system-libs/"),
os.path.abspath(os.path.join(test_dir, "..", "lib"))])
# GTEST_OUTPUT must be canonicalized and have a trailing slash for gtest to
# properly interpret it as a directory.
env['GTEST_OUTPUT'] = 'xml:' + os.path.abspath(
os.path.join(test_dir, "..", "test-logs")) + '/'
env['ASAN_SYMBOLIZER_PATH'] = os.path.join(ROOT, "thirdparty/installed/bin/llvm-symbolizer")
rc = subprocess.call([os.path.join(ROOT, "build-support/run-test.sh")] + args,
env=env)
sys.exit(rc)
if __name__ == "__main__":
main()