#!/bin/sh


check_arch() {
    local architecture
    architecture="$(dpkg --print-architecture)"
    # run test only on amd64 because it tests only Python code anyway
    case "$architecture" in
        amd64)
            echo "Running upgrade test on $architecture"
            ;;
        *)
            echo "Skipping upgrade test on $architecture"
            exit 0
            ;;
    esac
}

chroot_exec() {
    local chroot_dir
    chroot_dir="$1"
    shift

    chroot "$chroot_dir" env http_proxy="$http_proxy" eatmydata "$@"
}

do_debootstrap() {
    local chroot_dir distro mirror
    distro="$1"
    chroot_dir="$2"
    mirror="$3"

    if [ $(systemd-detect-virt) = "lxc" ]; then
       echo "mkdnod fails in lxc, skipping debootstrap"
       exit 77
    fi

    ret=0
    for i in $(seq 5); do
        debootstrap --include eatmydata,time "$@" 2>&1 && break || ret=$?
        # clean up incompletely debootstrapped chroot
        rm -rf "$chroot_dir"
        sleep 120
    done
    if [ $ret != 0 ]; then
        echo "Running debootstrap failed, skipping test."
        exit 77
    fi

    mount --bind /dev/pts "$chroot_dir/dev/pts"
    mount --bind /proc "$chroot_dir/proc"
    trap "umount \"$chroot_dir/proc\"; umount \"$chroot_dir/dev/pts\"; rm -rf \"$chroot_dir\"" EXIT
}

# pocket can be "proposed", "updates" or "security", not the actual distro-specific pocket name
enable_pocket() {
    local chroot_dir pocket distro mirror_dir_postfix real_pocket
    chroot_dir="$1"
    pocket="$2"
    distro=$(awk '{ print $3; exit}' "$chroot_dir/etc/apt/sources.list")
    case "$(dpkg-vendor --query Vendor)" in
        "Ubuntu")
            sed "s/$distro/$distro-$pocket/" < "$chroot_dir/etc/apt/sources.list" \
                > "$chroot_dir/etc/apt/sources.list.d/$pocket.list"
            ;;
        "Debian")
            case "$pocket" in
                proposed)
                    pocket_dir="${distro}-proposed-updates"
                    ;;
                security)
                    case "$distro" in
                        stretch|buster)
                            pocket_dir="$distro/updates"
                            ;;
                        *)
                            pocket_dir="${distro}-$pocket"
                            ;;
                    esac
                    mirror_dir_postfix="-security"
                    ;;
                *)
                    pocket_dir="${distro}-$pocket"
                    ;;
            esac
            sed "s|/debian |/debian$mirror_dir_postfix |;s|$distro|$pocket_dir|" < "$chroot_dir/etc/apt/sources.list" \
                > "$chroot_dir/etc/apt/sources.list.d/$pocket.list"
            ;;
    esac
}

# pocket can be "proposed", "updates" or "security", not the actual distro-specific pocket name
disable_pocket() {
    local chroot_dir pocket
    chroot_dir="$1"
    pocket="$2"
    rm "$chroot_dir/etc/apt/sources.list.d/$pocket.list"
}

upgrade_python_apt() {
    local chroot_dir distro
    chroot_dir="$1"
    distro="$2"

    # Release's most updated python-apt is installed because this is the version
    # systems are running most likely. This also contains latest stability fixes
    # and speed optimizations, thus speed regressions nd improvements can be
    # tracked in autopkgtest runs.
    enable_pocket "$chroot_dir" security
    enable_pocket "$chroot_dir" updates
    if [ "$distro" = "buster" ]; then
        # python-apt 1.9.6 is not available in buster
        exit 77
    fi
    chroot_exec "$chroot_dir" apt-get update
    chroot_exec "$chroot_dir" apt-get install -y python3-apt 2>&1
    disable_pocket "$chroot_dir" updates
    disable_pocket "$chroot_dir" security
    chroot_exec "$chroot_dir" apt-get update
}

run_u_u() {
    local chroot_dir
    chroot_dir="$1"

    uu_prefix=""
    if chroot_exec "$chroot_dir" which valgrind > /dev/null; then
        uu_prefix="$uu_prefix env PYTHONMALLOC=malloc valgrind"
    fi

    # let the test pass on battery power, too
    echo 'Unattended-Upgrade::OnlyOnACPower "false";' > "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-acpower"
    echo 'Unattended-Upgrade::Skip-Updates-On-Metered-Connections "false";' > "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-metered"

    # test if noninteractive is always passed to dpkg
    echo 'DPkg::Pre-Install-Pkgs:: "echo $DEBIAN_FRONTEND | grep -q noninteractive";' > "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-dpkg-frontend-check"

    # enable a few features to test

    echo 'Unattended-Upgrade::Mail "root";' > "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-mail"
    chroot_exec "$chroot_dir" apt-get update

    ret=0
    for i in $(seq 5); do
        chroot_exec "$chroot_dir" unattended-upgrade --download-only && break || ret=$?
        sleep 120
    done
    [ $ret = 0 ] || exit $ret

    chroot_exec "$chroot_dir" time unattended-upgrade --verbose --dry-run 2>&1
    chroot_exec "$chroot_dir" $uu_prefix python3 /usr/bin/unattended-upgrade --verbose --debug
    # turn on verbose loging in the congfiguration file
    echo 'Unattended-Upgrade::Verbose "true";' > "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-verbose"
    chroot_exec "$chroot_dir" time python3 /usr/bin/unattended-upgrade 2>&1
    echo "new packages marked as manually installed (should be none): "
    chroot_exec "$chroot_dir" apt-mark showmanual | diff "$chroot_dir/tmp/manual" -
    chroot_exec "$chroot_dir" perl -MMIME::QuotedPrint -pe '$_=MIME::QuotedPrint::decode($_);' /var/mail/mail

    printf  "Checking that no email is sent when nothing had to be done..."
    if ! chroot_exec "$chroot_dir" perl -MMIME::QuotedPrint -pe '$_=MIME::QuotedPrint::decode($_);' /var/mail/mail | grep -q "unattended and no pending auto-removals"; then
        echo "OK"
    else
        echo "FAILED, see last email above"
    fi

    printf  "Checking that no packages can be upgraded or auto-removed..."
    if tail -n 1 "$chroot_dir/var/log/unattended-upgrades/unattended-upgrades.log" | grep -q "No packages found that can be upgraded unattended and no pending auto-removals"; then
        echo "OK."
    else
        echo "Failed:"
        cat "$chroot_dir/var/log/unattended-upgrades/unattended-upgrades.log"
    fi

    rm "$chroot_dir/etc/apt/apt.conf.d/51unattended-upgrades-dpkg-frontend-check"
}
