#!/bin/bash
#
# Test cgclassify with various arguments, without /etc/cgrules.conf.
# cglassify is tested with exact destination group, multiple PIDs, groups
# specified by '*', multiple target groups, lot of PIDs on command line
# and various error cases.

. `dirname $0`/../testenv.sh

function checkpid()
{
	# check that given process is in given groups
	local PID=$1
	# delete hierarchy number, ignore systemd
	cat /proc/$PID/cgroup | sed 's/^[0-9]*://' | grep -v systemd > $TMP/pid-$PID.group
	printf >$TMP/pid-$PID.expected "$2"
	diff -u -w $TMP/pid-$PID.group $TMP/pid-$PID.expected
	return $?
}

function resetgroup()
{
	# move given processes back to root group
	$TOOLSDIR/cgclassify -g "*:/" $*
}

# prepare some hierarchy
$TOOLSDIR/cgconfigparser -l `prepare_config simple.conf` || \
	die "cannot parse simple.conf"

# start few processes to torture
/bin/sleep 10000 &
PID1=$!
/bin/sleep 10000 &
PID2=$!
/bin/sleep 10000 &
PID3=$!

# STEP1: simple cgclassify to exact groups
$TOOLSDIR/cgclassify -g net_cls,cpu:common $PID1 || \
	die "STEP1: cgclassify PID1 failed"
$TOOLSDIR/cgclassify -g net_cls:net1 $PID2 || \
	die "STEP1: cgclassify PID2 failed"
$TOOLSDIR/cgclassify -g cpu:cpu1 $PID3 || \
	die "STEP1: cgclassify PID3 failed"

checkpid $PID1 "net_cls,freezer:/common\ncpuacct,cpu:/common\n" || \
	die "STEP1: unexpected group of pid1"
checkpid $PID2 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP!: unexpected group of pid2"
checkpid $PID3 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP!: unexpected group of pid3"

# STEP2: try * and more PIDs
$TOOLSDIR/cgclassify -g "*:/" $PID1 $PID2 $PID3 || \
	die "cgclassify 2 failed"
checkpid $PID1 "net_cls,freezer:/\ncpuacct,cpu:/\n" || \
	die "STEP2: unexpected group of pid1"
checkpid $PID2 "net_cls,freezer:/\ncpuacct,cpu:/\n" || \
	die "STEP2: unexpected group of pid2"
checkpid $PID3 "net_cls,freezer:/\ncpuacct,cpu:/\n" || \
	die "STEP2: unexpected group of pid3"

# STEP3: try different groups
resetgroup $PID1 $PID2 $PID3
$TOOLSDIR/cgclassify -g cpu:cpu1 -g net_cls:net1 $PID1
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/cpu1\n" || \
	die "STEP3: unexpected group of pid1"

# STEP4: different groups multiple times (tha last should win)
resetgroup $PID1 $PID2 $PID3
$TOOLSDIR/cgclassify -g "*:/" -g cpu:common -g net_cls:common -g cpu:cpu1 -g net_cls:net1 $PID1 || \
	die "STEP4: cgclassify pid1 failed"
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/cpu1\n" || \
	die "STEP4: unexpected group of pid1"
$TOOLSDIR/cgclassify -g "*:/" -g cpu:common -g net_cls:common -g cpu:cpu1 $PID2 || \
	die "STEP4: cgclassify pid2 failed"
checkpid $PID2 "net_cls,freezer:/common\ncpuacct,cpu:/cpu1\n" || \
	die "STEP4: unexpected group of pid2"

# STEP5: some error cases
# group does not exist
echo "Testing error cases, error messages will appear!"
$TOOLSDIR/cgclassify -g cpu:invalid_group $PID1 && \
	die "STEP5: cgclassify with invalig_group succeeded"
# parameter is not a PID
$TOOLSDIR/cgclassify -g cpu:/ xxx && \
	die "STEP5: cgclassify with xxx pid succeeded"
# let's hope process 1234567 does not exist
$TOOLSDIR/cgclassify -g cpu:/ 1234567 && \
	die "STEP5: cgclassify with 1234567 succeeded"
# not-mounted controller
$TOOLSDIR/cgclassify -g xxx:/ $PID1 && \
	die "STEP5: cgclassify with xxx controller succeeded"
# no -g parameter
$TOOLSDIR/cgclassify -g  $PID1 && \
	die "STEP5: cgclassify without -g succeeded"
# invalid -g format
$TOOLSDIR/cgclassify -g  cpu/cpu1 $PID1 && \
	die "STEP5: cgclassify -g cpu/cpu1 succeeded"

# some existing processes among unexisting
resetgroup $PID1 $PID2 $PID3
$TOOLSDIR/cgclassify -g cpu,net_cls:common $PID1 1234567 $PID2 1234568 $PID3 && \
	die "STEP5: cgclassify with mixed processed succeeded"
checkpid $PID1 "net_cls,freezer:/common\ncpuacct,cpu:/common\n" || \
	die "STEP5: unexpected group of pid1"
checkpid $PID2 "net_cls,freezer:/common\ncpuacct,cpu:/common\n" || \
	die "STEP5: unexpected group of pid2"
checkpid $PID3 "net_cls,freezer:/common\ncpuacct,cpu:/common\n" || \
	die "STEP5: unexpected group of pid3"

echo "End of error cases"

# STEP6: *lot of* processes on command line
echo "Testing lot of arguments, this will take some time"
COUNT=1000
echo >$TMP/pids
(
	for i in `seq $COUNT`; do
		sleep 100000 &
		echo $! >>$TMP/pids
	done
) > /dev/null
$TOOLSDIR/cgclassify -g net_cls,cpu:common `cat $TMP/pids` || \
	die "STEP6: cgclassify failed"

kill `cat $TMP/pids`
sleep 1 # to settle down the sleep load - sigterm does not kill sleep immediatelly

kill $PID1 $PID2 $PID3
$TOOLSDIR/cgclear
cleanup
exit 0
