#!/bin/bash
#
# Test cgclassify with various /etc/cgrules.conf settings, like
# simple rules, multiple matching rules, using @groups, executable
# names and default rules.
# The test relies on testenv.sh to backup/restore /etc/cgrules.conf.
#

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

# The test need sto start few processes with non-root UID/GID. Which should be
# used?
TESTUSER=nobody
TESTGROUP=nobody

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"

# prepare specific process names
ln -s /bin/sleep $TMP/sleep1
$TMP/sleep1 10000 &
PID1=$!
ln -s /bin/sleep $TMP/sleep2
$TMP/sleep2 10000 &
PID2=$!

# start some processes as $TESTUSER
chmod o+rwX $TMP
su $TESTUSER -s /bin/bash -c "$TMP/sleep1 10000" &
su $TESTUSER -s /bin/bash -c "$TMP/sleep2 10000" &
sleep 0.1
NPID1=`ps h -u $TESTUSER | grep sleep1 | awk  '{ print $1; }' | tail -n 1`
NPID2=`ps h -u $TESTUSER | grep sleep2 | awk  '{ print $1; }' | tail -n 1`

# STEP1: simple global rule
cat <<EOF >/etc/cgrules.conf
unused	*	/
*	*	common
EOF
$TOOLSDIR/cgclassify $PID1
checkpid $PID1 "net_cls,freezer:/common\ncpuacct,cpu:/common\n" || \
	die "STEP1: unexpected group of pid1"
resetgroup $PID1

# STEP2: two destination groups
cat <<EOF >/etc/cgrules.conf
unused	*	/
*	cpu	cpu1
%	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/cpu1\n" || \
	die "STEP2: unexpected group of pid1"
resetgroup $PID1

# STEP3: two matching rules, only the first is executed
cat <<EOF >/etc/cgrules.conf
unused	*	/
*	cpu	cpu1
*	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1
checkpid $PID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP3: unexpected group of pid1"
resetgroup $PID1

# STEP4: process name in a rule
cat <<EOF >/etc/cgrules.conf
unused	*	/
*:sleep1	cpu	cpu1
*:sleep2	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1
checkpid $PID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP4: unexpected group of pid1"
$TOOLSDIR/cgclassify $PID2
checkpid $PID2 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP4: unexpected group of pid2"
resetgroup $PID1 $PID2

# STEP5: full path
cat <<EOF >/etc/cgrules.conf
unused	*	/
*:$TMP/sleep1	cpu	cpu1
*:$TMP/sleep2	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1
checkpid $PID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP5: unexpected group of pid1"
$TOOLSDIR/cgclassify $PID2
checkpid $PID2 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP5: unexpected group of pid2"
resetgroup $PID1 $PID2

#STEP6: username
cat <<EOF >/etc/cgrules.conf
unused	*	/
$TESTUSER	cpu	cpu1
*	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1 $NPID1
checkpid $NPID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP6: unexpected group of npid1"
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP6: unexpected group of pid1"
resetgroup $PID1 $NPID1

#STEP7: username + processname
cat <<EOF >/etc/cgrules.conf
unused	*	/
$TESTUSER:$TMP/sleep1	cpu	cpu1
*:$TMP/sleep1	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1 $NPID1
checkpid $NPID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP7: unexpected group of npid1"
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP7: unexpected group of pid1"
resetgroup $PID1 $NPID1

#STEP8: groupname + processname
cat <<EOF >/etc/cgrules.conf
unused	*	/
@$TESTGROUP:$TMP/sleep1	cpu	cpu1
*:$TMP/sleep1	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1 $NPID1
checkpid $NPID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP8: unexpected group of npid1"
checkpid $PID1 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP8: unexpected group of pid1"
resetgroup $PID1 $NPID1

#STEP9: processname + default
cat <<EOF >/etc/cgrules.conf
unused	*	/
*:$TMP/sleep1	cpu	cpu1
*	net_cls	net1
EOF
$TOOLSDIR/cgclassify $PID1 $PID2
checkpid $PID1 "net_cls,freezer:/\ncpuacct,cpu:/cpu1\n" || \
	die "STEP9: unexpected group of pid1"
checkpid $PID2 "net_cls,freezer:/net1\ncpuacct,cpu:/\n" || \
	die "STEP9: unexpected group of pid2"
resetgroup $PID1 $NPID1

kill -9 $PID1 $PID2 $NPID1 $NPID2

sleep 0.1
$TOOLSDIR/cgclear

cleanup
exit 0
