#!/bin/sh

. "tests/lib.sh"

# Very simple smoke test for squashfuse_ll. Make some random files.
# assemble a squashfs image, mount it, compare the files.

SFLL=${1:-./squashfuse_ll}         # The squashfuse_ll binary.

IDLE_TIMEOUT=5

trap cleanup EXIT
set -e

WORKDIR=$(mktemp -d)

cleanup() {
    set +e # Don't care about errors here.
    if [ -n "$WORKDIR" ]; then
        if [ -n "$SQ_SAVE_LOGS" ]; then
            cp "$WORKDIR/squashfs_ll.log" "$SQ_SAVE_LOGS" || true
        fi
        if sq_is_mountpoint "$WORKDIR/mount"; then
            sq_umount "$WORKDIR/mount"
        fi
        rm -rf "$WORKDIR"
    fi
}

find_compressors

echo "Generating random test files..."
mkdir -p "$WORKDIR/source"
head -c 64000000 /dev/urandom >"$WORKDIR/source/rand1"
head -c 17000 /dev/urandom >"$WORKDIR/source/rand2"
head -c 100000000 /dev/urandom >"$WORKDIR/source/rand3"
mkdir -p "$WORKDIR/source/subdir"
head -c 23200 /dev/urandom > "$WORKDIR/source/subdir/rand4"
head -c 87 /dev/zero >"$WORKDIR/source/z1 with spaces"

for comp in $compressors; do
    echo "Building $comp squashfs image..."
    mksquashfs "$WORKDIR/source" "$WORKDIR/squashfs.image" -comp $comp -no-progress

    mkdir -p "$WORKDIR/mount"

    echo "Mounting squashfs image..."
    FIFO_1=$(mktemp -u)
    mkfifo "$FIFO_1"
    $SFLL -f $SFLL_EXTRA_ARGS -o notify_pipe="$FIFO_1" "$WORKDIR/squashfs.image" "$WORKDIR/mount" >"$WORKDIR/squahfs_ll.log" 2>&1 &
    # Wait for the archive to be mounted. TSAN builds can take some time to mount.
    STATUS=$(head -c1 "$FIFO_1")
    if [ "$STATUS" != "s" ]; then
        echo "Image did not mount successfully"
        cp "$WORKDIR/squahfs_ll.log" /tmp/squahfs_ll.smoke.log
        echo "There may be clues in /tmp/squahfs_ll.smoke.log"
        exit 1
    fi

    FIFO_2=$(mktemp -u)
    mkfifo "$FIFO_2"
    $SFLL -f $SFLL_EXTRA_ARGS -o notify_pipe="$FIFO_2" "$WORKDIR/squashfs.image" "$WORKDIR/nonexistent_mount" >"$WORKDIR/squahfs_ll.log" 2>&1 &
    # This time the mount command should fail because the mountpoint doesn't exist
    STATUS=$(head -c1 "$FIFO_2")
    if [ "$STATUS" != "f" ]; then
        echo "Image mounted successfully when it should have failed"
        cp "$WORKDIR/squahfs_ll.log" /tmp/squahfs_ll.smoke.log
        echo "There may be clues in /tmp/squahfs_ll.smoke.log"
        exit 1
    fi

    if command -v fio >/dev/null; then
        echo "FIO tests..."
        fio --filename="$WORKDIR/mount/rand1" --direct=1 --rw=randread --ioengine=libaio --bs=512 --iodepth=16 --numjobs=4 --name=j1 --minimal --output=/dev/null --runtime 30
        fio --filename="$WORKDIR/mount/rand2" --rw=randread --ioengine=libaio --bs=4k --iodepth=16 --numjobs=4 --name=j2 --minimal --output=/dev/null --runtime 30
        fio --filename="$WORKDIR/mount/rand3" --rw=randread --ioengine=psync --bs=128k --name=j3 --minimal --output=/dev/null --runtime 30
    else
        echo "Consider installing fio for better test coverage."
    fi

    echo "Comparing files..."
    cmp "$WORKDIR/source/rand1" "$WORKDIR/mount/rand1"
    cmp "$WORKDIR/source/rand2" "$WORKDIR/mount/rand2"
    cmp "$WORKDIR/source/rand3" "$WORKDIR/mount/rand3"
    cmp "$WORKDIR/source/subdir/rand4" "$WORKDIR/mount/subdir/rand4"
    cmp "$WORKDIR/source/z1 with spaces" "$WORKDIR/mount/z1 with spaces"

    echo "Parallel md5sum..."
    find "$WORKDIR/mount" -type f -exec md5sum \{\} >>"$WORKDIR/md5sums" \;
    split -l1 "$WORKDIR/md5sums" "$WORKDIR/sumpiece"
    echo "$WORKDIR"/sumpiece* | xargs -P4 -n1 md5sum -c

    echo "Lookup tests..."
    # Look for non-existent files to exercise failed lookup path.
    if [ -e "$WORKDIR/mount/bogus" ]; then
        echo "Bogus existence test"
        exit 1
    fi
    # Twice so we hit cache path.
    if [ -e "$WORKDIR/mount/bogus" ]; then
        echo "Bogus existence test #2"
        exit 1
    fi

    SRCSZ=$(wc -c < "$WORKDIR/source/rand1")
    MNTSZ=$(wc -c < "$WORKDIR/mount/rand1")
    if [ "$SRCSZ" != "$MNTSZ" ]; then
        echo "Bogus size $MNTSZ != $SRCSZ"
        exit 1
    fi

    echo "Unmounting..."
    sq_umount "$WORKDIR/mount"

    echo "Mounting subdirectory..."
    $SFLL $SFLL_EXTRA_ARGS -osubdir=subdir "$WORKDIR/squashfs.image" "$WORKDIR/mount"

    # Wait up to 5 seconds to be mounted. TSAN builds can take some time to mount.
    for _ in $(seq 5); do
    if sq_is_mountpoint "$WORKDIR/mount"; then
        break
    fi
    sleep 1
    done

    if ! sq_is_mountpoint "$WORKDIR/mount"; then
        echo "Image did not mount after 5 seconds."
        cp "$WORKDIR/squashfs_ll.log" /tmp/squashfs_ll.smoke.log
        echo "There may be clues in /tmp/squashfs_ll.smoke.log"
        exit 1
    fi

    echo "Comparing files in subdir..."
    cmp "$WORKDIR/source/subdir/rand4" "$WORKDIR/mount/rand4"

    echo "Unmounting..."
    sq_umount "$WORKDIR/mount"

    # Only test timeouts once, it takes a long time
    if [ -z "$did_timeout" ]; then
        echo "Remounting with idle unmount option..."
        $SFLL $SFLL_EXTRA_ARGS -otimeout=$IDLE_TIMEOUT "$WORKDIR/squashfs.image" "$WORKDIR/mount"
        if ! sq_is_mountpoint "$WORKDIR/mount"; then
            echo "Not mounted?"
            exit 1
        fi
        echo "Waiting up to $(( IDLE_TIMEOUT + 10 )) seconds for idle unmount..."
        sleep $(( IDLE_TIMEOUT + 10 ))
        if sq_is_mountpoint "$WORKDIR/mount"; then
            echo "FS did not idle unmount in timely way."
            exit 1
        fi

        did_timeout=yes
    fi

    rm -f "$WORKDIR/squashfs.image"
done

echo "Success."
exit 0
