#!/bin/sh -e
# This program is free software: you can redistribute it and/or modify it
# under the terms of the the GNU General Public License version 3, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
# PURPOSE.  See the applicable version of the GNU General Public
# License for more details.
#.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Copyright (C) 2012 Canonical, Ltd.

if [ -f "$(dirname $0)/shell-adb-common.sh" ]; then
    . "$(dirname $0)/shell-adb-common.sh"
else
    . "/usr/share/phabletutils/shell-adb-common.sh"
fi

TESTSUITE=""
TESTPACKAGES=""
LOCALPACKAGES=""
RESULTDIR=""
ARTIFACTS=""
APFORMAT="xml"
APEXTRA=""

EXECUTE_COMMAND=0
USER=phablet
NOSHELL=0
RETVAL=0
VERBOSE=""
ASKPASS=""
SUDO=""

print_usage() {
    cat << EOF
usage: $0 [-s SERIAL] [-s] [-n] [-x] [-v] [-p PACKAGENAME] [ -r PASSWORD/PIN ] [-c PACKAGE] [-o DIR] [-a ARTIFACT] [-f xml|subunit|text] [-A args] testsuite

  Run the specified testsuite on the device

  -s SERIAL        Device serial number
  -p PACKAGENAME   Additional package to be installed, may be used multiple
                   times (requires -r option)
  -r PASSWORD/PIN  Device password or PIN for package installation
  -c PACKAGE       Copy and install local package to device, may be used
                   multiple times
  -n               Stop the shell during the test run
  -o DIR           Test report and artifacts output dir
  -f format        Specifies the output format autopilot will use:
                   xml, subunit, or text. Default=$APFORMAT (requires -o)
  -A               Extra arguments to pass to autopilot.
  -a ARTIFACT      Artifact to fetch after the test, may be used multiple times
                   (requires -o)
  -x               Execute command line, will not use autopilot by default
  -v               Run autopilot with -v option for more verbose output
EOF
}

wait_for_device() {
    adb wait-for-device
}

set_up_sudo() {
    if [ -z "$PW" ]; then
        echo "Please use the -r option to provide a device password or PIN"
        echo
        print_usage
        exit 0
    fi
    ASKPASS="$(adb shell "mktemp -t sudo_askpass.XXXX|tr -d '\n'")"
    adb shell "printf '#\x21/bin/sh\necho \"%s\"\n' '${PW}' >$ASKPASS; chmod +x $ASKPASS"
    SUDO="SUDO_ASKPASS=$ASKPASS sudo -A"
}

clean_up_sudo() {
    [ -n "$ASKPASS" ] && adb shell "rm -rf $ASKPASS"
}

exec_with_adb() {
    set_up_sudo
    adb shell "LC_ALL=C $SUDO /usr/bin/env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin $@"
    clean_up_sudo
}

exec_with_adb_user() {
    adb shell "LC_ALL=C $@"
}

install_packages() {

    if test -n "$TESTPACKAGES"; then
        exec_with_adb DEBIAN_FRONTEND=noninteractive apt-get -y -q install $TESTPACKAGES
    fi

    if test -n "$LOCALPACKAGES"; then
        exec_with_adb mkdir -p /tmp/phablet-run-test/
        exec_with_adb rm -rf /tmp/phablet-run-test/*
        PACKAGELIST=""
        for PACKAGEPATH in $LOCALPACKAGES; do
            PACKAGE=$(basename $PACKAGEPATH)
            echo "Pushing $PACKAGE..."
            adb push $PACKAGEPATH /tmp/phablet-run-test/
            PACKAGELIST="$PACKAGELIST /tmp/phablet-run-test/$PACKAGE"
        done
        exec_with_adb dpkg -i $PACKAGELIST
        exec_with_adb DEBIAN_FRONTEND=noninteractive apt-get -fyq install
    fi
}

disable_shell() {
    exec_with_adb_user initctl stop unity8
}

restore_shell() {
    exec_with_adb_user initctl start unity8
}

get_returncode() {
    while read line; do
        set +e
        RETVAL=$(echo $line | grep -Po '(?<=ADB_RC=)\d+')
        if [ $? -eq 0 ] ; then
            set -e
            return $RETVAL
        fi
        echo $line
        set -e
    done
}


run_autopilot_test() {
    # This directory doesn't exist in a freshly flashed device, so create it.
    exec_with_adb_user mkdir -p /home/phablet/autopilot

    # adb shell always returns 0, so we have to do some hackery to get the
    # actual RC from the test
    {
        apbase="cd /home/phablet/autopilot;SUPPRESS_DEPRECATED_NOTE=yes autopilot3 run $VERBOSE $APEXTRA"
        if [ "$RESULTDIR" ]; then
            adb shell "$apbase -o /tmp/test_results.$APFORMAT -f $APFORMAT $TESTSUITE; echo ADB_RC=\$?"
	    if [ $APFORMAT = "xml" ]; then
                echo "***** Test summary *****"
                exec_with_adb_user "head -n 1 /tmp/test_results.$APFORMAT"
            fi
        else
            adb shell "$apbase $TESTSUITE; echo ADB_RC=\$?"
        fi
    } | get_returncode
}

run_cli_command() {
    apbase="cd /home/phablet; $TESTSUITE"
    # adb shell always returns 0, so we have to do some hackery to get the
    # actual RC from the test
    {
        if [ "$RESULTDIR" ]; then
            result_output=/tmp/test_results.$APFORMAT
            adb shell 'rm -rf $result_output'
            adb shell "$apbase | tee $result_output; echo ADB_RC=\$?"
            adb pull $result_output $RESULTDIR
        else
            adb shell "$apbase; echo ADB_RC=\$?"
        fi
    } | get_returncode

}

fetch_artifacts() {
    if [ "$RESULTDIR" ]; then
        mkdir -p $RESULTDIR
        echo "***** Artifacts ($RESULTDIR) *****"
        set +e
        if [ $EXECUTE_COMMAND -eq 0 ]; then
            adb pull /tmp/test_results.$APFORMAT $RESULTDIR
        fi
        for artifact in $ARTIFACTS; do
           adb pull $artifact $RESULTDIR
        done
        set -e
    fi
}

while getopts A:a:c:f:hnxo:p:r:s:v opt; do
    case $opt in
    A)
        APEXTRA=$OPTARG
        ;;
    a)
        ARTIFACTS="$ARTIFACTS $OPTARG"
        ;;
    c)
        LOCALPACKAGES="$LOCALPACKAGES $OPTARG"
        ;;
    f)
        APFORMAT=$OPTARG
        ;;
    h)
        print_usage
        exit 0
        ;;
    n)
        NOSHELL=1
        ;;
    o)
        RESULTDIR=$OPTARG
        ;;
    p)
        TESTPACKAGES="$TESTPACKAGES $OPTARG"
        ;;
    r)
        PW=$OPTARG
        ;;
    s)
        SERIAL="$OPTARG"
        ;;
    x)
        EXECUTE_COMMAND=1
        ;;
    v)
        VERBOSE="-v"
        ;;
  esac
done

shift $((OPTIND - 1))


# exporting ANDROID_SERIAL to support multiple devices connected
# seamlessly
[ -z "$SERIAL" ] || export ANDROID_SERIAL="$SERIAL"

TESTSUITE=$@
if test -z "$TESTSUITE"; then
    echo To run a test please specify a test suite
    exit 0
fi

check_devices

install_packages

if [ $NOSHELL -eq 1 ]; then
    echo "Disabling shell"
    disable_shell
fi

if [ $EXECUTE_COMMAND -eq 1 ]; then
    echo "running $TESTSUITE"
    run_cli_command || RETVAL=1
else
    run_autopilot_test || RETVAL=1
fi

fetch_artifacts

if [ $NOSHELL -eq 1 ]; then
    echo "Restoring shell"
    restore_shell
fi

exit $RETVAL
