#!/usr/bin/env bash

# osync test suite 2023061401


# Allows the following environment variables
# RUNNING_ON_GITHUB_ACTIONS=[true|false]
# SSH_PORT=22
# SKIP_REMOTE=[true|false]

## On Mac OSX, this needs to be run as root in order to use sudo without password
## From current terminal run sudo -s in order to get a new terminal as root

## On CYGWIN / MSYS, ACL and extended attributes aren't supported

# 4 tests:
# quicklocal
# quickremote (with ssh_filter.sh)
# conflocal
# confremote (with ssh_filter.sh)

# for each test
# 	files with spaces, subdirs
# 	largefileset (...large ?)
#	quickremote test with controlmaster enabled
# 	exclusions
# 	conflict resolution initiator with backups / multiple backups
# 	conflict resolution target with backups / multiple backups
# 	deletion propagation, failed deletion repropagation, skip deletion
#	symlink and broken symlink propagation and deletion
# 	replica lock checks
#	file attribute tests
# 	local / remote locking resume tests
#	conflict detection
#	timed execution tests

# function test
# WaitForTaskCompletion
# ParallelExec
# daemon mode tests for both config files

# on BSD, remount UFS with ACL support using mount -o acls /
# setfacl needs double ':' to be compatible with both linux and BSD
# setfacl -m o::rwx file

# On Windows 10 bash, we need to create host SSH keys first with ssh-keygen -A
# Then start ssh with service ssh start

# TODO, use copies of config file on each test function

if [ "$SKIP_REMOTE" = "" ]; then
	SKIP_REMOTE=false
	REMOTE_USER=root
fi

homedir=$(eval echo ~${REMOTE_USER})

# drupal servers are often unreachable for whetever reason or give 0 bytes files
#LARGE_FILESET_URL="http://ftp.drupal.org/files/projects/drupal-8.2.2.tar.gz"
LARGE_FILESET_URL="https://ftp.drupal.org/files/projects/drupal-11.0.10.tar.gz"

OSYNC_DIR="$(pwd)"
OSYNC_DIR=${OSYNC_DIR%%/dev*}
DEV_DIR="$OSYNC_DIR/dev"
TESTS_DIR="$DEV_DIR/tests"

# Fakeroot for install / uninstall and test of executables
FAKEROOT="${homedir}/osync_test_install"

CONF_DIR="$TESTS_DIR/conf"
LOCAL_CONF="local.conf"
REMOTE_CONF="remote.conf"
OLD_CONF="old.conf"
TMP_OLD_CONF="tmp.old.conf"

OSYNC_EXECUTABLE="$FAKEROOT/usr/local/bin/osync.sh"
OSYNC_DEV_EXECUTABLE="dev/n_osync.sh"
OSYNC_UPGRADE="upgrade-v1.0x-v1.3x.sh"
TMP_FILE="$DEV_DIR/tmp"


OSYNC_TESTS_DIR="${homedir}/osync-tests"
INITIATOR_DIR="$OSYNC_TESTS_DIR/initiator"
TARGET_DIR="$OSYNC_TESTS_DIR/target"
OSYNC_WORKDIR=".osync_workdir"
OSYNC_STATE_DIR="$OSYNC_WORKDIR/state"
OSYNC_DELETE_DIR="$OSYNC_WORKDIR/deleted"
OSYNC_BACKUP_DIR="$OSYNC_WORKDIR/backup"

# Later populated variables
OSYNC_VERSION=1.x.y
OSYNC_MIN_VERSION=x
OSYNC_IS_STABLE=maybe

PRIVKEY_NAME="id_rsa_local_osync_tests"
PUBKEY_NAME="${PRIVKEY_NAME}.pub"

function SetupSSH {
	echo "Setting up an ssh key to ${homedir}/.ssh/${PRIVKEY_NAME}"
	echo -e  'y\n'| ssh-keygen -t rsa -b 2048 -N "" -f "${homedir}/.ssh/${PRIVKEY_NAME}"



	SSH_AUTH_LINE="from=\"*\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command=\"$FAKEROOT/usr/local/bin/ssh_filter.sh SomeAlphaNumericToken9\" $(cat ${homedir}/.ssh/${PUBKEY_NAME})"
	echo "ls -alh ${homedir}"
	ls -alh "${homedir}"
	echo "ls -alh ${homedir}/.ssh"
	ls -alh "${homedir}/.ssh"

	if [ -f "${homedir}/.ssh/authorized_keys" ]; then
		if ! grep "$(cat ${homedir}/.ssh/${PUBKEY_NAME})" "${homedir}/.ssh/authorized_keys"; then
			echo "Adding auth line in authorized_keys file ${homedir}/.ssh/authorized_keys"
			echo "$SSH_AUTH_LINE" >> "${homedir}/.ssh/authorized_keys"
		fi
	else
		echo "Creating authorized_keys file ${homedir}/.ssh/authorized_keys"
		echo "$SSH_AUTH_LINE" >> "${homedir}/.ssh/authorized_keys"
	fi
	chmod 600 "${homedir}/.ssh/authorized_keys"

	# Add localhost to known hosts so self connect works
	if [ -z "$(ssh-keygen -F localhost)" ]; then
		ssh-keyscan -H localhost >> "${homedir}/.ssh/known_hosts"
	fi

	# Update remote conf files with SSH port and file id location
	sed -i.tmp 's#ssh://.*@localhost:[0-9]*/${HOME}/osync-tests/target#ssh://'$REMOTE_USER'@localhost:'$SSH_PORT'/'${homedir}'/osync-tests/target#' "$CONF_DIR/$REMOTE_CONF"
	sed -i.tmp2 's#SSH_RSA_PRIVATE_KEY="${HOME}/.ssh/id_rsa_local_osync_tests"#SSH_RSA_PRIVATE_KEY="'${homedir}'/.ssh/id_rsa_local_osync_tests"#' "$CONF_DIR/$REMOTE_CONF"

	echo "ls -alh ${homedir}/.ssh"
	ls -alh "${homedir}/.ssh"
	echo "cat ${homedir}/.ssh/authorized_keys" 
	cat "${homedir}/.ssh/authorized_keys"
	
	echo "###"
	echo "END SETUP SSH"
}

function RemoveSSH {
	echo "Now removing SSH keys"
	if [ -f "${homedir}/.ssh/id_rsa_local_osync_tests" ]; then
		echo "Restoring SSH authorized_keys file"
		sed -i.bak "s|.*$(cat "${homedir}/.ssh/id_rsa_local_osync_tests.pub")||g" "${homedir}/.ssh/authorized_keys"
		rm -f "${homedir}/.ssh/{id_rsa_local_osync_tests.pub,id_rsa_local_osync_tests}"
	fi
}

function DownloadLargeFileSet() {
	local destinationPath="${1}"

	cd "$OSYNC_DIR"
	if type wget > /dev/null 2>&1; then
		wget -q --no-check-certificate "$LARGE_FILESET_URL" > /dev/null
		assertEquals "Download [$LARGE_FILESET_URL] with wget." "0" $?
	elif type curl > /dev/null 2>&1; then
		curl -O -L "$LARGE_FILESET_URL" > /dev/null 2>&1
		assertEquals "Download [$LARGE_FILESET_URL] with curl." "0" $?
	fi

	tar xf "$(basename $LARGE_FILESET_URL)" -C "$destinationPath"
	assertEquals "Extract $(basename $LARGE_FILESET_URL)" "0" $?

	rm -f "$(basename $LARGE_FILESET_URL)"
}

function CreateOldFile () {
	local drive
	local filePath="${1}"
	local type="${2:-false}"

	if [ $type == true ]; then
		mkdir -p "$filePath"
	else
		mkdir -p "$(dirname $filePath)"
		touch "$filePath"
	fi

	assertEquals "touch [$filePath]" "0" $?

	# Get current drive
	drive=$(df "$OSYNC_DIR" | tail -1 | awk '{print $1}')

	# modify ctime on ext4 so osync thinks it has to delete the old files
	debugfs -w -R 'set_inode_field "'$filePath'" ctime 201001010101' $drive
	assertEquals "CreateOldFile [$filePath]" "0" $?

	# force update of inodes (ctimes)
	echo 3 > /proc/sys/vm/drop_caches
	assertEquals "Drop caches" "0" $?
}

function PrepareLocalDirs () {
	if [ -d "$OSYNC_TESTS_DIR" ]; then
		rm -rf "$OSYNC_TESTS_DIR"
	fi
	mkdir "$OSYNC_TESTS_DIR"
	mkdir "$INITIATOR_DIR"
	mkdir "$TARGET_DIR"
}

function oneTimeSetUp () {
	START_TIME=$SECONDS

	#echo "Running forced merge"
	#cd "${DEV_DIR}"
	#$SUDO_CMD ./merge.sh osync
	echo "Setting security for files"
	$SUDO_CMD find ${OSYNC_DIR} -exec chmod 755 {} \+ 

	echo "Show content of osync dir"
	ls -alh ${OSYNC_DIR}
	echo "Running install.sh from ${OSYNC_DIR}"
	$SUDO_CMD ${OSYNC_DIR}/install.sh --no-stats --prefix="${FAKEROOT}"
	source "$DEV_DIR/ofunctions.sh"

	# Fix default umask because of ACL test that expects 0022 when creating test files
	umask 0022

	GetLocalOS

	echo "Detected OS: $LOCAL_OS"

	# Set some travis related changes
	if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ]; then
	echo "Running with GITHUB ACTIONS settings"
		#REMOTE_USER="runner"
		REMOTE_USER="root" # WIP
		homedir=$(eval echo ~${REMOTE_USER})
		RHOST_PING=false
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "REMOTE_3RD_PARTY_HOSTS" ""
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "REMOTE_HOST_PING" false

		SetConfFileValue "$CONF_DIR/$OLD_CONF" "REMOTE_3RD_PARTY_HOSTS" ""
		SetConfFileValue "$CONF_DIR/$OLD_CONF" "REMOTE_HOST_PING" false

	else
		echo "Running with local settings"
		REMOTE_USER="root"
		homedir=$(eval echo ~${REMOTE_USER})
		RHOST_PING=true
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "REMOTE_3RD_PARTY_HOSTS" "\"www.kernel.org www.google.com\""
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "REMOTE_HOST_PING" true

		SetConfFileValue "$CONF_DIR/$OLD_CONF" "REMOTE_3RD_PARTY_HOSTS" "\"www.kernel.org www.google.com\""
		SetConfFileValue "$CONF_DIR/$OLD_CONF" "REMOTE_HOST_PING" true
	fi


	# Fix test directories for Github actions
	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" INITIATOR_SYNC_DIR "\"${homedir}/osync-tests/initiator\""
	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" TARGET_SYNC_DIR "\"${homedir}/osync-tests/target\""

	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" INITIATOR_SYNC_DIR "\"${homedir}/osync-tests/initiator\""

	SetConfFileValue "$CONF_DIR/$OLD_CONF" MASTER_SYNC_DIR "\"${homedir}/osync-tests/initiator\""
	SetConfFileValue "$CONF_DIR/$OLD_CONF" SLAVE_SYNC_DIR "\"${homedir}/osync-tests/target\""


	# Get default ssh port from env
	if [ "$SSH_PORT" == "" ]; then
		SSH_PORT=22
		echo "Running with SSH_PORT=${SSH_PORT}"
	fi

	# Setup modes per test
	readonly __quickLocal=0
	readonly __quickRemote=1
	readonly __confLocal=2
	readonly __confRemote=3

	osyncParameters=()
	osyncParameters[$__quickLocal]="--initiator=$INITIATOR_DIR --target=$TARGET_DIR --instance-id=quicklocal --non-interactive"
	osyncParameters[$__confLocal]="$CONF_DIR/$LOCAL_CONF --non-interactive"

	osyncDaemonParameters=()

	readonly __local
	readonly __remote

	osyncDaemonParameters[$__local]="$CONF_DIR/$LOCAL_CONF --on-changes"

  # Do not check remote config on msys or cygwin since we don't have a local SSH server
	if [ "$LOCAL_OS" != "msys" ] && [ "$LOCAL_OS" != "Cygwin" ] && [ $SKIP_REMOTE != true ]; then
		osyncParameters[$__quickRemote]="--initiator=$INITIATOR_DIR --target=ssh://localhost:$SSH_PORT/$TARGET_DIR --rsakey=${homedir}/.ssh/id_rsa_local_osync_tests --instance-id=quickremote --remote-token=SomeAlphaNumericToken9 --non-interactive"
		osyncParameters[$__confRemote]="$CONF_DIR/$REMOTE_CONF --non-interactive"

		osyncDaemonParameters[$__remote]="$CONF_DIR/$REMOTE_CONF --on-changes"

		SetupSSH
	fi

	#TODO: Assuming that macos has the same syntax than bsd here
	if [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
		SUDO_CMD=""
	elif [ "$LOCAL_OS" == "BSD" ] || [ "$LOCAL_OS" == "MacOSX" ]; then
		SUDO_CMD=""
		IMMUTABLE_ON_CMD="chflags schg"
		IMMUTABLE_OFF_CMD="chflags noschg"
	else
		IMMUTABLE_ON_CMD="chattr +i"
		IMMUTABLE_OFF_CMD="chattr -i"
		SUDO_CMD="sudo"
	fi

	# Get osync version
	OSYNC_VERSION=$(GetConfFileValue "$OSYNC_DIR/$OSYNC_DEV_EXECUTABLE" "PROGRAM_VERSION")
	OSYNC_VERSION="${OSYNC_VERSION##*=}"
	OSYNC_MIN_VERSION="${OSYNC_VERSION:2:1}"

	OSYNC_IS_STABLE=$(GetConfFileValue "$OSYNC_DIR/$OSYNC_DEV_EXECUTABLE" "IS_STABLE")

	echo "Running with $OSYNC_VERSION ($OSYNC_MIN_VERSION) STABLE=$OSYNC_IS_STABLE"

	# Be sure to set default values for config files which can be incoherent if tests gets aborted
	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "SKIP_DELETION" ""
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "SKIP_DELETION" ""

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "COPY_SYMLINKS" false
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "COPY_SYMLINKS" false

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "CONFLICT_BACKUP_MULTIPLE" false
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "CONFLICT_BACKUP_MULTIPLE" false

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "FORCE_STRANGER_LOCK_RESUME" false
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "FORCE_STRANGER_LOCK_RESUME" false

	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "SOFT_MAX_EXEC_TIME" "7200"
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "HARD_MAX_EXEC_TIME" "10600"

}

function oneTimeTearDown () {

	# Set osync version stable flag back to origin
	#SetConfFileValue "$OSYNC_DIR/osync.sh" "IS_STABLE" "$OSYNC_IS_STABLE"

	if [ "$SKIP_REMOTE" != true ]; then
		RemoveSSH
	fi

	#TODO: uncomment this when dev is done
	#rm -rf "$OSYNC_TESTS_DIR"
	rm -f "$TMP_FILE"

	cd "$OSYNC_DIR"
	echo ""
	echo "Uninstalling osync from $FAKEROOT"
	$SUDO_CMD ./install.sh --remove --no-stats --prefix="$FAKEROOT"
	assertEquals "Uninstall failed" "0" $?

	ELAPSED_TIME=$((SECONDS-START_TIME))
	echo "It took $ELAPSED_TIME seconds to run these tests."
}

function setUp () {
	rm -rf "$INITIATOR_DIR"
	rm -rf "$TARGET_DIR"
}

function test_SSH {
	# Make sure we have SSH on your test server
	# This has become kind of tricky on github actions servers
	echo "Testing SSH"

	failure=false

	# Testing as "remote user"
	echo "ls -alh ${homedir}/.ssh"
	ls -alh "${homedir}/.ssh"

	echo "Running SSH test as ${REMOTE_USER}"
	# SSH_PORT and SSH_USER are set by oneTimeSetup
	$SUDO_CMD ssh -i "${homedir}/.ssh/${PRIVKEY_NAME}" -p $SSH_PORT ${REMOTE_USER}@localhost "env _REMOTE_TOKEN=SomeAlphaNumericToken9 echo \"Remotely:\"; whoami; echo \"TEST OK\""
	if [ $? -ne 0 ]; then
		echo "SSH test failed"
		failure=true
	fi

	# Testing as current user
	#echo "ls -alh ${homedir}/.ssh"
	#ls -alh "${homedir}/.ssh"
	
	#echo "Running SSH test as $(whoami)"
	#$SUDO_CMD ssh -i "${homedir}/.ssh/${PRIVKEY_NAME}" -p $SSH_PORT $(whoami)@localhost "env _REMOTE_TOKEN=SomeAlphaNumericToken9 echo \"Remotely:\"; whoami; echo \"TEST OK\""
	#if [ $? -ne 0 ]; then
	#	echo "SSH test failed"
	#	failure=true
	#fi
	
	if [ $failure == true ]; then
		exit 1 # Try to see if we can abort all tests
		assertEquals "Test SSH failed" false $failure
	fi
}

# This test has to be done everytime in order for osync executable to be fresh
function test_Merge () {
	cd "$DEV_DIR"
	./merge.sh osync
	assertEquals "Merging code" "0" $?

	#WIP use debug code
	alias cp=cp
	cp "$DEV_DIR/debug_osync.sh" "$OSYNC_DIR/osync.sh"

	cd "$OSYNC_DIR"

	echo ""
	echo "Installing osync to $FAKEROOT"
	$SUDO_CMD ./install.sh --no-stats --prefix="$FAKEROOT"

	# Set osync version to stable while testing to avoid warning message
	# Don't use SetConfFileValue here since for whatever reason Travis does not like creating a sed temporary file in $FAKEROOT

	if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ]; then
		$SUDO_CMD sed -i.tmp 's/^IS_STABLE=.*/IS_STABLE=true/' "$OSYNC_EXECUTABLE"
	else
		sed -i.tmp 's/^IS_STABLE=.*/IS_STABLE=true/' "$OSYNC_EXECUTABLE"
	fi
	#SetConfFileValue "$OSYNC_EXECUTABLE" "IS_STABLE" true


	assertEquals "Install failed" "0" $?
}

function test_LargeFileSet () {
	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs
		DownloadLargeFileSet "$INITIATOR_DIR"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "LargeFileSet test with parameters [$i]." "0" $?

		[ -d "$INITIATOR_DIR/$OSYNC_STATE_DIR" ]
		assertEquals "Initiator state dir exists" "0" $?

		[ -d "$TARGET_DIR/$OSYNC_STATE_DIR" ]
		assertEquals "Target state dir exists" "0" $?
	done
}

function test_controlMaster () {
	cd "$OSYNC_DIR"

	PrepareLocalDirs
	echo "Running with parameters ${osyncParameters[$__quickRemote]} --ssh-controlmaster"
	REMOTE_HOST_PING=$REMOTE_PING $OSYNC_EXECUTABLE ${osyncParameters[$__quickRemote]} --ssh-controlmaster
	assertEquals "Running quick remote test with controlmaster enabled." "0" $?
}

function test_Exclusions () {
	# Will sync except php files
	# RSYNC_EXCLUDE_PATTERN="*.php" is set at runtime for quicksync and in config files for other runs

	local numberOfPHPFiles
	local numberOfExcludedFiles
	local numberOfInitiatorFiles
	local numberOfTargetFiles

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs
		DownloadLargeFileSet "$INITIATOR_DIR"

		numberOfPHPFiles=$(find "$INITIATOR_DIR" ! -wholename "$INITIATOR_DIR/$OSYNC_WORKDIR*" -name "*.php" | wc -l)

		REMOTE_HOST_PING=$RHOST_PING RSYNC_EXCLUDE_PATTERN="*.php" $OSYNC_EXECUTABLE $i
		assertEquals "Exclusions with parameters [$i]." "0" $?

		numberOfInitiatorFiles=$(find "$INITIATOR_DIR" ! -wholename "$INITIATOR_DIR/$OSYNC_WORKDIR*" | wc -l)
		numberOfTargetFiles=$(find "$TARGET_DIR" ! -wholename "$TARGET_DIR/$OSYNC_WORKDIR*" | wc -l)
		numberOfExcludedFiles=$((numberOfInitiatorFiles-numberOfTargetFiles))

		assertEquals "Number of php files: $numberOfPHPFiles - Number of excluded files: $numberOfExcludedFiles" $numberOfPHPFiles $numberOfExcludedFiles
	done
}

function test_Deletetion () {
	local iFile1="$INITIATOR_DIR/i fic"
	local iFile2="$INITIATOR_DIR/i foc (something)"
	local tFile1="$TARGET_DIR/t fic"
	local tFile2="$TARGET_DIR/t foc [nothing]"


	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs
		touch "$iFile1"
		touch "$iFile2"
		touch "$tFile1"
		touch "$tFile2"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		rm -f "$iFile1"
		rm -f "$tFile1"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Second deletion run with parameters [$i]." "0" $?

		[ -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$(basename $iFile1)" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$(basename $iFile1)] has been soft deleted on target" "0" $?
		[ -f "$iFile1" ]
		assertEquals "File [$iFile1] is still in initiator" "1" $?

		# The variable substitution is not the best comprehensible code
		[ -f "${iFile1/$INITIATOR_DIR/TARGET_DIR}" ]
		assertEquals "File [${iFile1/$INITIATOR_DIR/TARGET_DIR}] is still in target" "1" $?

		[ -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$(basename $tFile1)" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$(basename $tFile1)] has been soft deleted on initiator" "0" $?
		[ -f "$tFile1" ]
		assertEquals "File [$tFile1] is still in target" "1" $?

		[ -f "${tFile1/$TARGET_DIR/INITIATOR_DIR}" ]
		assertEquals "File [${tFile1/$TARGET_DIR/INITIATOR_DIR}] is still in initiator" "1" $?
	done
}

function test_deletion_failure () {
	if [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
		echo "Skipping deletion failure test as Win10 does not have chattr  support."
		return 0
	fi

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs

		DirA="some directory with spaces"
		DirB="another directoy/and sub directory"

		mkdir -p "$INITIATOR_DIR/$DirA"
		mkdir -p "$TARGET_DIR/$DirB"

		FileA="$DirA/File A"
		FileB="$DirB/File B"

		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		rm -f "$INITIATOR_DIR/$FileA"
		rm -f "$TARGET_DIR/$FileB"

		# Prevent files from being deleted
		$SUDO_CMD $IMMUTABLE_ON_CMD "$TARGET_DIR/$FileA"
		$SUDO_CMD $IMMUTABLE_ON_CMD "$INITIATOR_DIR/$FileB"

		# This shuold fail with exitcode 1
		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Second deletion run with parameters [$i]." "1" $?

		# standard file tests
		[ -f "$TARGET_DIR/$FileA" ]
		assertEquals "File [$TARGET_DIR/$FileA] is still present in replica dir." "0" $?
		[ ! -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA] is not present in deletion dir." "0" $?

		[ -f "$INITIATOR_DIR/$FileB" ]
		assertEquals "File [$INITIATOR_DIR/$FileB] is still present in replica dir." "0" $?
		[ ! -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB] is not present in deletion dir." "0" $?

		# Allow files from being deleted
		$SUDO_CMD $IMMUTABLE_OFF_CMD "$TARGET_DIR/$FileA"
		$SUDO_CMD $IMMUTABLE_OFF_CMD "$INITIATOR_DIR/$FileB"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i --verbose
		assertEquals "Third deletion run with parameters [$i]." "0" $?

		[ ! -f "$TARGET_DIR/$FileA" ]
		assertEquals "File [$TARGET_DIR/$FileA] is still present in replica dir." "0" $?
		[ -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA] is not present in deletion dir." "0" $?

		[ ! -f "$INITIATOR_DIR/$FileB" ]
		assertEquals "File [$INITIATOR_DIR/$FileB] is still present in replica dir." "0" $?
		[ -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB] is not present in deletion dir." "0" $?
	done
}

function test_skip_deletion () {
	local modes

	if [ "$OSYNC_MIN_VERSION" == "1" ]; then
		echo "Skipping SkipDeletion test because it wasn't implemented in osync v1.1."
		return 0
	fi

	# TRAVIS SPECIFIC - time limitation
	if [ "$RUNNING_ON_GITHUB_ACTIONS" != true ]; then
		modes=('initiator' 'target' 'initiator,target')
	else
		modes=('target')
	fi

	for mode in "${modes[@]}"; do

		SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "SKIP_DELETION" "$mode"
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "SKIP_DELETION" "$mode"

		for i in "${osyncParameters[@]}"; do
			cd "$OSYNC_DIR"
			PrepareLocalDirs

			DirA="another/one/bites/ de_dust"
			DirB="phantom of /the opera"

			mkdir -p "$INITIATOR_DIR/$DirA"
			mkdir -p "$TARGET_DIR/$DirB"

			FileA="$DirA/Iron Rhapsody"
			FileB="$DirB/Bohemian Maiden"

			touch "$INITIATOR_DIR/$FileA"
			touch "$TARGET_DIR/$FileB"

			# First run
			REMOTE_HOST_PING=$RHOST_PING SKIP_DELETION="$mode" $OSYNC_EXECUTABLE $i
			assertEquals "First deletion run with parameters [$i]." "0" $?

			rm -f "$INITIATOR_DIR/$FileA"
			rm -f "$TARGET_DIR/$FileB"

			# Second run
			REMOTE_HOST_PING=$RHOST_PING SKIP_DELETION="$mode" $OSYNC_EXECUTABLE $i
			assertEquals "First deletion run with parameters [$i]." "0" $?

			if [ "$mode" == "initiator" ]; then
				[ -f "$TARGET_DIR/$FileA" ]
				assertEquals "File [$TARGET_DIR/$FileA] still exists in mode $mode." "1" $?
				[ -f "$INITIATOR_DIR/$FileB" ]
				assertEquals "File [$INITIATOR_DIR/$FileB still exists in mode $mode." "0" $?

			elif [ "$mode" == "target" ]; then
				[ -f "$TARGET_DIR/$FileA" ]
				assertEquals "File [$TARGET_DIR/$FileA] still exists in mode $mode." "0" $?
				[ -f "$INITIATOR_DIR/$FileB" ]
				assertEquals "File [$INITIATOR_DIR/$FileB still exists in mode $mode." "1" $?


			elif [ "$mode" == "initiator,target" ]; then
				[ -f "$TARGET_DIR/$FileA" ]
				assertEquals "File [$TARGET_DIR/$FileA] still exists in mode $mode." "0" $?
				[ -f "$INITIATOR_DIR/$FileB" ]
				assertEquals "File [$INITIATOR_DIR/$FileB still exists in mode $mode." "0" $?
			else
				assertEquals "Bogus skip deletion mode" "0" "1"
			fi
		done
	done

	# Set original values back
	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "SKIP_DELETION" ""
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "SKIP_DELETION" ""
}

function test_handle_symlinks () {
	if [ "$OSYNC_MIN_VERSION" == "1" ]; then
		echo "Skipping symlink tests as osync v1.1x didn't handle this."
		return 0
	fi

	if [ "$LOCAL_OS" == "msys" ]; then
		echo "Skipping symlink tests because msys handles them strangely or not at all."
		return 0
	fi

	# Check with and without copySymlinks
	copySymlinks=false

	echo "Running with COPY_SYMLINKS=$copySymlinks"

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "COPY_SYMLINKS" "$copySymlinks"
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "COPY_SYMLINKS" "$copySymlinks"

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs

		DirA="some directory with spaces"
		DirB="another directoy/and sub directory"

		mkdir -p "$INITIATOR_DIR/$DirA"
		mkdir -p "$TARGET_DIR/$DirB"

		FileA="$DirA/File A"
		FileB="$DirB/File B"
		FileAL="$DirA/File A symlink"
		FileBL="$DirB/File B symlink"

		# Create symlinks
		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"
		ln -s "$INITIATOR_DIR/$FileA" "$INITIATOR_DIR/$FileAL"
		ln -s "$TARGET_DIR/$FileB" "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First symlink run with parameters [$i]." "0" $?

		# Delete symlinks
		rm -f "$INITIATOR_DIR/$FileAL"
		rm -f "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Second symlink deletion run with parameters [$i]." "0" $?

		# symlink deletion propagation
		[ ! -L "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is still present in replica dir." "0" $?
		[ -L "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL] is not present in deletion dir." "0" $?
		[ ! -L "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is still present in replica dir." "0" $?
		[ -L "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL] is not present in deletion dir." "0" $?

		# Create broken symlinks and propagate them
		ln -s "$INITIATOR_DIR/$FileA" "$INITIATOR_DIR/$FileAL"
		ln -s "$TARGET_DIR/$FileB" "$TARGET_DIR/$FileBL"
		rm -f "$INITIATOR_DIR/$FileA"
		rm -f "$TARGET_DIR/$FileB"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Third broken symlink run with parameters [$i]." "0" $?

		[ -L "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is present in replica dir." "0" $?

		[ -L "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is present in replica dir." "0" $?

		# Check broken symlink deletion propagation
		rm -f "$INITIATOR_DIR/$FileAL"
		rm -f "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Fourth symlink deletion run with parameters [$i]." "0" $?

		[ ! -L "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is still present in replica dir." "0" $?
		[ -L "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL] is not present in deletion dir." "0" $?
		[ ! -L "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is still present in replica dir." "0" $?
		[ -L "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL] is not present in deletion dir." "0" $?
	done

	# TRAVIS SPECIFIC - time limitation
	if [ "$RUNNING_ON_GITHUB_ACTIONS" != true ]; then
		return 0
	fi

	# Check with and without copySymlinks
	copySymlinks=true

	echo "Running with COPY_SYMLINKS=$copySymlinks"

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "COPY_SYMLINKS" "$copySymlinks"
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "COPY_SYMLINKS" "$copySymlinks"

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"

		PrepareLocalDirs

		DirA="some directory with spaces"
		DirB="another directoy/and sub directory"

		mkdir -p "$INITIATOR_DIR/$DirA"
		mkdir -p "$TARGET_DIR/$DirB"

		FileA="$DirA/File A"
		FileB="$DirB/File B"
		FileAL="$DirA/File A symlink"
		FileBL="$DirB/File B symlink"

		# Create symlinks
		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"
		ln -s "$INITIATOR_DIR/$FileA" "$INITIATOR_DIR/$FileAL"
		ln -s "$TARGET_DIR/$FileB" "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First symlink run with parameters [$i]." "0" $?

		# Delete symlinks
		rm -f "$INITIATOR_DIR/$FileAL"
		rm -f "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Second symlink deletion run with parameters [$i]." "0" $?

		# symlink deletion propagation
		[ ! -f "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is still present in replica dir." "0" $?
		[ -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL] is not present in deletion dir." "0" $?
		[ ! -f "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is still present in replica dir." "0" $?
		[ -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL] is not present in deletion dir." "0" $?

		# Create broken symlinks and propagate them
		ln -s "$INITIATOR_DIR/$FileA" "$INITIATOR_DIR/$FileAL"
		ln -s "$TARGET_DIR/$FileB" "$TARGET_DIR/$FileBL"
		rm -f "$INITIATOR_DIR/$FileA"
		rm -f "$TARGET_DIR/$FileB"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Third broken symlink run with parameters should fail [$i]." "1" $?

		[ ! -f "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is present in replica dir." "0" $?

		[ ! -f "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is present in replica dir." "0" $?

		# Check broken symlink deletion propagation
		rm -f "$INITIATOR_DIR/$FileAL"
		rm -f "$TARGET_DIR/$FileBL"

		COPY_SYMLINKS=$copySymlinks REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Fourth symlink deletion run should resume with parameters [$i]." "0" $?

		[ ! -f "$TARGET_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$FileAL] is still present in replica dir." "0" $?
		[ -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileAL] is not present in deletion dir." "0" $?
		[ ! -f "$INITIATOR_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$FileBL] is still present in replica dir." "0" $?
		[ -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileBL] is not present in deletion dir." "0" $?
	done
}

function test_softdeletion_cleanup () {
	#declare -A files

	files=()
	files[0]="$INITIATOR_DIR/$OSYNC_DELETE_DIR/someDeletedFileInitiator"
	files[1]="$TARGET_DIR/$OSYNC_DELETE_DIR/someDeletedFileTarget"
	files[2]="$INITIATOR_DIR/$OSYNC_BACKUP_DIR/someBackedUpFileInitiator"
	files[3]="$TARGET_DIR/$OSYNC_BACKUP_DIR/someBackedUpFileTarget"

	DirA="$INITIATOR_DIR/$OSYNC_DELETE_DIR/somedir"
	DirB="$TARGET_DIR/$OSYNC_DELETE_DIR/someotherdir"

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"
		PrepareLocalDirs

		# First run
		#REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		#assertEquals "First deletion run with parameters [$i]." "0" $?

		# Get current drive
		drive=$(df "$OSYNC_DIR" | tail -1 | awk '{print $1}')

		# Create some deleted & backed up files, some new and some old
		for file in "${files[@]}"; do
			# Create directories first if they do not exist (deletion dir is created by osync, backup dir is created by rsync only when needed)
			if [ ! -d "$(dirname $file)" ]; then
				mkdir -p "$(dirname $file)"
			fi

			touch "$file.new"

			if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ] || [ "$LOCAL_OS" == "BSD" ] || [ "$LOCAL_OS" == "MacOSX" ] || [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
				echo "Skipping changing ctime on file because travis / bsd / macos / Win10 / msys / cygwin does not support debugfs"
			else
				CreateOldFile "$file.old"
			fi
		done
		if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ] || [ "$LOCAL_OS" == "BSD" ] || [ "$LOCAL_OS" == "MacOSX" ] || [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
			echo "Skipping changing ctime on dir too"
		else
			CreateOldFile "$DirA" true
			CreateOldFile "$DirB" true
		fi

		# Second run
		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i

		# Check file presence
		for file in "${files[@]}"; do
			[ -f "$file.new" ]
			assertEquals "New softdeleted / backed up file [$file.new] exists." "0" $?

			if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ] || [ "$LOCAL_OS" == "BSD" ] || [ "$LOCAL_OS" == "MacOSX" ] || [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
				[ ! -f "$file.old" ]
				assertEquals "Old softdeleted / backed up file [$file.old] is deleted permanently." "0" $?
			else
				[ ! -f "$file.old" ]
				assertEquals "Old softdeleted / backed up file [$file.old] is deleted permanently." "1" $?
			fi
		done

		if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ] || [ "$LOCAL_OS" == "BSD" ] || [ "$LOCAL_OS" == "MacOSX" ] || [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
			[ ! -d "$DirA" ]
			assertEquals "Old softdeleted / backed up directory [$dirA] is deleted permanently." "0" $?
			[ ! -d "$DirB" ]
			assertEquals "Old softdeleted / backed up directory [$dirB] is deleted permanently." "0" $?
		else
			[ ! -d "$DirA" ]
			assertEquals "Old softdeleted / backed up directory [$DirA] is deleted permanently." "1" $?
			[ ! -d "$DirB" ]
			assertEquals "Old softdeleted / backed up directory [$DirB] is deleted permanently." "1" $?
		fi
	done

}

function test_FileAttributePropagation () {

	if [ "$RUNNING_ON_GITHUB_ACTIONS" == true ]; then
		echo "Skipping FileAttributePropagation tests as travis does not support getfacl / setfacl."
		return 0
	fi

	if [ "$LOCAL_OS" == "MacOSX" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
		echo "Skipping FileAttributePropagation tests because [$LOCAL_OS]  does not support ACL."
		return 0
	fi

        SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "PRESERVE_ACL" true
        SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "PRESERVE_XATTR" true
        SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "PRESERVE_ACL" true
        SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "PRESERVE_XATTR" true

	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"
		PrepareLocalDirs

		DirA="dir a"
		DirB="dir b"
		DirC="dir c"
		DirD="dir d"

		mkdir "$INITIATOR_DIR/$DirA"
		mkdir "$TARGET_DIR/$DirB"
		mkdir "$INITIATOR_DIR/$DirC"
		mkdir "$TARGET_DIR/$DirD"

		FileA="$DirA/FileA"
		FileB="$DirB/FileB"

		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"

		# First run
		PRESERVE_ACL=yes PRESERVE_XATTR=yes REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		sleep 1

		getfacl "$INITIATOR_DIR/$FileA" | grep "other::r--" > /dev/null
		assertEquals "Check getting ACL on initiator." "0" $?

		getfacl "$TARGET_DIR/$FileB" | grep "other::r--" > /dev/null
		assertEquals "Check getting ACL on target." "0" $?

		getfacl "$INITIATOR_DIR/$DirC" | grep "other::r-x" > /dev/null
		assertEquals "Check getting ACL on initiator subdirectory." "0" $?

		getfacl "$TARGET_DIR/$DirD" | grep "other::r-x" > /dev/null
		assertEquals "Check getting ACL on target subdirectory." "0" $?

		setfacl -m o::r-x "$INITIATOR_DIR/$FileA"
		assertEquals "Set ACL on initiator" "0" $?
		setfacl -m o::-w- "$TARGET_DIR/$FileB"
		assertEquals "Set ACL on target" "0" $?

		setfacl -m o::rwx "$INITIATOR_DIR/$DirC"
		assertEquals "Set ACL on initiator directory" "0" $?
		setfacl -m o::-wx "$TARGET_DIR/$DirD"
		assertEquals "Set ACL on target directory" "0" $?

		# Second run
		PRESERVE_ACL=yes PRESERVE_XATTR=yes REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		getfacl "$TARGET_DIR/$FileA" | grep "other::r-x" > /dev/null
		assertEquals "ACLs matched original value on target." "0" $?

		getfacl "$INITIATOR_DIR/$FileB" | grep "other::-w-" > /dev/null
		assertEquals "ACLs matched original value on initiator." "0" $?

		getfacl "$TARGET_DIR/$DirC" | grep "other::rwx" > /dev/null
		assertEquals "ACLs matched original value on target subdirectory." "0" $?

		getfacl "$INITIATOR_DIR/$DirD" | grep "other::-wx" > /dev/null
		assertEquals "ACLs matched original value on initiator subdirectory." "0" $?
	done

        SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "PRESERVE_ACL" false
        SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "PRESERVE_XATTR" false
        SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "PRESERVE_ACL" false
        SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "PRESERVE_XATTR" false
}

function test_ConflictBackups () {
	for i in "${osyncParameters[@]}"; do
		cd "$OSYNC_DIR"
		PrepareLocalDirs

		DirA="some dir"
		DirB="some other dir"

		mkdir -p "$INITIATOR_DIR/$DirA"
		mkdir -p "$TARGET_DIR/$DirB"

		FileA="$DirA/FileA"
		FileB="$DirB/File B"

		echo "$FileA" > "$INITIATOR_DIR/$FileA"
		echo "$FileB" > "$TARGET_DIR/$FileB"

		# First run
		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		echo "$FileA+" > "$TARGET_DIR/$FileA"
		echo "$FileB+" > "$INITIATOR_DIR/$FileB"

		# Second run
		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "First deletion run with parameters [$i]." "0" $?

		[ -f "$INITIATOR_DIR/$OSYNC_BACKUP_DIR/$FileA" ]
		assertEquals "Backup file is present in [$INITIATOR_DIR/$OSYNC_BACKUP_DIR/$FileA]." "0" $?

		[ -f "$TARGET_DIR/$OSYNC_BACKUP_DIR/$FileB" ]
		assertEquals "Backup file is present in [$TARGET_DIR/$OSYNC_BACKUP_DIR/$FileB]." "0" $?
	done
}

function test_MultipleConflictBackups () {

	local additionalParameters

	# modify config files
	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "CONFLICT_BACKUP_MULTIPLE" true
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "CONFLICT_BACKUP_MULTIPLE" true

	if [ "$OSYNC_MIN_VERSION" != "1" ]; then
		additionalParameters="--errors-only --summary --no-prefix"
	fi

	for i in "${osyncParameters[@]}"; do

		echo "Running with parameters [$i]."

		cd "$OSYNC_DIR"
		PrepareLocalDirs

		FileA="FileA"
		FileB="FileB"

		echo "$FileA" > "$INITIATOR_DIR/$FileA"
		echo "$FileB" > "$TARGET_DIR/$FileB"

		# First run
		CONFLICT_BACKUP_MULTIPLE=true REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i $additionalParameters
		assertEquals "First deletion run with parameters [$i]." "0" $?

		echo "$FileA+" > "$TARGET_DIR/$FileA"
		echo "$FileB+" > "$INITIATOR_DIR/$FileB"

		# Second run
		CONFLICT_BACKUP_MULTIPLE=true REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i $additionalParameters
		assertEquals "First deletion run with parameters [$i]." "0" $?

		echo "$FileA-" > "$TARGET_DIR/$FileA"
		echo "$FileB-" > "$INITIATOR_DIR/$FileB"

		# Third run
		CONFLICT_BACKUP_MULTIPLE=true REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i $additionalParameters
		assertEquals "First deletion run with parameters [$i]." "0" $?

		echo "$FileA*" > "$TARGET_DIR/$FileA"
		echo "$FileB*" > "$INITIATOR_DIR/$FileB"

		# Fouth run
		CONFLICT_BACKUP_MULTIPLE=true REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i $additionalParameters
		assertEquals "First deletion run with parameters [$i]." "0" $?

		# This test may fail only on 31th December at 23:59 :)
		[ $(find "$INITIATOR_DIR/$OSYNC_BACKUP_DIR/" -type f -name "FileA.$(date '+%Y')*" | wc -l) -eq 3 ]
		assertEquals "3 Backup files are present in [$INITIATOR_DIR/$OSYNC_BACKUP_DIR/]." "0" $?

		[ $(find "$TARGET_DIR/$OSYNC_BACKUP_DIR/" -type f -name "FileB.$(date '+%Y')*" | wc -l) -eq 3 ]
		assertEquals "3 Backup files are present in [$TARGET_DIR/$OSYNC_BACKUP_DIR/]." "0" $?
	done

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "CONFLICT_BACKUP_MULTIPLE" false
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "CONFLICT_BACKUP_MULTIPLE" false
}

function test_Locking () {
# local not running = resume
# remote same instance_id = resume
# remote different instance_id = stop
# remote dfiffent instance_id + FORCE_STRANGER_LOCK_RESUME = resume

	# Initiator lock present should always be resumed if pid does not run
	for i in "${osyncParameters[@]}"; do

		cd "$OSYNC_DIR"
		PrepareLocalDirs

		mkdir -p "$INITIATOR_DIR/$OSYNC_WORKDIR"
		echo 65536 > "$INITIATOR_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Should be able to resume when initiator has lock without running pid." "0" $?

		echo $$ > "$INITIATOR_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Should never be able to resume when initiator has lock with running pid." "1" $?
	done

	# Target lock present should be resumed if instance ID is the same as current one
	PrepareLocalDirs
	mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
	echo 65536@quicklocal > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

	REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__quickLocal]}
	assertEquals "Should be able to resume locked target with same instance_id in quickLocal mode." "0" $?

	PrepareLocalDirs
	mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
	echo 65536@local > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

	REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__confLocal]}
	assertEquals "Should be able to resume locked target with same instance_id in confLocal mode." "0" $?

	if [ "$LOCAL_OS" != "msys" ] && [ "$LOCAL_OS" != "Cygwin" ]; then
		PrepareLocalDirs
		mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
		echo 65536@quickremote > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__quickRemote]}
		assertEquals "Should be able to resume locked target with same instance_id in quickRemote mode." "0" $?

		PrepareLocalDirs
		mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
		echo 65536@remote > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__confRemote]}
		assertEquals "Should be able to resume locked target with same instance_id in confRemote mode." "0" $?
	fi

	# Remote Target lock present should not be resumed if instance ID is NOT the same as current one, local target lock is resumed
	PrepareLocalDirs
	mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
	echo 65536@bogusinstance > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

	REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__quickLocal]}
	assertEquals "Should be able to resume locked local target with bogus instance id in quickLocal mode." "0" $?

	PrepareLocalDirs
	mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
	echo 65536@bogusinstance > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

	REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__confLocal]}
	assertEquals "Should be able to resume locked local target with bogus instance_id in confLocal mode." "0" $?

	if [ "$LOCAL_OS" != "msys" ] && [ "$LOCAL_OS" != "Cygwin" ]; then
		PrepareLocalDirs
		mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
		echo 65536@bogusinstance > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__quickRemote]}
		assertEquals "Should not be able to resume remote locked target with bogus instance_id in quickRemote mode." "1" $?

		PrepareLocalDirs
		mkdir -p "$TARGET_DIR/$OSYNC_WORKDIR"
		echo 65536@bogusinstance > "$TARGET_DIR/$OSYNC_WORKDIR/lock"

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__confRemote]}
		assertEquals "Should not be able to resume remote locked target with bogus instance_id in confRemote mode." "1" $?
	fi

	# Target lock present should be resumed if instance ID is NOT the same as current one but FORCE_STRANGER_UNLOCK=yes

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "FORCE_STRANGER_LOCK_RESUME" true
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "FORCE_STRANGER_LOCK_RESUME" true

	for i in "${osyncParameters[@]}"; do

		cd "$OSYNC_DIR"
		PrepareLocalDirs

		mkdir -p "$INITIATOR_DIR/$OSYNC_WORKDIR"
		echo 65536@bogusinstance > "$INITIATOR_DIR/$OSYNC_WORKDIR/lock"

		FORCE_STRANGER_UNLOCK=yes REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i
		assertEquals "Should be able to resume when target has lock with different instance id but FORCE_STRANGER_UNLOCK=yes." "0" $?
	done

	SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "FORCE_STRANGER_LOCK_RESUME" false
	SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "FORCE_STRANGER_LOCK_RESUME" false
}

function test_ConflictDetetion () {
	# Tests compatible with v1.4+

	if [ $OSYNC_MIN_VERSION -lt 4 ]; then
		echo "Skipping conflict detection test because osync min version is $OSYNC_MIN_VERSION (must be 4 at least)."
		return 0
	fi

	for i in "${osyncParameters[@]}"; do

		cd "$OSYNC_DIR"
		PrepareLocalDirs

		FileA="some file"
		FileB="some other file"

		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"
		touch "$INITIATOR_DIR/$FileB"
		touch "$TARGET_DIR/$FileA"

		# Initializing treeList
		REMOTE_HOST_PING=$RHOST_PING _PARANOIA_DEBUG=no $OSYNC_EXECUTABLE $i --initialize
		assertEquals "Initialization run with parameters [$i]." "0" $?

		# Now modifying files on both sides

		echo "A" > "$INITIATOR_DIR/$FileA"
		echo "B" > "$TARGET_DIR/$FileB"
		echo "BB" > "$INITIATOR_DIR/$FileB"
		echo "AA" > "$TARGET_DIR/$FileA"

		# Now run should return conflicts

		REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE $i --log-conflicts > "$FAKEROOT/output2.log" 2>&1
		assertEquals "Second run that should detect conflicts with parameters [$i]." "0" $?

		cat "$FAKEROOT/output2.log"

		#WIP TODO change output.log from output2.log for debug reasons
		grep "$INITIATOR_DIR/$FileA << >> $TARGET_DIR/$FileA" "$FAKEROOT/output2.log" 
		assertEquals "FileA conflict detect with parameters [$i]." "0" $?

		grep "$INITIATOR_DIR/$FileB << >> $TARGET_DIR/$FileB" "$FAKEROOT/output2.log"
		assertEquals "FileB conflict detect with parameters [$i]." "0" $?

		#TODO: Missing test for conflict prevalance (once we have FORCE_CONFLICT_PREVALANCE
	done
	return 0
}

function test_WaitForTaskCompletion () {
	local pids

	# Tests compatible with v1.1 syntax

	# These tests aren't really effective because in any case, output from WaitFor functions is always 0, which was a bad behavior in v1.1

	if [ "$OSYNC_MIN_VERSION" == "1" ]; then
		echo "Using v1.1 WaitForTaskCompletion test"

		# Needed in order to get PROCESS_test_CMD value
		InitLocalOSSettings

		# Standard wait
		sleep 2 &
		pid=$!
		WaitForTaskCompletion $pid 0 0 ${FUNCNAME[0]}
		assertEquals "WaitForTaskCompletion v1.1 test 1" "0" $?

		# Standard wait with warning
		sleep 5 &
		WaitForTaskCompletion $! 3 0 ${FUNCNAME[0]}
		assertEquals "WaitForTaskCompletion v1.1 test 2" "0" $?

		# Pid is killed
		sleep 5 &
		WaitForTaskCompletion $! 0 2 ${FUNCNAME[0]}
		assertEquals "WaitForTaskCompletion v1.1 test 3" "1" $?

		# Standard wait
		sleep 2 &
		WaitForCompletion $! 0 0 ${FUNCNAME[0]}
		assertEquals "WaitForCompletion test 1" "0" $?

		# Standard wait with warning
		sleep 5 &
		WaitForCompletion $! 3 0 ${FUNCNAME[0]}
		assertEquals "WaitForCompletion test 2" "0" $?

		# Pid is killed
		sleep 5 &
		WaitForCompletion $! 0 2 ${FUNCNAME[0]}
		assertEquals "WaitForCompletion test 3" "1" $?

		return 0
	fi

	# Tests if wait for task completion works correctly with v1.2+

	# Standard wait
	sleep 1 &
	pids="$!"
	sleep 2 &
	pids="$pids;$!"
	WaitForTaskCompletion $pids 0 0 $SLEEP_TIME $KEEP_LOGGING true true false ${FUNCNAME[0]}
	assertEquals "WaitForTaskCompletion test 1" "0" $?

	# Standard wait with warning
	sleep 2 &
	pids="$!"
	sleep 5 &
	pids="$pids;$!"

	WaitForTaskCompletion $pids 3 0 $SLEEP_TIME $KEEP_LOGGING true true false ${FUNCNAME[0]}
	assertEquals "WaitForTaskCompletion test 2" "0" $?

	# Both pids are killed
	sleep 5 &
	pids="$!"
	sleep 5 &
	pids="$pids;$!"

	WaitForTaskCompletion $pids 0 2 $SLEEP_TIME $KEEP_LOGGING true true false ${FUNCNAME[0]}
	assertEquals "WaitForTaskCompletion test 3" "2" $?

	# One of two pids are killed
	sleep 2 &
	pids="$!"
	sleep 10 &
	pids="$pids;$!"

	WaitForTaskCompletion $pids 0 3 $SLEEP_TIME $KEEP_LOGGING true true false ${FUNCNAME[0]}
	assertEquals "WaitForTaskCompletion test 4" "1" $?

	# Count since script begin, the following should output two warnings and both pids should get killed
	sleep 20 &
	pids="$!"
	sleep 20 &
	pids="$pids;$!"

	WaitForTaskCompletion $pids 3 5 $SLEEP_TIME $KEEP_LOGGING false true false ${FUNCNAME[0]}
	assertEquals "WaitForTaskCompletion test 5" "2" $?
}

function test_ParallelExec () {
	if [ "$OSYNC_MIN_VERSION" == "1" ]; then
		echo "Skipping ParallelExec test because osync v1.1 ofunctions don't have this function."
		return 0
	fi

	local cmd

	# Test if parallelExec works correctly in array mode

	cmd="sleep 2;sleep 2;sleep 2;sleep 2"
	ParallelExec 4 "$cmd"
	assertEquals "ParallelExec test 1" "0" $?

	cmd="sleep 2;du /none;sleep 2"
	ParallelExec 2 "$cmd"
	assertEquals "ParallelExec test 2" "1" $?

	cmd="sleep 4;du /none;sleep 3;du /none;sleep 2"
	ParallelExec 3 "$cmd"
	assertEquals "ParallelExec test 3" "2" $?

	# Test if parallelExec works correctly in file mode

	echo "sleep 2" > "$TMP_FILE"
	echo "sleep 2" >> "$TMP_FILE"
	echo "sleep 2" >> "$TMP_FILE"
	echo "sleep 2" >> "$TMP_FILE"
	ParallelExec 4 "$TMP_FILE" true
	assertEquals "ParallelExec test 4" "0" $?

	echo "sleep 2" > "$TMP_FILE"
	echo "du /nome" >> "$TMP_FILE"
	echo "sleep 2" >> "$TMP_FILE"
	ParallelExec 2 "$TMP_FILE" true
	assertEquals "ParallelExec test 5" "1" $?

	echo "sleep 4" > "$TMP_FILE"
	echo "du /none" >> "$TMP_FILE"
	echo "sleep 3" >> "$TMP_FILE"
	echo "du /none" >> "$TMP_FILE"
	echo "sleep 2" >> "$TMP_FILE"
	ParallelExec 3 "$TMP_FILE" true
	assertEquals "ParallelExec test 6" "2" $?

	#function ParallelExec $numberOfProcesses $commandsArg $readFromFile $softTime $HardTime $sleepTime $keepLogging $counting $Spinner $noError $callerName
	# Test if parallelExec works correctly in array mode with full  time control

	cmd="sleep 5;sleep 5;sleep 5;sleep 5;sleep 5"
	ParallelExec 4 "$cmd" false 1 0 .05 3600 true true false ${FUNCNAME[0]}
	assertEquals "ParallelExec full test 1" "0" $?

	cmd="sleep 2;du /none;sleep 2;sleep 2;sleep 4"
	ParallelExec 2 "$cmd" false 0 0 .1 2 true false false ${FUNCNAME[0]}
	assertEquals "ParallelExec full test 2" "1" $?

	cmd="sleep 4;du /none;sleep 3;du /none;sleep 2"
	ParallelExec 3 "$cmd" false 1 2 .05 7000 true true false ${FUNCNAME[0]}
	assertNotEquals "ParallelExec full test 3" "0" $?
}

function test_timedExecution () {
	local arguments

	# Clever usage of indexes and exit codes
	# osync exits with 0 when no problem detected
	# exits with 1 when error detected (triggered by reaching HARD_MAX_EXEC_TIME)
	# exits with 2 when warning only detected (triggered by reaching SOFT_MAX_EXEC_TIME)

	softTimes=()
	softTimes[0]=7200 	# original values (to be executed at last in order to leave config file in original state)
	hardTimes[0]=10600
	softTimes[1]=0
	hardTimes[1]=3
	softTimes[2]=2
	hardTimes[2]=10600

	for x in 2 1 0; do

		SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "SOFT_MAX_EXEC_TIME" ${softTimes[$x]}
		SetConfFileValue "$CONF_DIR/$LOCAL_CONF" "HARD_MAX_EXEC_TIME" ${hardTimes[$x]}
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "SOFT_MAX_EXEC_TIME" ${softTimes[$x]}
		SetConfFileValue "$CONF_DIR/$REMOTE_CONF" "HARD_MAX_EXEC_TIME" ${hardTimes[$x]}

		for i in "${osyncParameters[@]}"; do
			cd "$OSYNC_DIR"
			PrepareLocalDirs

			echo "Test with args [$i $arguments]."
			SLEEP_TIME=1 SOFT_MAX_EXEC_TIME=${softTimes[$x]} HARD_MAX_EXEC_TIME=${hardTimes[$x]} $OSYNC_EXECUTABLE $i
			retval=$?
			if [ "$OSYNC_MIN_VERSION" -gt 1 ]; then
				assertEquals "Timed Execution test with timed SOFT_MAX_EXEC_TIME=${softTimes[$x]} and HARD_MAX_EXEC_TIME=${hardTimes[$x]}." $x $retval
			else
				# osync v1.1 had different exit codes, 240 was warning, anything else than 0 was error
				if [ $x -eq 2 ]; then
					assertEquals "Timed Execution test with timed SOFT_MAX_EXEC_TIME=${softTimes[$x]} and HARD_MAX_EXEC_TIME=${hardTimes[$x]}." 240 $retval
				elif [ $x -eq 1 ]; then
					assertNotEquals "Timed Execution test with timed SOFT_MAX_EXEC_TIME=${softTimes[$x]} and HARD_MAX_EXEC_TIME=${hardTimes[$x]}." 0 $retval
				else
					assertEquals "Timed Execution test with timed SOFT_MAX_EXEC_TIME=${softTimes[$x]} and HARD_MAX_EXEC_TIME=${hardTimes[$x]}." 0 $retval
				fi
			fi
		done
	done
}

function test_UpgradeConfRun () {
	if [ "$OSYNC_MIN_VERSION" == "1" ]; then
		echo "Skipping Upgrade script test because no further dev will happen on this for v1.1"
		return 0
	fi

	# Basic return code tests. Need to go deep into file presence testing
	cd "$OSYNC_DIR"
	PrepareLocalDirs

	# Make a security copy of the old config file
	cp "$CONF_DIR/$OLD_CONF" "$CONF_DIR/$TMP_OLD_CONF"

	./$OSYNC_UPGRADE "$CONF_DIR/$TMP_OLD_CONF"
	assertEquals "Conf file upgrade" "0" $?

	# Update remote conf files with SSH port
	sed -i.tmp 's#ssh://.*@localhost:[0-9]*/${homedir}/osync-tests/target#ssh://'$REMOTE_USER'@localhost:'$SSH_PORT'/${homedir}/osync-tests/target#' "$CONF_DIR/$TMP_OLD_CONF"

	$OSYNC_EXECUTABLE "$CONF_DIR/$TMP_OLD_CONF"
	assertEquals "Upgraded conf file execution test" "0" $?

	rm -f "$CONF_DIR/$TMP_OLD_CONF"
	rm -f "$CONF_DIR/$TMP_OLD_CONF.save"
}

function test_DaemonMode () {
	if [ "$LOCAL_OS" == "WinNT10" ] || [ "$LOCAL_OS" == "msys" ] || [ "$LOCAL_OS" == "Cygwin" ]; then
		echo "Skipping daemon mode test as [$LOCAL_OS] does not have inotifywait support."
		return 0
	fi

	for i in "${osyncDaemonParameters[@]}"; do

		cd "$OSYNC_DIR"
		PrepareLocalDirs

		FileA="FileA"
		FileB="FileB"
		FileC="FileC"

		touch "$INITIATOR_DIR/$FileA"
		touch "$TARGET_DIR/$FileB"

		$OSYNC_EXECUTABLE "$CONF_DIR/$LOCAL_CONF" --on-changes &
		pid=$!

		#TODO: Lower that value when dispatecher is written
		# Trivial value of 2xMIN_WAIT from config files
		echo "Sleeping for 120s"
		sleep 120

		[ -f "$TARGET_DIR/$FileB" ]
		assertEquals "File [$TARGET_DIR/$FileB] should be synced." "0" $?
		[ -f "$INITIATOR_DIR/$FileA" ]
		assertEquals "File [$INITIATOR_DIR/$FileB] should be synced." "0" $?

		touch "$INITIATOR_DIR/$FileC"
		rm -f "$INITIATOR_DIR/$FileA"
		rm -f "$TARGET_DIR/$FileB"

		echo "Sleeping for 120s"
		sleep 120

		[ ! -f "$TARGET_DIR/$FileB" ]
		assertEquals "File [$TARGET_DIR/$FileB] should be deleted." "0" $?
		[ ! -f "$INITIATOR_DIR/$FileA" ]
		assertEquals "File [$INITIATOR_DIR/$FileA] should be deleted." "0" $?

		[ -f "$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA" ]
		assertEquals "File [$TARGET_DIR/$OSYNC_DELETE_DIR/$FileA] should be in soft deletion dir." "0" $?
		[ -f "$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB" ]
		assertEquals "File [$INITIATOR_DIR/$OSYNC_DELETE_DIR/$FileB] should be in soft deletion dir." "0" $?

		[ -f "$TARGET_DIR/$FileC" ]
		assertEquals "File [$TARGET_DIR/$FileC] should be synced." "0" $?

		kill $pid
	done

}

function test_NoRemoteAccessTest () {
	RemoveSSH

	cd "$OSYNC_DIR"
	PrepareLocalDirs

	REMOTE_HOST_PING=$RHOST_PING $OSYNC_EXECUTABLE ${osyncParameters[$__confLocal]}
	assertEquals "Basic local test without remote access." "0" $?
}

. "$TESTS_DIR/shunit2/shunit2"
