Red Hat QA meet-up
Camping Baldovec, Czech Republic
June 2013
Sr. QA Engineer at Red Hat IDM QE.
Formerly Sr. System Software Engineer
at NVIDIA Tegra graphics team.
Open Source developer.
Founder of DIGImend project - improving
Linux support for generic graphics tablets.
Bash test framework
An alternative to BeakerLib
3 KLOC in Bash, Lua and Python
Nearing first release, already useful
Personal spare-time project
Limits assertion structuring
Produces noisy output
Can't verify a subset of assertions
Ignores setup/teardown failures
#!/bin/bash
# Phase
rlPhaseStartTest "defaults"
# Assertion
rlRun client_sudo_user_requires_auth 0 "defaults_without"
# Assertion
rlRun client_sudo_user_is_allowed 0 "defaults_with"
rlPhaseEnd
# Phase
rlPhaseStartTest "config"
# Assertion
rlRun client_sudo_user_is_allowed 0 "config_all_options"
rlPhaseEnd
How about something more complex?
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ LOG ] :: simple_access_001: where simple_allow_groups = simple group1 :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: spawn ssh -o StrictHostKeyChecking=no -l simple userB localhost simple userB@localhost's password: Last login: Thu Jun 27 10:19:34 2013 from localhost.localdomain [simple userB@client-rhel6 ~]$ :: [ PASS ] :: Authentication successfull, as expected spawn ssh -o StrictHostKeyChecking=no -l simple userE localhost simple userE@localhost's password: Permission denied, please try again. simple userE@localhost's password: :: [ FAIL ] :: ERROR: Authentiation failed, not as expected Jun 27 10:38:16 client-rhel6 sshd[484]: pam_sss(sshd:account): Access denied for user simple userD: 6 (Permission denied) :: [ PASS ] :: Running 'cat /var/log/secure | grep "pam_sss(sshd:account): Access denied for user simple[ ]userD: 6 (Permission denied)"' :: [ PASS ] :: Authentication successfull connection closed, as expected :: [ PASS ] :: Running '> /var/log/secure' Jun 27 10:38:22 client-rhel6 sshd[508]: pam_sss(sshd:account): Access denied for user simple userF: 6 (Permission denied) :: [ PASS ] :: Running 'cat /var/log/secure | grep "pam_sss(sshd:account): Access denied for user simple[ ]userF: 6 (Permission denied)"' :: [ PASS ] :: Authentication successfull connection closed, as expected
# time SERVER="server.sss-test.test" CLIENT="client-rhel6.sss-test.test" make :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ LOG ] :: defaults :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ PASS ] :: defaults_without :: [ PASS ] :: defaults_with . . . :: [ PASS ] :: attrs_command_paranoid_non_equal2_match_negative :: [ PASS ] :: attrs_command_paranoid_non_equal2_mismatch :: [ 18:34:04 ] :: JOURNAL XML: /var/tmp/beakerlib-y2ii2jZ/journal.xml :: [ 18:34:04 ] :: JOURNAL TXT: /var/tmp/beakerlib-y2ii2jZ/journal.txt result_server not set, assuming developer mode. Setting client-rhel6.sss-test.test to state DONE real 10m28.666s user 0m10.454s sys 0m8.929s
10 minutes
Got milk?
:: [ FAIL ] :: Running 'cat /var/log/secure | grep "pam_sss(sshd:account): Access denied for user simple[ ]userC: 6 (Permission denied)"' (Expected 0, got 1)
50 lines back...
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ LOG ] :: simple_group_Setup :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ldap_bind: Invalid credentials (49) :: [ FAIL ] :: Running 'ldapmodify -x -h server.sss-test.test -D "cn=Manager,dc=example,dc=com" -w Secret124 -a -f /tmp/setup.ldif' (Expected 0, got 49) :: [ 10:43:23 ] :: Server Setup: :: [ 10:43:23 ] :: simple group1 => simple UserA simple UserB simple Group3 :: [ 10:43:23 ] :: simple Group2 => simple UserC simple UserD :: [ 10:43:23 ] :: simple Group3 => simple UserE :: [ 10:43:23 ] :: simple UserF (belongs to no group/its own group) :: [ 10:43:23 ] ::
#!/bin/bash
# Add Epoxy module directory to PATH
eval "`ep_env || echo exit 1`"
# Source epoxy modules
. ep.sh
# Initialize the suite shell, process command line arguments
ep_suite_init "$@"
# Setup
declare TMP_DIR="`mktemp -d`"
# Add a teardown command
ep_teardown_push rm -Rf "$TMP_DIR"
# More setup and teardown
pushd "$TMP_DIR" >/dev/null
ep_teardown_push eval 'popd >/dev/null'
But where's the meat?
# Run a test
ep_test "touch_present" command -v "test"
# Run another test
ep_test "rm_present" command -v "rm"
# Run a sub-suite
ep_suite_begin "file"; (
ep_suite_init
# Sub-suite teardown
ep_teardown_push rm -f "file1" "file2"
# A test
ep_test "create" touch "file1"
# Setup
touch "file2"
# Another test
ep_test "remove" rm "file2"
); ep_suite_end
function test_function()
{
true
}
function suite_function()
{
ep_test "executable_test" true
ep_test_sh "function_test" test_function
}
ep_suite_begin "subshell_suite"; (
ep_suite_init
ep_suite_sh "function_suite" suite_function
ep_test_begin "subshell_test"; (
ep_test_init
true
); ep_test_end
); ep_suite_end
#!/bin/bash
eval "`ep_env || echo exit 1`"
. ep.sh
ep_suite_init "$@"
declare depth="${EP_SUITE_ARGS[0]-0}"
declare i
if ((depth >= 3)); then
exit
fi
for ((i = 1; i <= 3; i++)); do
ep_suite "suite$i" "$0" -- "$((depth + 1))"
done
Into recursion!
$ ./example -r STRUCT BEGIN '' STRUCT BEGIN '/file' STRUCT BEGIN '/file/create' STRUCT END '/file/create' PASSED STRUCT BEGIN '/file/remove' STRUCT END '/file/remove' PASSED STRUCT BEGIN '/file/stress' STRUCT BEGIN '/file/stress/1' OUTPUT Creating 1 STRUCT END '/file/stress/1' PASSED STRUCT BEGIN '/file/stress/2' OUTPUT Creating 2 STRUCT END '/file/stress/2' PASSED STRUCT BEGIN '/file/stress/3' OUTPUT Creating 3 STRUCT END '/file/stress/3' PASSED OUTPUT Removing 1 OUTPUT Removing 2 OUTPUT Removing 3 STRUCT END '/file/stress' PASSED STRUCT END '/file' PASSED STRUCT END '' PASSED
$ ./example /file/create PASSED /file/remove PASSED /file/stress/1 PASSED /file/stress/2 PASSED /file/stress/3 PASSED /file/stress PASSED /file PASSED PASSED
$ ./example -f-b2 /file/create PASSED /file/remove PASSED /file/stress PASSED /file PASSED PASSED
$ ./example -r | ep_log_beakerlib :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ LOG ] :: /file :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: [ PASS ] :: /file/create :: [ PASS ] :: /file/remove :: [ PASS ] :: /file/stress :: [ 17:05:37 ] :: JOURNAL XML: /var/tmp/beakerlib-XpmJyEb/journal.xml :: [ 17:05:37 ] :: JOURNAL TXT: /var/tmp/beakerlib-XpmJyEb/journal.txt
$ ./example_long /file/create PASSED /file/remove PASSED /file/stress/1 PASSED /file/stress/2 PASSED /file/stress/3 PASSED /file/stress/4 PASSED /file/stress/5 PASSED /file/stress PASSED /file PASSED /dir/create PASSED /dir/remove PASSED /dir/stress/1 PASSED /dir/stress/2 PASSED /dir/stress/3 PASSED /dir/stress/4 PASSED /dir/stress/5 PASSED /dir/stress PASSED /dir PASSED PASSED
$ ./example_long /file/create /dir/remove /file/create PASSED /file PASSED /dir/remove PASSED /dir PASSED PASSED
$ ./example_long /file/@(create|remove|stress/[123]) /file/create PASSED /file/remove PASSED /file/stress/1 PASSED /file/stress/2 PASSED /file/stress/3 PASSED /file/stress PASSED /file PASSED PASSED
ep_test dusk true
ep_test bar true
ep_test vampires true
shotgun
ep_test dawn true
/dusk PASSED
/bar PASSED
/vampires PASSED
ERRORED "./dusk_dawn: line 10: shotgun: command not found"
ep_suite_begin Earth; ( ep_suite_init ep_suite_begin Arthur; ( ep_suite_init ep_teardown_push "lifting ray" ep_test bulldozers true touch earth ep_test bar true ep_test beer true ep_test vogons true ); ep_suite_end
ep_suite_begin Ford; ( ep_suite_init ep_test towel true ); ep_suite_end ); ep_suite_end
/Earth/Arthur/bulldozers PASSED /Earth/Arthur/bar PASSED /Earth/Arthur/beer PASSED /Earth/Arthur/vogons PASSED /Earth/Arthur PANICKED "ep_teardown.sh: line 55: lifting ray: command not found" /Earth PANICKED PANICKED
Tests itself (1.3 KLOC)
Tests Carton (2.3 KLOC)
TCMS (Nitrate) integration
Suite/test code consistency verification
Minor fixes
Extensive testing