#!/bin/bash
# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# Runs Chrome / content_shell and attaches to the renderer process for the
# target URL (or the first navigation if none is specified).
usage() {
echo "usage: $(basename $0) [-d <debug-url>] <path-to-content-shell> <url> [more-args...]"
exit 1
}
DEFAULT_TARGET_FLAGS=(--no-sandbox --disable-hang-monitor --wait-for-debugger-on-navigation)
while getopts "h?d:" OPTION
do
case $OPTION in
h|\?)
usage
;;
d)
DEBUG_URL=$OPTARG
;;
esac
done
shift $[$OPTIND-1]
TARGET=$1
shift
if [ -z "$TARGET" ]; then
usage
fi
if [[ "$TARGET" =~ run_web_tests.py$ ]]; then
# Adjust flags to be passed to driver
WEB_TESTS_FLAGS=(--jobs=1 --timeout-ms=100000000 --driver-logging)
for DEFAULT_FLAG in "${DEFAULT_TARGET_FLAGS[@]}"; do
WEB_TESTS_FLAGS=(${WEB_TESTS_FLAGS[@]} --additional-driver-flag="$DEFAULT_FLAG")
done
TARGET_FLAGS=(${WEB_TESTS_FLAGS[@]} "$@")
elif [[ "$TARGET" =~ run_wpt_tests.py$ ]]; then
WPT_TESTS_FLAGS=(--jobs=1 --timeout-multiplier=10000 --verbose)
for DEFAULT_FLAG in "${DEFAULT_TARGET_FLAGS[@]}"; do
WPT_TESTS_FLAGS=(${WPT_TESTS_FLAGS[@]} --additional-driver-flag="$DEFAULT_FLAG")
done
TARGET_FLAGS=(${WPT_TESTS_FLAGS[@]} "$@")
else
TARGET_FLAGS=(${DEFAULT_TARGET_FLAGS[@]} "$@")
fi
if [ -z "$DEBUG_URL" ]; then
echo "Debugging first renderer"
fi
# TODO: If you pass a URL containing characters that require URL encoding,
# the URL will be encoded by chrome and won't be equivalent to the $DEBUG_URL.
# We should url encode DEBUG_URL so that it matches the url chrome navigates to.
RENDERER_PID_RE='Renderer url="([^"]+)" \(([0-9]+)\) paused waiting for debugger'
if [ -z "$DEBUGGER" ]; then
if which lldb > /dev/null; then
DEBUGGER="lldb"
CONTINUE="continue"
elif which gdb > /dev/null; then
DEBUGGER="gdb -q"
CONTINUE="signal SIGUSR1"
else
echo "no debugger found"
exit 1
fi
fi
OUTPUT=$(mktemp "${TMPDIR:-/tmp}"/"$(basename $0)".XXXXX)
UNBUFFER=""
# Use unbuffer to ensure we get the output while the subprocess is paused
# waiting for a renderer.
if [ -z `which unbuffer` ]; then
echo "Warning: Couldn't find unbuffer. Buffered output can result in" \
"failure to read the PID of the paused renderer from the pipe. If" \
"you encounter a hang install unbuffer tool from your package manager."
else
UNBUFFER="unbuffer "
fi
maybe_kill() {
[ -n "$1" ] && ps -p $1 > /dev/null && kill $1
}
cleanup() {
rm $OUTPUT
maybe_kill "$BROWSER_PID"
maybe_kill "$SIGNAL_PID"
}
trap cleanup EXIT
echo "Running ${UNBUFFER}${TARGET} ${TARGET_FLAGS[@]}" >&2
${UNBUFFER}"${TARGET}" "${TARGET_FLAGS[@]}" > >(tee $OUTPUT) 2>&1 &
BROWSER_PID=$!
echo "Process $BROWSER_PID logging to $OUTPUT"
wait_renderer_pid() {
NEXT_LINE=1
tail +1f $OUTPUT | while read LINE; do
NEXT_LINE=$[$NEXT_LINE + 1]
if [[ "$LINE" =~ $RENDERER_PID_RE ]]; then
RENDERER_URL=${BASH_REMATCH[1]}
RENDERER_PID=${BASH_REMATCH[2]}
if [ -z "$DEBUG_URL" ] || [[ "$RENDERER_URL" == "$DEBUG_URL" ]]; then
echo "$NEXT_LINE $RENDERER_PID"
return
fi
# Unblock unrelated renderers.
kill -s SIGUSR1 "$RENDERER_PID"
fi
done
}
signal_renderers() {
STARTING_OUTPUT_LINE=$1
tail +${STARTING_OUTPUT_LINE}f $OUTPUT | while read LINE; do
if [[ "$LINE" =~ $RENDERER_PID_RE ]]; then
kill -s SIGUSR1 ${BASH_REMATCH[2]}
fi
done
}
RESULT=$(wait_renderer_pid)
NEXT_LINE=$(echo $RESULT|cut -d' ' -f 1)
RENDERER_PID=$(echo $RESULT|cut -d' ' -f 2)
if [ -n "$RENDERER_PID" ]; then
echo "Target renderer found. Sending SIGUSR1 to unblock any subsequent renderers."
signal_renderers ${NEXT_LINE} &
SIGNAL_PID=$!
# print yellow message
echo -e "\n\033[1;33mDebugging renderer, use '$CONTINUE' to run.\033[0m\n"
$DEBUGGER -p $RENDERER_PID
fi