# Test restore database backups after a failed upgrade.
test_database_restore() {
    INCUS_RESTORE_DIR=$(mktemp -d -p "${TEST_DIR}" XXX)

    spawn_incus "${INCUS_RESTORE_DIR}" true

    # Set a config value before the broken upgrade.
    (
        set -e
        # shellcheck disable=SC2034
        INCUS_DIR=${INCUS_RESTORE_DIR}
        incus config set "core.https_allowed_credentials" "true"
    )

    shutdown_incus "${INCUS_RESTORE_DIR}"

    # Simulate a broken update by dropping in a buggy patch.global.sql
    cat << EOF > "${INCUS_RESTORE_DIR}/database/patch.global.sql"
UPDATE config SET value='false' WHERE key='core.https_allowed_credentials';
INSERT INTO broken(n) VALUES(1);
EOF

    # Starting Incus fails.
    ! INCUS_DIR="${INCUS_RESTORE_DIR}" incusd --logfile "${INCUS_RESTORE_DIR}/incus.log" "${DEBUG-}" 2>&1 || false

    # Remove the broken patch
    rm -f "${INCUS_RESTORE_DIR}/database/patch.global.sql"

    # Restore the backup
    rm -rf "${INCUS_RESTORE_DIR}/database/global"
    cp -a "${INCUS_RESTORE_DIR}/database/global.bak" "${INCUS_RESTORE_DIR}/database/global"

    # Restart the daemon and check that our previous settings are still there
    respawn_incus "${INCUS_RESTORE_DIR}" true
    (
        set -e
        # shellcheck disable=SC2034
        INCUS_DIR=${INCUS_RESTORE_DIR}
        incus config get "core.https_allowed_credentials" | grep -q "true"
    )

    kill_incus "${INCUS_RESTORE_DIR}"
}

test_database_no_disk_space() {
    # shellcheck disable=2039,3043
    local INCUS_DIR

    INCUS_NOSPACE_DIR=$(mktemp -d -p "${TEST_DIR}" XXX)

    # Mount a tmpfs with limited space in the global database directory and create
    # a very big file in it, which will eventually cause database transactions to
    # fail.
    GLOBAL_DB_DIR="${INCUS_NOSPACE_DIR}/database/global"
    BIG_FILE="${GLOBAL_DB_DIR}/bigfile"
    mkdir -p "${GLOBAL_DB_DIR}"
    mount -t tmpfs -o size=67108864 tmpfs "${GLOBAL_DB_DIR}"
    dd bs=1024 count=51200 if=/dev/zero of="${BIG_FILE}"

    spawn_incus "${INCUS_NOSPACE_DIR}" true

    (
        set -e
        # shellcheck disable=SC2034,SC2030
        INCUS_DIR="${INCUS_NOSPACE_DIR}"

        ensure_import_testimage
        incus init testimage c

        # Set a custom user property with a big value, so we eventually eat up all
        # available disk space in the database directory.
        DATA="${INCUS_NOSPACE_DIR}/data"
        head -c 262144 < /dev/zero | tr '\0' '\141' > "${DATA}"
        for i in $(seq 20); do
            if ! incus config set c "user.prop${i}" - < "${DATA}"; then
                break
            fi
        done

        # Commands that involve writing to the database keep failing.
        ! incus config set c "user.propX" - < "${DATA}" || false
        ! incus config set c "user.propY" - < "${DATA}" || false

        # Removing the big file eventually makes the database happy again.
        rm "${BIG_FILE}"

        succeeded=no
        for i in $(seq 10); do
            if incus config set c "user.propZ" - < "${DATA}"; then
                succeeded=yes
                break
            fi
            sleep 1
        done
        [ "${succeeded}" = "yes" ] || false

        incus delete -f c

        # The cleanup routine does not take care of image deletion in this test,
        # because the socket is closed and the DB is deleted before cleanup
        incus image delete testimage
    )

    shutdown_incus "${INCUS_NOSPACE_DIR}"
    umount "${GLOBAL_DB_DIR}"
    kill_incus "${INCUS_NOSPACE_DIR}"
}
