#!/bin/bash

# Test matrix
FILESYSTEMS='NTFS={}   Ext2/3={journal=TRUE}'
SB_VERSIONS='0.90   1.0   1.1   1.2'
RAID_LEVELS='raid1   raid5'
DEV_SIZE="+128M"
HOSTNAME=$(hostname)
MULTIVERSION=false
LOOPDEV=false
STOP_MD_DM="/usr/share/install2/initinstall.d/80-stop-md-dm.sh"

# Floating point delay factor for sleep
DELAY_FACTOR=1.0

get_delay() {
	bc -l <<< "$DELAY_FACTOR*$1"
}

sleep_f() {
	sleep "$(get_delay "$1")"
}

while [[ $1 == --* ]]; do
	case "$1" in
	--help)
		printf "Usage:\n
Multi-volume test with identical superblock versions:
$0 [--delay=N]? [--loop=*]? [MD_COUNT] [<device>...]
MD_COUNT is a count of raid arrays

Multi-volume test with different superblock versions:
$0 --multiver [--delay=N]? [--loop=*] | [<device> ...]

'--delay=N'    - optional floating point factor that affects sleep duration, it's 1.0 by default.
'--loop=PATH'  - use loop devices instead of real. PATH is a directory when loop files will be created.
"
		exit 0
		;;

	--multiver)
		MULTIVERSION=true
		MD_ARRAY_COUNT=$(echo "$SB_VERSIONS" | wc -w)
		;;

	--loop=*)
		LOOPDEV=true
		LOOPDEV_PATH="${1##*=}"
		;;

	--delay=*)
		DELAY_FACTOR=${1##*=}
		;;
	esac

	shift
done

if [ $MULTIVERSION == false ]; then
	MD_ARRAY_COUNT="$1"
	shift
fi

DISKS=("$@")

if [ $LOOPDEV == true ]; then
	DISKS=()
	loopstart=0
	mkdir -p "$LOOPDEV_PATH"
	size=$((MD_ARRAY_COUNT*128+64))
	dd if=/dev/zero of="$LOOPDEV_PATH/loopfile0" bs=1M count=$size
	dd if=/dev/zero of="$LOOPDEV_PATH/loopfile1" bs=1M count=$size

	while [ ${#DISKS[@]} != 2 ]; do
		if losetup loop$loopstart "$LOOPDEV_PATH/loopfile${#DISKS[@]}" ; then
			DISKS+=("/dev/loop$loopstart")
		fi
		loopstart=$((loopstart+1))
	done
fi

ITERATIONS=$(echo "$FILESYSTEMS" | wc -w)
[ $MULTIVERSION == false ] && ITERATIONS=$((ITERATIONS * $(echo "$SB_VERSIONS" | wc -w)))
ITERATIONS=$((ITERATIONS * $(echo "$RAID_LEVELS" | wc -w)))
ITERATION=1

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
PURPLE='\033[1;35m'
NC='\033[0m'

if [ ! -t 1 ]; then
	RED=''
	GREEN=''
	YELLOW=''
	PURPLE=''
	NC=''
fi

LOG_STR=""
TEST_RES=true
LAST_TEST_RES=true

partition_name() {
	[ $LOOPDEV == true ] && echo "/dev/mapper/${1##*/}p$2" || echo "$1$2"
}

create_partitions() {
    for disk in "${DISKS[@]}"; do
        echo "Create partitions on $disk"
        cmd=$'g\n'
        for j in $(seq $MD_ARRAY_COUNT); do
            cmd+="n


$DEV_SIZE
"
        done
        fdisk -W always -w always "$disk" << EOF 1>/dev/null 2>/dev/null
$cmd
w
q
EOF
	if [ $LOOPDEV == true ]; then
		kpartx -u "$disk"
	fi
    done
    sleep_f 2
}

clear_disk() {
	echo "Clear disk $1"
	fdisk -W always "$1" << EOF > /dev/null
g
w
EOF
	sleep_f 1
}

clear_disks() {
	for i in "${!DISKS[@]}"; do
		clear_disk "${DISKS[i]}"
	done
}

create_md() {
	num="$1"
	num=$((num-1))
	COMMAND="mdadm --create /dev/md$num --name=test$num --level=$2 --metadata=$3 --raid-devices=${#DISKS[@]}"
	for i in "${!DISKS[@]}"; do
		COMMAND+=" $(partition_name ${DISKS[i]} $1)"
	done

	echo "$COMMAND"
	eval $COMMAND
	sleep_f 3
}

create_mds() {
	if [ $MULTIVERSION == true ]; then
		sb_versions=($SB_VERSIONS)
		for i in $(seq $MD_ARRAY_COUNT); do
			num=$((i-1))
			create_md "$i" "$1" "${sb_versions[num]}"
		done
	else
		for i in $(seq $MD_ARRAY_COUNT); do
			create_md "$i" "$1" "$2"
		done
	fi
}

stop_mds() {
	echo "mdadm -S --scan"
	mdadm -S --scan
	sleep_f 1
}

zero_superblocks() {
	for i in "${!DISKS[@]}"; do
		for j in $(seq $MD_ARRAY_COUNT); do
			echo "mdadm --zero-superblock $(partition_name ${DISKS[i]} $j)"
			mdadm --zero-superblock "$(partition_name ${DISKS[i]} $j)"
			sleep_f 0.1
		done
	done
}

evms_mkfs() {
	#echo "evms format: $1, \"/dev/evms/$HOSTNAME:test$num\""
	evms -s << EOF
format: $1, "/dev/evms/$2"
EOF
	sleep_f 3
}

initinstall_stop_md_dm() {
	echo -e "${YELLOW}Run ${STOP_MD_MD}${NC}"
	${STOP_MD_DM}
	sleep_f 1
}

evms_mkfs_all() {
	vers=($SB_VERSIONS)
	for i in $(seq $MD_ARRAY_COUNT); do
		num=$((i-1))
		initinstall_stop_md_dm
		if { [ "$MULTIVERSION" == true ] && [ "${vers[num]}" == '0.90' ]; } || [ "$2" == '0.90' ]; then
			evms_mkfs $1 "md/md$num"
		else
			evms_mkfs $1 "$HOSTNAME:test$num"
		fi
	done
}

zero_partitions() {
	for disk in "${DISKS[@]}"; do
		for i in $(seq $MD_ARRAY_COUNT); do
			echo "dd if=/dev/zero of=$disk$i"
			dd if=/dev/zero of="$disk$i" 1>/dev/null 2>/dev/null
		done
	done
}

read_write_test() {
	mkdir /mnt/evms_test
	echo -e "${YELLOW}mount $1 ${NC}"
	if ! mount "$1" /mnt/evms_test; then
		echo -e "${RED} Failed to mount $1 ${NC}"
		rm -rf /mnt/evms_test
		TEST_RES=false
		LAST_TEST_RES=false
		return
	fi

	printf "${YELLOW}read/write test on $1... ${NC}"

	echo "write test lmao" > /mnt/evms_test/test
	value=$(cat /mnt/evms_test/test)

	if [ "$value" == 'write test lmao' ]; then
		echo -e "${GREEN}OK!${NC}"
		LAST_TEST_RES=true
	else
		echo -e "${RED}FAILED${NC}"
		TEST_RES=false
		LAST_TEST_RES=false
	fi

	umount "$1"
	sleep_f 0.1
	rm -rf /mnt/evms_test
}

read_write_test_all() {
	ver="$1"
	for i in $(seq $MD_ARRAY_COUNT); do
		num=$((i-1))
		[ $MULTIVERSION == true ] && ver="${sb_versions[num]}"
		[ "$ver" == "0.90" ] && read_write_test "/dev/evms/md/md$num" || \
			read_write_test "/dev/evms/.nodes/$HOSTNAME:test$num"
	done
}

test_iteration() {
	[ $MULTIVERSION == true ] && sbs="$SB_VERSIONS" || sbs="$1"
	printf "\n${GREEN}Iteration $ITERATION/$ITERATIONS${NC}\n"
	INFO="${YELLOW}Superblock: ${PURPLE}$sbs${YELLOW}  RAID: ${PURPLE}$2${YELLOW}  FS: ${PURPLE}$3${NC}"
	echo -e "$INFO"
	create_partitions
	#zero_partitions
	create_mds "$2" "$1"
	evms_mkfs_all "$3" "$1"
	read_write_test_all "$1"

	LOG_STR+="$INFO"
	if [ $LAST_TEST_RES == true ]; then
		LOG_STR+="   ${GREEN}OK${NC}\n"
	else
		LOG_STR+="   ${RED}FAILED${NC}\n"
	fi

	stop_mds
	[ $LOOPDEV == false ] && initinstall_stop_md_dm
	zero_superblocks
	[ $LOOPDEV == true ] && initinstall_stop_md_dm
	clear_disks
	[ $LOOPDEV == true ] && initinstall_stop_md_dm

	rm -rf '/dev/evms'

	ITERATION=$((ITERATION+1))
}

printf "${YELLOW}Iterations count: $ITERATIONS\n"
printf "Test matrix:${PURPLE}\n"
[ $MULTIVERSION == false ] && printf "$SB_VERSIONS\n"
printf "$RAID_LEVELS\n$FILESYSTEMS${NC}\n"

for fs in $FILESYSTEMS; do
	for raid_level in $RAID_LEVELS; do
		if [ $MULTIVERSION == true ]; then
			test_iteration "" "$raid_level" "$fs"
		else
			for sb_ver in $SB_VERSIONS; do
				test_iteration "$sb_ver" "$raid_level" "$fs"
			done
		fi
	done
done

printf "\n${YELLOW}Results:${NC}\n$LOG_STR"

if [ $TEST_RES == true ]; then
	printf "${GREEN}\nAll test are OK${NC}\n"
else
	printf "${RED}\nSome tests failed${NC}\n"
fi


if [ $LOOPDEV == true ]; then
	for loopdev in ${DISKS[@]}; do
		losetup -d "$loopdev"
	done

	rm -rf "$LOOPDEV_PATH/loopfile0"
	rm -rf "$LOOPDEV_PATH/loopfile1"
fi
