test_storage_volume_snapshots() {
    ensure_import_testimage

    # shellcheck disable=2039,3043
    local INCUS_STORAGE_DIR incus_backend

    incus_backend=$(storage_backend "$INCUS_DIR")
    INCUS_STORAGE_DIR=$(mktemp -d -p "${TEST_DIR}" XXXXXXXXX)
    chmod +x "${INCUS_STORAGE_DIR}"
    spawn_incus "${INCUS_STORAGE_DIR}" false
    token="$(INCUS_DIR=${INCUS_DIR} incus config trust add foo -q)"
    # shellcheck disable=2153
    incus remote add test "${INCUS_ADDR}" --accept-certificate --token "${token}"

    # shellcheck disable=2039,3043
    local storage_pool storage_volume
    storage_pool="incustest-$(basename "${INCUS_STORAGE_DIR}")-pool"
    storage_pool2="${storage_pool}2"
    storage_volume="${storage_pool}-vol"

    if [ "${incus_backend}" = "linstor" ]; then
        incus storage create "$storage_pool" "$incus_backend" linstor.resource_group.place_count=1
    elif [ "${incus_backend}" = "truenas" ]; then
        incus storage create "$storage_pool" "$incus_backend" "$(truenas_source)/" "$(truenas_config)" "$(truenas_allow_insecure)" "$(truenas_api_key)"
    else
        incus storage create "$storage_pool" "$incus_backend"
    fi

    incus storage volume create "${storage_pool}" "${storage_volume}"
    incus launch testimage c1 -s "${storage_pool}"
    incus storage volume attach "${storage_pool}" "${storage_volume}" c1 /mnt
    # Create file on volume
    echo foobar > "${TEST_DIR}/testfile"
    incus file push "${TEST_DIR}/testfile" c1/mnt/testfile

    # Validate file
    incus exec c1 -- test -f /mnt/testfile
    [ "$(incus exec c1 -- cat /mnt/testfile)" = 'foobar' ]

    incus storage volume detach "${storage_pool}" "${storage_volume}" c1
    # This will create a snapshot named 'snap0'
    incus storage volume snapshot create "${storage_pool}" "${storage_volume}"
    incus storage volume snapshot list "${storage_pool}" "${storage_volume}" | grep -q "snap0"
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | grep 'name: snap0'
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | grep 'expires_at: 0001-01-01T00:00:00Z'

    # edit volume snapshot description
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | sed 's/^description:.*/description: foo/' | incus storage volume edit "${storage_pool}" "${storage_volume}/snap0"
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | grep -q 'description: foo'

    # edit volume snapshot expiry date
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | sed 's/^expires_at:.*/expires_at: 2100-01-02T15:04:05Z/' | incus storage volume edit "${storage_pool}" "${storage_volume}/snap0"
    # Depending on the timezone of the runner, some values will be different.
    # Both the year (2100) and the month (01) will be constant though.
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | grep -q '^expires_at: 2100-01'
    # Reset/remove expiry date
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | sed '/^expires_at:/d' | incus storage volume edit "${storage_pool}" "${storage_volume}/snap0"
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap0" | grep -q '^expires_at: 0001-01-01T00:00:00Z'

    incus storage volume set "${storage_pool}" "${storage_volume}" snapshots.expiry '1d'
    incus storage volume snapshot create "${storage_pool}" "${storage_volume}"
    ! incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap1" | grep -q 'expires_at: 0001-01-01T00:00:00Z' || false

    incus storage volume snapshot create "${storage_pool}" "${storage_volume}" --no-expiry
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap2" | grep -q 'expires_at: 0001-01-01T00:00:00Z' || false

    incus storage volume snapshot rm "${storage_pool}" "${storage_volume}" "snap2"
    incus storage volume snapshot rm "${storage_pool}" "${storage_volume}" "snap1"

    # Test snapshot renaming
    incus storage volume snapshot create "${storage_pool}" "${storage_volume}"
    incus storage volume snapshot list "${storage_pool}" "${storage_volume}" | grep -q "snap1"
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/snap1" | grep 'name: snap1'
    incus storage volume snapshot rename "${storage_pool}" "${storage_volume}" snap1 foo
    incus storage volume snapshot list "${storage_pool}" "${storage_volume}" | grep -q "foo"
    incus storage volume snapshot show "${storage_pool}" "${storage_volume}/foo" | grep 'name: foo'

    incus storage volume attach "${storage_pool}" "${storage_volume}" c1 /mnt
    # Delete file on volume
    incus file delete c1/mnt/testfile

    # Validate file
    ! incus exec c1 -- test -f /mnt/testfile || false

    # This should fail since you cannot restore a snapshot when the target volume
    # is attached to the container
    ! incus storage volume snapshot restore "${storage_pool}" "${storage_volume}" snap0 || false

    incus stop -f c1
    incus storage volume snapshot restore "${storage_pool}" "${storage_volume}" foo

    incus start c1
    incus storage volume detach "${storage_pool}" "${storage_volume}" c1
    incus storage volume snapshot restore "${storage_pool}" "${storage_volume}" foo
    incus storage volume attach "${storage_pool}" "${storage_volume}" c1 /mnt

    # Validate file
    incus exec c1 -- test -f /mnt/testfile
    [ "$(incus exec c1 -- cat /mnt/testfile)" = 'foobar' ]

    incus storage volume detach "${storage_pool}" "${storage_volume}" c1
    incus delete -f c1
    incus storage volume delete "${storage_pool}" "${storage_volume}"

    # Check snapshots naming conflicts.
    incus storage volume create "${storage_pool}" "vol1"
    incus storage volume create "${storage_pool}" "vol1-snap0"
    incus storage volume snapshot create "${storage_pool}" "vol1" "snap0"
    incus storage volume delete "${storage_pool}" "vol1"
    incus storage volume delete "${storage_pool}" "vol1-snap0"

    # Check snapshot pattern
    incus storage volume create "${storage_pool}" "vol1"
    incus storage volume snapshot create "${storage_pool}" "vol1"
    incus storage volume snapshot show "${storage_pool}" "vol1/snap0"
    incus storage volume set "${storage_pool}" "vol1" snapshots.pattern="test%d"
    incus storage volume snapshot create "${storage_pool}" "vol1"
    incus storage volume snapshot show "${storage_pool}" "vol1/test0"
    incus storage volume delete "${storage_pool}" "vol1"

    # Check snapshot restore of type block volumes.
    incus storage volume create "${storage_pool}" "vol1" --type block
    incus storage volume snapshot create "${storage_pool}" "vol1" "snap0"
    incus storage volume snapshot restore "${storage_pool}" "vol1" "snap0"
    incus storage volume delete "${storage_pool}" "vol1"

    # Check filesystem specific config keys cannot be applied on type block volumes.
    ! incus storage volume create "${storage_pool}" "vol1" --type block block.filesystem=btrfs || false
    ! incus storage volume create "${storage_pool}" "vol1" --type block block.mount_options=xyz || false

    # Check snapshot copy (mode pull).
    incus launch testimage "c1"
    incus storage volume create "${storage_pool}" "vol1"
    incus storage volume attach "${storage_pool}" "vol1" "c1" /mnt
    incus exec "c1" -- touch /mnt/foo
    incus delete -f "c1"
    incus storage volume snapshot create "${storage_pool}" "vol1" "snap0"
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2" --mode pull
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy (mode pull, remote).
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2" --mode pull
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy (mode push).
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2" --mode push
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy (mode push, remote).
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2" --mode push
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy (mode relay).
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2" --mode relay
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy (mode relay, remote).
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2" --mode relay
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy between pools.
    incus storage create "${storage_pool2}" dir
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool2}/vol2"
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool2}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool2}" "vol2"
    incus storage delete "${storage_pool2}"

    # Check snapshot copy between pools (remote).
    incus storage create "${storage_pool2}" dir
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool2}/vol2"
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool2}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool2}" "vol2"
    incus storage volume copy "test:${storage_pool}/vol1/snap0" "${storage_pool2}/vol2"
    incus launch testimage "c1"
    incus storage volume attach "${storage_pool2}" "vol2" "c1" /mnt
    incus exec "c1" -- test -f /mnt/foo
    incus delete -f "c1"
    incus storage volume delete "${storage_pool2}" "vol2"
    incus storage delete "${storage_pool2}"

    # Check snapshot volume only copy.
    ! incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2" --volume-only || false
    incus storage volume copy "${storage_pool}/vol1" "${storage_pool}/vol2" --volume-only
    [ "$(incus query "/1.0/storage-pools/${storage_pool}/volumes/custom/vol2/snapshots" | jq "length == 0")" = "true" ]
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot volume only copy (remote).
    ! incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2" --volume-only || false
    incus storage volume copy "${storage_pool}/vol1" "test:${storage_pool}/vol2" --volume-only
    [ "$(incus query "/1.0/storage-pools/${storage_pool}/volumes/custom/vol2/snapshots" | jq "length == 0")" = "true" ]
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot refresh.
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2"
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol2" --refresh
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot refresh (remote).
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2"
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol2" --refresh
    incus storage volume delete "${storage_pool}" "vol2"

    # Check snapshot copy between projects.
    incus project create project1
    incus storage volume copy "${storage_pool}/vol1/snap0" "${storage_pool}/vol1" --target-project project1
    [ "$(incus query "/1.0/storage-pools/${storage_pool}/volumes?project=project1" | jq "length == 1")" = "true" ]
    incus storage volume delete "${storage_pool}" "vol1" --project project1

    # Check snapshot copy between projects (remote).
    incus storage volume copy "${storage_pool}/vol1/snap0" "test:${storage_pool}/vol1" --target-project project1
    [ "$(incus query "/1.0/storage-pools/${storage_pool}/volumes?project=project1" | jq "length == 1")" = "true" ]
    incus storage volume delete "${storage_pool}" "vol1" --project project1

    incus storage volume delete "${storage_pool}" "vol1"
    incus project delete "project1"
    incus storage delete "${storage_pool}"
    incus remote remove "test"

    # shellcheck disable=SC2031,2269
    INCUS_DIR="${INCUS_DIR}"
    kill_incus "${INCUS_STORAGE_DIR}"
}
