#!/bin/bash
#
# Copyright (C) 2018 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
#
# SPDX-License-Identifier: LGPL-2.1-only

TEST_DESC="Change working directory of process"

CURDIR=$(dirname "$0")/
TESTDIR=$CURDIR/../../../

DIR=$(readlink -f "$TESTDIR")

NUM_TESTS=35

source $TESTDIR/utils/utils.sh

#MUST set TESTDIR before calling those functions
plan_tests $NUM_TESTS

print_test_banner "$TEST_DESC"
function test_relayd()
{
	local relayd_bin_path="$DIR/../src/bin/lttng-relayd/$RELAYD_BIN"
	local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")
	local pid
	local cwd


	diag "Test lttng-relayd normal mode change working directory"

	# There is no rendez-vous mechanism that can guarantee the good timing
	# to check if the workdir directory was changed.
	# In the case of lttng-sessiond this would be achieved using the
	# --sig-parent option but lttng-relayd does not have this feature yet.
	# Fall back on using polling of the value and unblock when the value is
	# the one we expect. In case of a failure the test will hang.
	$relayd_bin_path --working-directory "$working_dir" > /dev/null 2>&1 &
	pid=$!

	while true; do
		cwd=$(readlink "/proc/${pid}/cwd")
		if test "$working_dir" = "$cwd"; then
			# Working dir for process is valid
			break
		fi
		sleep 0.1
	done

	# If we are here the test passed
	pass "Working directory changed"

	stop_lttng_relayd
	rm -rf "$working_dir"
}

function test_relayd_daemon()
{
	local cwd
	local pid
	local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")

	diag "Test lttng-relayd daemon mode change working directory"

	start_lttng_relayd_opt 1 "-d" "--working-directory $working_dir"

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/${pid}/cwd")

	is "$cwd" "$working_dir" "Working directory changed"

	stop_lttng_relayd
	rm -rf "$working_dir"
}

function test_relayd_daemon_no_working_dir()
{
	local expected_working_dir="/"
	local cwd
	local pid

	diag "Test lttng-relayd daemon mode change working directory"

	start_lttng_relayd_opt 1 "-d" ""

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/${pid}/cwd")

	is "$cwd" "$expected_working_dir" "Working directory is $expected_working_dir"

	stop_lttng_relayd
	rm -rf "$working_dir"
}

function test_relayd_background()
{
	local cwd
	local pid
	local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")

	diag "Test lttng-relayd background mode change working directory"

	start_lttng_relayd_opt 1 "-b" "--working-directory $working_dir"

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/${pid}/cwd")

	is "$cwd" "$working_dir" "Working directory changed"

	stop_lttng_relayd
	rm -rf "$working_dir"
}

function test_relayd_background_no_working_dir()
{
	local expected_working_dir="/"
	local cwd
	local pid

	diag "Test lttng-relayd background working directory"

	start_lttng_relayd_opt 1 "-b" ""

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/${pid}/cwd")

	is "$cwd" "$expected_working_dir" "Working directory is $expected_working_dir"

	stop_lttng_relayd
	rm -rf "$working_dir"
}

function test_relayd_debug_permission()
{
	local is_user

	diag "Test lttng-relayd change working directory on non writable directory"

	if [ "$(id -u)" == "0" ]; then
	    is_user=0
	else
	    is_user=1
	fi

	skip $is_user "Skipping permission debug output test; operation can't fail as root" 6 ||
	{
		local output_pattern='Working directory \".*\" is not writable'
		local cwd
		local pid
		local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")

		# Removing write access to working dir
		okx chmod -w "$working_dir"

		# Redirect the error output to a temporary file

		ERROR_OUTPUT_DEST=$(mktemp --tmpdir "tmp.${FUNCNAME[0]}_error_output.XXXXXX")
		start_lttng_relayd_opt 1 "-b" "-v --working-dir $working_dir"

		pid=$(lttng_pgrep "$RELAYD_MATCH")
		ok $? "Found lttng-relayd"

		cwd=$(readlink "/proc/${pid}/cwd")
		is "$cwd" "$working_dir" "Working directory changed"

		grep -q "$output_pattern" "$ERROR_OUTPUT_DEST"
		ok $? "Warning about missing write permission is present"

		stop_lttng_relayd
		rm "$ERROR_OUTPUT_DEST"
		rm -rf "$working_dir" "$ERROR_OUTPUT_DEST"
		ERROR_OUTPUT_DEST=/dev/null
	}
}

function test_relayd_failure()
{
	local output_pattern='Failed to change working directory to'
	local relayd_bin_path="$DIR/../src/bin/lttng-relayd/$RELAYD_BIN"
	local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")
	local output_dest=$(mktemp --tmpdir "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")

	local working_dir_imaginary
	local pid

	working_dir_imaginary="${working_dir}/imaginary_directory"

	diag "Test lttng-relayd normal mode change non-existing directory"

	$relayd_bin_path -b --working-directory "$working_dir_imaginary" > "$output_dest" 2>&1
	test $? -eq "1"
	ok $? "Expect failure to start lttng-relayd for non-existent working directory"

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	if [ -z "$pid" ]; then
		pass "No lttng-relayd present"
	else
		fail "No lttng-relayd present"
		stop_lttng_relayd_notap
	fi

	grep -q "$output_pattern" "$output_dest"
	ok $? "Found error message: invalid directory"

	rm "$output_dest"
	rm -rf "$working_dir"
}

function test_relayd_env()
{
	local cwd
	local pid
	local working_dir=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir.XXXXXX")")

	diag "Test lttng-relayd change working directory from env. variable"

	export LTTNG_RELAYD_WORKING_DIRECTORY=${working_dir}
	start_lttng_relayd_opt 1 "-b" ""

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/$pid/cwd")

	is "$cwd" "$working_dir" "Working directory changed"

	stop_lttng_relayd
	rm -rf "$working_dir"
	unset LTTNG_RELAYD_WORKING_DIRECTORY
}

function test_relayd_cmdline_overwrite_env()
{
	local cwd
	local pid
	local working_dir_env=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir_even.XXXXXX")")
	local working_dir_cmdline=$(realpath "$(mktemp --tmpdir -d "tmp.${FUNCNAME[0]}_working_dir_cmdline.XXXXXX")")

	diag "Test lttng-relayd change working directory command line overwrite env variable"

	export LTTNG_RELAYD_WORKING_DIRECTORY=${working_dir_env}
	start_lttng_relayd_opt 1 "-b" "--working-dir ${working_dir_cmdline}"

	pid=$(lttng_pgrep "$RELAYD_MATCH")
	ok $? "Found lttng-relayd"

	cwd=$(readlink "/proc/$pid/cwd")

	is "$cwd" "$working_dir_cmdline" "Working directory is the one from command line"

	stop_lttng_relayd
	rm -rf "$working_dir_env" "$working_dir_cmdline"
	unset LTTNG_RELAYD_WORKING_DIRECTORY
}

TESTS=(
	test_relayd
	test_relayd_daemon
	test_relayd_daemon_no_working_dir
	test_relayd_background
	test_relayd_background_no_working_dir
	test_relayd_debug_permission
	test_relayd_failure
	test_relayd_env
	test_relayd_cmdline_overwrite_env
)

for fct_test in "${TESTS[@]}";
do
	if ! ${fct_test}; then
		break;
	fi
done
