| #!/bin/bash |
| |
| # Copyright (c) 2011 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. |
| |
| # This script can be used by waterfall sheriffs to fetch the status |
| # of Valgrind bots on the memory waterfall and test if their local |
| # suppressions match the reports on the waterfall. |
| |
| set -e |
| |
| THISDIR=$(dirname "${0}") |
| LOGS_DIR=$THISDIR/waterfall.tmp |
| WATERFALL_PAGE="http://build.chromium.org/p/chromium.memory/builders" |
| WATERFALL_FYI_PAGE="http://build.chromium.org/p/chromium.memory.fyi/builders" |
| |
| download() { |
| # Download a file. |
| # $1 = URL to download |
| # $2 = Path to the output file |
| # {{{1 |
| if [ "$(which curl)" != "" ] |
| then |
| if ! curl -s -o "$2" "$1" |
| then |
| echo |
| echo "Failed to download '$1'... aborting" |
| exit 1 |
| fi |
| elif [ "$(which wget)" != "" ] |
| then |
| if ! wget "$1" -O "$2" -q |
| then |
| echo |
| echo "Failed to download '$1'... aborting" |
| exit 1 |
| fi |
| else |
| echo "Need either curl or wget to download stuff... aborting" |
| exit 1 |
| fi |
| # }}} |
| } |
| |
| fetch_logs() { |
| # Fetch Valgrind logs from the waterfall {{{1 |
| |
| # TODO(timurrrr,maruel): use JSON, see |
| # http://build.chromium.org/p/chromium.memory/json/help |
| |
| rm -rf "$LOGS_DIR" # Delete old logs |
| mkdir "$LOGS_DIR" |
| |
| echo "Fetching the list of builders..." |
| download $1 "$LOGS_DIR/builders" |
| SLAVES=$(grep "<a href=\"builders\/" "$LOGS_DIR/builders" | \ |
| grep 'td class="box"' | \ |
| sed "s/.*<a href=\"builders\///" | sed "s/\".*//" | \ |
| sort | uniq) |
| |
| for S in $SLAVES |
| do |
| SLAVE_URL=$1/$S |
| SLAVE_NAME=$(echo $S | sed -e "s/%20/ /g" -e "s/%28/(/g" -e "s/%29/)/g") |
| echo -n "Fetching builds by slave '${SLAVE_NAME}'" |
| download $SLAVE_URL?numbuilds=${NUMBUILDS} "$LOGS_DIR/slave_${S}" |
| |
| # We speed up the 'fetch' step by skipping the builds/tests which succeeded. |
| # TODO(timurrrr): OTOH, we won't be able to check |
| # if some suppression is not used anymore. |
| # |
| # The awk script here joins the lines ending with </td> to make it possible |
| # to find the failed builds. |
| LIST_OF_BUILDS=$(cat "$LOGS_DIR/slave_$S" | \ |
| awk 'BEGIN { buf = "" } |
| { |
| if ($0 ~ /<\/td>/) { buf = (buf $0); } |
| else { |
| if (buf) { print buf; buf="" } |
| print $0 |
| } |
| } |
| END {if (buf) print buf}' | \ |
| grep "success\|failure" | \ |
| head -n $NUMBUILDS | \ |
| grep "failure" | \ |
| grep -v "failed compile" | \ |
| sed "s/.*\/builds\///" | sed "s/\".*//") |
| |
| for BUILD in $LIST_OF_BUILDS |
| do |
| # We'll fetch a few tiny URLs now, let's use a temp file. |
| TMPFILE=$(mktemp -t memory_waterfall.XXXXXX) |
| download $SLAVE_URL/builds/$BUILD "$TMPFILE" |
| |
| REPORT_FILE="$LOGS_DIR/report_${S}_${BUILD}" |
| rm -f $REPORT_FILE 2>/dev/null || true # make sure it doesn't exist |
| |
| REPORT_URLS=$(grep -o "[0-9]\+/steps/memory.*/logs/[0-9A-F]\{16\}" \ |
| "$TMPFILE" \ |
| || true) # `true` is to succeed on empty output |
| FAILED_TESTS=$(grep -o "[0-9]\+/steps/memory.*/logs/[A-Za-z0-9_.]\+" \ |
| "$TMPFILE" | grep -v "[0-9A-F]\{16\}" \ |
| | grep -v "stdio" || true) |
| |
| for REPORT in $REPORT_URLS |
| do |
| download "$SLAVE_URL/builds/$REPORT/text" "$TMPFILE" |
| echo "" >> "$TMPFILE" # Add a newline at the end |
| cat "$TMPFILE" | tr -d '\r' >> "$REPORT_FILE" |
| done |
| |
| for FAILURE in $FAILED_TESTS |
| do |
| echo -n "FAILED:" >> "$REPORT_FILE" |
| echo "$FAILURE" | sed -e "s/.*\/logs\///" -e "s/\/.*//" \ |
| >> "$REPORT_FILE" |
| done |
| |
| rm "$TMPFILE" |
| echo $SLAVE_URL/builds/$BUILD >> "$REPORT_FILE" |
| done |
| echo " DONE" |
| done |
| # }}} |
| } |
| |
| match_suppressions() { |
| PYTHONPATH=$THISDIR/../python/google \ |
| python "$THISDIR/test_suppressions.py" $@ "$LOGS_DIR/report_"* |
| } |
| |
| match_gtest_excludes() { |
| for PLATFORM in "Linux" "Chromium%20Mac" "Chromium%20OS" "Windows" |
| do |
| echo |
| echo "Test failures on ${PLATFORM}:" | sed "s/%20/ /" |
| grep -h -o "^FAILED:.*" -R "$LOGS_DIR"/*${PLATFORM}* | \ |
| grep -v "FAILS\|FLAKY" | sort | uniq | \ |
| sed -e "s/^FAILED://" -e "s/^/ /" |
| # Don't put any operators between "grep | sed" and "RESULT=$PIPESTATUS" |
| RESULT=$PIPESTATUS |
| |
| if [ "$RESULT" == 1 ] |
| then |
| echo " None!" |
| else |
| echo |
| echo " Note: we don't check for failures already excluded locally yet" |
| echo " TODO(timurrrr): don't list tests we've already excluded locally" |
| fi |
| done |
| echo |
| echo "Note: we don't print FAILS/FLAKY tests and 1200s-timeout failures" |
| } |
| |
| usage() { |
| cat <<EOF |
| usage: $0 fetch|match options |
| |
| This script can be used by waterfall sheriffs to fetch the status |
| of Valgrind bots on the memory waterfall and test if their local |
| suppressions match the reports on the waterfall. |
| |
| OPTIONS: |
| -h Show this message |
| -n N Fetch N builds from each slave. |
| |
| COMMANDS: |
| fetch Fetch Valgrind logs from the memory waterfall |
| match Test the local suppression files against the downloaded logs |
| |
| EOF |
| } |
| |
| NUMBUILDS=3 |
| |
| CMD=$1 |
| if [ $# != 0 ]; then |
| shift |
| fi |
| |
| # Arguments for "match" are handled in match_suppressions |
| if [ "$CMD" != "match" ]; then |
| while getopts “hn:” OPTION |
| do |
| case $OPTION in |
| h) |
| usage |
| exit |
| ;; |
| n) |
| NUMBUILDS=$OPTARG |
| ;; |
| ?) |
| usage |
| exit |
| ;; |
| esac |
| done |
| shift $((OPTIND-1)) |
| if [ $# != 0 ]; then |
| usage |
| exit 1 |
| fi |
| fi |
| |
| if [ "$CMD" = "fetch" ]; then |
| echo "Fetching $NUMBUILDS builds" |
| fetch_logs $WATERFALL_PAGE |
| fetch_logs $WATERFALL_FYI_PAGE |
| elif [ "$CMD" = "match" ]; then |
| match_suppressions $@ |
| match_gtest_excludes |
| elif [ "$CMD" = "blame" ]; then |
| echo The blame command died of bitrot. If you need it, please reimplement it. |
| echo Reimplementation is blocked on http://crbug.com/82688 |
| else |
| usage |
| exit 1 |
| fi |