summary: Check that upgrade works

details: |
    On classic systems, the snapd package can be upgraded. Certain properties,
    such as aliases, are retained. On SELinux-based systems extra care is taken
    to ensure extended attributes carrying the labels are set up properly.

# arch: there is no snapd in arch repos
# amazon: enable once it's possible to install snapd from EPEL
# centos-9: enable once it's possible to install snapd from CentOS Stream 9
systems: [-debian-sid-*, -arch-*, -amazon-*, -centos-9-*]

environment:
    # downloading the core snap triggers OOM occasionally
    SNAPD_NO_MEMORY_LIMIT: 1

restore: |
    if [ "$REMOTE_STORE" = staging ]; then
        echo "skip upgrade tests while talking to the staging store"
        exit 0
    fi
    rm -f /var/tmp/myevil.txt

    # An older version of snapd might have been missing proper context
    # transitions for fontconfig cache locations, attempt to restore the context
    # to avoid breaking tests that run after this one
    case "$SPREAD_SYSTEM" in
        fedora-*|centos-*)
            if [ -d /var/cache/fontconfig ]; then
                restorecon -RvF /var/cache/fontconfig
            fi
            ;;
    esac

execute: |
    if [ "$REMOTE_STORE" = staging ]; then
        echo "skip upgrade tests while talking to the staging store"
        exit 0
    fi
    #shellcheck source=tests/lib/pkgdb.sh
    . "$TESTSLIB/pkgdb.sh"

    if [[ "$SPREAD_REBOOT" == "0" ]]; then

        echo "Remove snapd and snap-confine"
        distro_purge_package snapd snap-confine || true
        case "$SPREAD_SYSTEM" in
            fedora-*|centos-*)
                distro_purge_package snapd-selinux || true
                ;;
        esac

        echo "Install previous snapd version from the store"
        distro_install_package snap-confine snapd

        case "$SPREAD_SYSTEM" in
            arch-*|centos-*)
                # Start the services on distros where that doesn't happen
                # automatically
                systemctl daemon-reload
                systemctl restart snapd.socket
                systemctl enable snapd.socket
                ;;
        esac

        # Need to be seeded to allow snap install
        if ! snap wait 2>&1|MATCH "unknown command" ; then
            snap wait system seed.loaded
        fi

        prevsnapdver="$(snap --version|grep "snapd ")"
        echo "$prevsnapdver" > prevsnapdver.out

        if os.query is-debian; then
            # For debian we install the latest core snap independently until
            # the bug fix is on stable once 2.27 landed
            snap install core
        fi

        echo "Install precondition check snaps with it"
        snap install test-snapd-sh
        snap install test-snapd-auto-aliases

        do_classic=no
        if "$TESTSTOOLS"/snaps-state is-confinement-supported classic; then
            "$TESTSTOOLS"/snaps-state install-local test-snapd-classic-confinement --classic
            do_classic=yes
            # Preserve the state across reboots if necessary
            touch do-classic
        fi

        echo "Precondition check installs"
        test-snapd-sh.sh -c 'echo Hello' | grep Hello
        test-snapd-sh.sh -c 'env' | grep SNAP_NAME=test-snapd-sh
        test_snapd_wellknown1|MATCH "ok wellknown 1"
        test_snapd_wellknown2|MATCH "ok wellknown 2"

        context_transition=0
        case "$SPREAD_SYSTEM" in
            fedora-*|centos-*)
                if ! MATCH 'Options=.*context=.' /etc/systemd/system/var-lib-snapd-snap-core-*.mount; then
                    context_transition=1
                fi
                ;;
        esac

        echo "Do upgrade"
        # allow-downgrades prevents errors when new versions hit the archive, for instance,
        # trying to install 2.11ubuntu1 over 2.11+0.16.04
        pkg_extension="$(distro_get_package_extension)"
        if os.query is-arch-linux; then
            # Arch's pacman is a bit funky here, the command that's run is:
            #    pacman -U --noconfirm --force /home/gopath/snapd-*.pkg.tar.xz
            # The official repo package contains snapd and snap-confine. The local test package
            # conflicts with snap-confine, thus pacman will ask to remove snap-confine, displaying
            # a question, but at the same time it completely ignores --noconfirm and aborts the upgrade.
            # As a workaround, drop --noconfirm and pass 'y' to all the questions.
            yes | pacman -U "$GOHOME"/snap*."$pkg_extension"
        else
            distro_install_local_package --allow-downgrades "$GOHOME"/snap*."$pkg_extension"
            if [ "$context_transition" = "1" ]; then
                echo "Requesting reboot to enable SELinux mount context transition"
                # transitioning SELinux mount contexts requires a reboot
                REBOOT
            fi
        fi

    fi # SPREAD_REBOOT == 0

    do_classic=no
    if [ -e do-classic ]; then
        do_classic=yes
    fi

    snapdver=$(snap --version|grep "snapd ")
    [ "$snapdver" != "$(cat prevsnapdver)" ]

    case "$SPREAD_SYSTEM" in
        fedora-*|centos-*)
            # All mount units should have been patched on upgrade
            SNAP_MOUNT_DIR="$(os.paths snap-mount-dir)"
            unit_prefix="$(systemd-escape -p "${SNAP_MOUNT_DIR}")"
            for unit in /etc/systemd/system/"$unit_prefix"-*.mount; do
                MATCH 'Options=.*context=system_u:object_r:snappy_snap_t:s0' "$unit"
            done
            ;;
    esac


    echo "Precondition check already installed snaps after upgrade"
    snap list | grep core
    snap list | grep test-snapd-sh
    test-snapd-sh.sh -c 'echo Hello' | MATCH "Hello"
    test-snapd-sh.sh -c 'env' | MATCH "SNAP_NAME=test-snapd-sh"
    if [ "$do_classic" = yes ]; then
        test-snapd-classic-confinement.recurse 5
    fi

    # only test if confinement works and we actually have apparmor available
    # FIXME: this will be converted to a better check once we added the
    # plumbing for that into the snap command.
    if [ -e /sys/kernel/security/apparmor ]; then
        echo Hello > /var/tmp/myevil.txt
        if test-snapd-sh.cat /var/tmp/myevil.txt; then
            exit 1
        fi
    fi

    # check that automatic aliases survived
    test_snapd_wellknown1|MATCH "ok wellknown 1"
    test_snapd_wellknown2|MATCH "ok wellknown 2"
    snap aliases|MATCH "test-snapd-auto-aliases.wellknown1 +test_snapd_wellknown1 +-"
    snap aliases|MATCH "test-snapd-auto-aliases.wellknown2 +test_snapd_wellknown2 +-"

    echo "Check migrating to types in state"
    coreType=$(gojq -r '.data.snaps["core"].type' /var/lib/snapd/state.json)
    testSnapType=$(gojq -r '.data.snaps["test-snapd-sh"].type' /var/lib/snapd/state.json)
    [ "$coreType" = "os" ]
    [ "$testSnapType" = "app" ]
