#!/bin/sh

# adb.ssh is part of autopkgtest
# autopkgtest is a tool for testing Debian binary packages
#
# This script sets up an ssh connection to an adb host. If that adb host is an
# Ubuntu Touch system, it also does some extra configuration like disabling the
# screen timeout and allowing Autopilot to introspect running apps.
#
# Options:
# -w/--rw     Switch the device to read/write mode
# -r/--reset  Do a factory reset of the device before running the test
#             (Available on Ubuntu Phone only)
# -s serial | --serial=serial
#             Serial  ID  of  the device as returned by adb devices -l when
#             several devices are connected to the same host.
#
#
# autopkgtest is Copyright (C) 2006-2014 Canonical Ltd.
#
# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See 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, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# See the file CREDITS for a full list of credits information (often
# installed as /usr/share/doc/autopkgtest/CREDITS).
set -e

SSH_USER=phablet
SUDO_PASSWORD=phablet
CAPABILITIES='isolation-machine reboot'

# allow using lp:phablet-tools from a checkout
if [ -n "$PHABLET_TOOLS_PATH" ]; then
    export PATH="$PHABLET_TOOLS_PATH:$PATH"
fi

open() {
    # Setup a connection to an adb device
    # - Configure ssh connection
    # - optionally mount device RW
    ADBOPTS=""
    RWCMD=""
    RESET=""

    SHORTOPTS="l:,P:,s:,w,r"
    LONGOPTS="login:,serial:,rw,reset,no-reset"

    TEMP=$(getopt -o $SHORTOPTS --long $LONGOPTS -- "$@")
    eval set -- "$TEMP"

    while true; do
        case "$1" in
            -l|--login)
                SSH_USER=$2
                shift 2;;
            -s|--serial)
                ADBOPTS="$ADBOPTS -s $2"
                shift 2;;
            -w|--rw)
                RWCMD="mount -o rw,remount /"
                shift;;
            -r|--reset)
                RESET="1"
                shift;;
            # passed in "extraopts" so that --reset is only applied once, not
            # in between tests that call "revert"
            --no-reset)
                RESET=""
                shift;;
            --)
                shift;
                break;;
            *)
                echo "E: $(basename $0): Unsupported option $1" >&2
                exit 1;;
        esac
    done

    wait_booted

    # special setup on Ubuntu images
    SYSTEM_IMAGE=$(adb $ADBOPTS shell 'system-image-cli -i 2>/dev/null')
    if [ "${SYSTEM_IMAGE#*ubuntu}" != "$SYSTEM_IMAGE" ]; then
        if [ -n "$RESET" ]; then
            revert
        else
            ubuntu_prepare_config
            ubuntu_prepare_for_testing
        fi
        CAPABILITIES="$CAPABILITIES revert"
    fi


    # Configure SSH
    adb $ADBOPTS shell start ssh
    for port in `seq 2222 2299`; do
        adb $ADBOPTS forward tcp:$port tcp:22 && break
    done

    # Purge the device host key so that SSH doesn't print a scary warning about it
    # (it changes every time the device is reflashed and this is expected)
    ssh-keygen -f ~/.ssh/known_hosts -R [localhost]:$PORT 2>/dev/null

    # Copy your ssh id down to the device so you never need a password.
    if [ ! -e ~/.ssh/id_rsa.pub ] || [ ! -e ~/.ssh/id_rsa ]; then
        echo "~/.ssh/id_rsa.pub or ~/.ssh/id_rsa do not exist. Please generate a key" >&2
        exit 1
    fi
    script=$(mktemp /tmp/$(basename $0).XXXXXX)
    adb $ADBOPTS push ~/.ssh/id_rsa.pub /home/$SSH_USER/.ssh/authorized_keys
    cat>$script <<EOF
# Set right permissions
chown $SSH_USER:$SSH_USER -R /home/$SSH_USER/.ssh/
chmod 700 /home/$SSH_USER/.ssh
chmod 600 /home/$SSH_USER/.ssh/authorized_keys

$RWCMD
EOF

    adb $ADBOPTS push $script /tmp
    adb $ADBOPTS shell sh $script
    adb $ADBOPTS shell rm $script
    rm $script

    # print info for adt-virt-ssh
    cat<<EOF
login=$SSH_USER
hostname=localhost
port=$port
capabilities=$CAPABILITIES
identity=$HOME/.ssh/id_rsa
extraopts=--no-reset
EOF
    if [ -n "$SUDO_PASSWORD" ]; then
        echo "password=$SUDO_PASSWORD"
    fi
}

wait_booted() {
    echo "Waiting for device ADB to appear..." >&2
    adb $ADBOPTS wait-for-device
}

# configure Ubuntu device for testing
ubuntu_prepare_config() {
    if [ -z "$(adb $ADBOPTS shell 'type unity8 2>/dev/null')" ]; then
        # not an Ubuntu phone
        return
    fi

    if ! type phablet-config >/dev/null 2>&1; then
        echo "ERROR: phablet-config not found! Install phablet-tools package or" >&2
        echo "bzr branch lp:phablet-tools and run with PHABLET_TOOLS_PATH=<checkout dir>" >&2
        exit 1
    fi

    echo "Configuring Ubuntu phone for testing..." >&2

    # allow autopilot to introspect programs
    phablet-config $ADBOPTS autopilot --dbus-probe enable

    # disable first-time wizards
    phablet-config $ADBOPTS welcome-wizard --disable
    # this needs accounts-daemon running
    adb $ADBOPTS shell 'while ! pidof accounts-daemon >/dev/null; do sleep 1; done'
    phablet-config $ADBOPTS edges-intro --disable

    # TODO: disable greeter
}

# test run time setup for Ubuntu device
ubuntu_prepare_for_testing() {
    if [ -z "$(adb $ADBOPTS shell 'type unity8 2>/dev/null')" ]; then
        # not an Ubuntu phone
        return
    fi

    echo "Preparing Ubuntu phone for running tests..." >&2

    # if welcome wizard is already running, restart unity8
    adb $ADBOPTS shell "su -c 'pidof system-settings-wizard >/dev/null && kill -9 -1' phablet"

    local timeout=60
    local extra_wait=0
    echo "Waiting for desktop to boot" >&2
    while [ "$timeout" -ge 0 ]; do
        [ -z "$(adb $ADBOPTS shell 'pidof unity8')" ] || break
        # unity8 needs a few more seconds to actually be ready if it's not yet
        # running
        extra_wait=5
        timeout=$((timeout -1))
        sleep 5
    done
    sleep $extra_wait

    # disable screen dimming; ugly, but pretty much everything else hangs forever
    echo 'bash -c "powerd-cli display on bright & disown"' | adb $ADBOPTS shell &
    P=$!
    sleep 0.3
    kill $P
}

revert() {
    # revert is only offered on Ubuntu images
    echo "Performing factory reset, this will take a minute..." >&2

    # save current network connections
    local network_tar=$(mktemp)
    adb $ADBOPTS shell tar cPpf /run/netconf.tar /etc/NetworkManager/system-connections
    adb pull /run/netconf.tar $network_tar
    adb $ADBOPTS shell 'echo format data > /cache/recovery/ubuntu_command'
    adb $ADBOPTS reboot recovery
    wait_booted
    # restore network connections
    adb push $network_tar /run/netconf.tar
    adb shell 'tar xPpf /run/netconf.tar && rm /run/netconf.tar'

    ubuntu_prepare_config
    ubuntu_prepare_for_testing
}

reboot() {
    adb $ADBOPTS reboot
    wait_booted
    ubuntu_prepare_for_testing
}

cleanup() {
    adb $ADBOPTS shell pkill powerd-cli
}

if [ -z "$1" ]; then
    echo "Needs to be called with command as first argument" >&2
    exit 1
fi

cmd=$(echo "$1"|tr [[:upper:]] [[:lower:]])
shift

case $cmd in
    open)
        open $@;;
    revert)
        revert $@;;
    reboot)
        reboot $@;;
    cleanup)
        cleanup $@;;
    *)
        echo "invalid command $cmd" >&2
        exit 1
        ;;
esac
