#!/bin/bash
#
# Copyright (C) - 2013 Julien Desfossez <jdesfossez@efficios.com>
#
# This library is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; version 2.1 of the License.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
TEST_DESC="Snapshots - UST tracing"

CURDIR=$(dirname $0)/
TESTDIR=$CURDIR/../../..
EVENT_NAME="tp:tptest"
PID_RELAYD=0
SESSION_NAME=""
CHANNEL_NAME="snapchan"
TESTAPP_PATH="$TESTDIR/utils/testapp"
TESTAPP_NAME="gen-ust-events"
TESTAPP_BIN="$TESTAPP_PATH/$TESTAPP_NAME/$TESTAPP_NAME"
NR_ITER=2000000
NR_USEC_WAIT=100

TRACE_PATH=$(mktemp -d)

NUM_TESTS=2053

source $TESTDIR/utils/utils.sh

if [ ! -x "$TESTAPP_BIN" ]; then
	BAIL_OUT "No UST events binary detected."
fi

function test_ust_local_snapshot ()
{
	diag "Test local UST snapshots"
	create_lttng_session_no_output $SESSION_NAME
	enable_lttng_mmap_overwrite_ust_channel $SESSION_NAME $CHANNEL_NAME
	enable_ust_lttng_event $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
	start_lttng_tracing $SESSION_NAME
	lttng_snapshot_add_output $SESSION_NAME $TRACE_PATH
	$TESTAPP_BIN $NR_ITER $NR_USEC_WAIT &
	ok $? "Start application to trace"
	lttng_snapshot_record $SESSION_NAME
	stop_lttng_tracing $SESSION_NAME
	destroy_lttng_session $SESSION_NAME

	# Validate test
	validate_trace $EVENT_NAME $TRACE_PATH/
	if [ $? -eq 0 ]; then
		# Only delete if successful
		rm -rf $TRACE_PATH
	else
		break
	fi
	diag "Killing $TESTAPP_NAME"
	PID_APP=`pidof $TESTAPP_NAME`
	kill $PID_APP >/dev/null 2>&1
}

function test_ust_local_snapshot_large_metadata ()
{
	LM_EVENT="tp:tptest1,tp:tptest2,tp:tptest3,tp:tptest4,tp:tptest5"
	LM_PATH="$TESTDIR/utils/testapp"
	LM_NAME="gen-ust-nevents"
	LM_BIN="$LM_PATH/$LM_NAME/$LM_NAME"

	diag "Test local UST snapshots with > 4kB metadata"
	create_lttng_session_no_output $SESSION_NAME
	enable_lttng_mmap_overwrite_ust_channel $SESSION_NAME $CHANNEL_NAME
	enable_ust_lttng_event $SESSION_NAME $LM_EVENT $CHANNEL_NAME
	start_lttng_tracing $SESSION_NAME
	lttng_snapshot_add_output $SESSION_NAME $TRACE_PATH
	$LM_BIN 1 1
	ok $? "Start application to trace"
	lttng_snapshot_record $SESSION_NAME
	stop_lttng_tracing $SESSION_NAME
	destroy_lttng_session $SESSION_NAME

	# Validate test
	validate_trace $LM_EVENT $TRACE_PATH/
	if [ $? -eq 0 ]; then
		# Only delete if successful
		rm -rf $TRACE_PATH
	else
		break
	fi
}

function enable_channel_per_uid_mmap_overwrite()
{
	sess_name=$1
	channel_name=$2

	$TESTDIR/../src/bin/lttng/$LTTNG_BIN enable-channel --buffers-uid -u $channel_name -s $sess_name --output mmap --overwrite >/dev/null 2>&1
	ok $? "Enable channel $channel_name per UID for session $sess_name"
}

function test_ust_per_uid_local_snapshot ()
{
	diag "Test local UST snapshots"
	create_lttng_session_no_output $SESSION_NAME
	enable_channel_per_uid_mmap_overwrite $SESSION_NAME $CHANNEL_NAME
	enable_ust_lttng_event $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
	start_lttng_tracing $SESSION_NAME
	lttng_snapshot_add_output $SESSION_NAME $TRACE_PATH
	$TESTAPP_BIN $NR_ITER $NR_USEC_WAIT &
	ok $? "Start application to trace"
	lttng_snapshot_record $SESSION_NAME
	stop_lttng_tracing $SESSION_NAME
	destroy_lttng_session $SESSION_NAME

	# Validate test
	validate_trace $EVENT_NAME $TRACE_PATH/
	if [ $? -eq 0 ]; then
		# Only delete if successful
		rm -rf $TRACE_PATH
	else
		break
	fi
	diag "Killing $TESTAPP_NAME"
	PID_APP=`pidof $TESTAPP_NAME`
	kill $PID_APP >/dev/null 2>&1
}

function test_ust_per_uid_local_snapshot_post_mortem ()
{
	diag "Test local UST snapshots post-mortem"
	create_lttng_session_no_output $SESSION_NAME
	enable_channel_per_uid_mmap_overwrite $SESSION_NAME $CHANNEL_NAME
	enable_ust_lttng_event $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
	start_lttng_tracing $SESSION_NAME
	lttng_snapshot_add_output $SESSION_NAME $TRACE_PATH
	$TESTAPP_BIN $NR_ITER $NR_USEC_WAIT &
	ok $? "Start application to trace"
	diag "Killing $TESTAPP_NAME"
	PID_APP=`pidof $TESTAPP_NAME`
	kill $PID_APP >/dev/null 2>&1
	lttng_snapshot_record $SESSION_NAME
	stop_lttng_tracing $SESSION_NAME
	destroy_lttng_session $SESSION_NAME

	# Validate test
	validate_trace $EVENT_NAME $TRACE_PATH/
	if [ $? -eq 0 ]; then
		# Only delete if successful
		rm -rf $TRACE_PATH
	else
		break
	fi
}

function test_ust_1000_local_snapshots ()
{
	NB_SNAP=1000

	diag "Test $NB_SNAP local UST snapshots"
	create_lttng_session_no_output $SESSION_NAME
	enable_lttng_mmap_overwrite_ust_channel $SESSION_NAME $CHANNEL_NAME
	enable_ust_lttng_event $SESSION_NAME $EVENT_NAME $CHANNEL_NAME
	start_lttng_tracing $SESSION_NAME
	lttng_snapshot_add_output $SESSION_NAME $TRACE_PATH
	$TESTAPP_BIN $NR_ITER $NR_USEC_WAIT &
	for i in $(seq 1 $NB_SNAP); do
		diag "Snapshot $i/$NB_SNAP"
		rm -rf $TRACE_PATH/snapshot/* 2>/dev/null
		lttng_snapshot_record $SESSION_NAME
		# Validate test
		validate_trace $EVENT_NAME $TRACE_PATH/
		if [ $? -eq 0 ]; then
			# Only delete if successful
			rm -rf $TRACE_PATH
		else
			break
		fi
	done
	stop_lttng_tracing $SESSION_NAME
	destroy_lttng_session $SESSION_NAME
	diag "Killing $TESTAPP_NAME"
	PID_APP=`pidof $TESTAPP_NAME`
	kill $PID_APP >/dev/null 2>&1
}

plan_tests $NUM_TESTS

print_test_banner "$TEST_DESC"

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

start_lttng_sessiond

tests=( test_ust_local_snapshot \
	test_ust_per_uid_local_snapshot \
	test_ust_per_uid_local_snapshot_post_mortem \
	test_ust_local_snapshot_large_metadata \
	test_ust_1000_local_snapshots )

for fct_test in ${tests[@]};
do
	SESSION_NAME=$(randstring 16 0)
	${fct_test}

done

stop_lttng_sessiond
