From e8a7a6327950349aa897ce84e507d4fd94f43834 Mon Sep 17 00:00:00 2001 From: Andrew Lewis Date: Mon, 27 Jun 2016 21:11:07 +0200 Subject: [PATCH] [Test] New functional test framework --- test/functional/cases/__init__.robot | 18 ++++ test/functional/cases/encrypted_gtube.sh | 9 -- test/functional/cases/general.robot | 38 ++++++++ test/functional/cases/gtube.sh | 8 -- test/functional/cases/http_streamline.pl | 35 ------- test/functional/cases/learn_bad.sh | 12 --- test/functional/cases/learn_empty.sh | 17 ---- test/functional/cases/learn_simple.sh | 17 ---- test/functional/cases/learn_siphash.sh | 18 ---- test/functional/cases/learn_xxhash.sh | 18 ---- test/functional/cases/lua.robot | 31 ++++++ test/functional/cases/relearn-sqlite.sh | 28 ------ test/functional/cases/relearn.sh | 27 ------ test/functional/cases/reload.sh | 23 ----- test/functional/cases/scan_file.pl | 28 ------ test/functional/cases/scan_file.sh | 24 ----- test/functional/cases/spamc.pl | 40 -------- test/functional/cases/spamc_gtube.sh | 8 -- test/functional/cases/statistics.robot | 99 +++++++++++++++++++ test/functional/cases/symbol_depends.sh | 14 --- test/functional/cases/task_flags.sh | 17 ---- test/functional/configs/lua_test.conf | 14 +-- test/functional/configs/stats.conf | 17 ++-- test/functional/configs/trivial.conf | 6 +- test/functional/functions.sh | 118 ----------------------- test/functional/lib/.gitignore | 1 + test/functional/lib/rspamd.py | 87 +++++++++++++++++ test/functional/lib/rspamd.robot | 65 +++++++++++++ test/functional/lib/vars.py | 7 ++ test/functional/{cases => lua}/deps.lua | 0 test/functional/{cases => lua}/flags.lua | 0 test/functional/tests.sh | 60 ------------ 32 files changed, 362 insertions(+), 542 deletions(-) create mode 100644 test/functional/cases/__init__.robot delete mode 100644 test/functional/cases/encrypted_gtube.sh create mode 100644 test/functional/cases/general.robot delete mode 100644 test/functional/cases/gtube.sh delete mode 100644 test/functional/cases/http_streamline.pl delete mode 100644 test/functional/cases/learn_bad.sh delete mode 100644 test/functional/cases/learn_empty.sh delete mode 100644 test/functional/cases/learn_simple.sh delete mode 100644 test/functional/cases/learn_siphash.sh delete mode 100644 test/functional/cases/learn_xxhash.sh create mode 100644 test/functional/cases/lua.robot delete mode 100644 test/functional/cases/relearn-sqlite.sh delete mode 100644 test/functional/cases/relearn.sh delete mode 100644 test/functional/cases/reload.sh delete mode 100644 test/functional/cases/scan_file.pl delete mode 100644 test/functional/cases/scan_file.sh delete mode 100644 test/functional/cases/spamc.pl delete mode 100644 test/functional/cases/spamc_gtube.sh create mode 100644 test/functional/cases/statistics.robot delete mode 100644 test/functional/cases/symbol_depends.sh delete mode 100644 test/functional/cases/task_flags.sh delete mode 100644 test/functional/functions.sh create mode 100644 test/functional/lib/.gitignore create mode 100644 test/functional/lib/rspamd.py create mode 100644 test/functional/lib/rspamd.robot create mode 100644 test/functional/lib/vars.py rename test/functional/{cases => lua}/deps.lua (100%) rename test/functional/{cases => lua}/flags.lua (100%) delete mode 100644 test/functional/tests.sh diff --git a/test/functional/cases/__init__.robot b/test/functional/cases/__init__.robot new file mode 100644 index 000000000..46fdc8f2a --- /dev/null +++ b/test/functional/cases/__init__.robot @@ -0,0 +1,18 @@ +*** Settings *** +Suite Setup Export Global Variables +Library ../lib/rspamd.py +Variables ../lib/vars.py + +*** Keywords *** +Export Global Variables + ${TESTDIR} = Get Test Directory + Set Global Variable ${KEY_PUB1} + Set Global Variable ${KEY_PVT1} + Set Global Variable ${LOCAL_ADDR} + Set Global Variable ${PORT_CONTROLLER} + Set Global Variable ${PORT_NORMAL} + Set Global Variable ${RSPAMC} ${TESTDIR}/../../src/client/rspamc + Set Global Variable ${RSPAMD} ${TESTDIR}/../../src/rspamd + Set Global Variable ${RSPAMD_GROUP} + Set Global Variable ${RSPAMD_USER} + Set Global Variable ${TESTDIR} diff --git a/test/functional/cases/encrypted_gtube.sh b/test/functional/cases/encrypted_gtube.sh deleted file mode 100644 index 016a1f6ec..000000000 --- a/test/functional/cases/encrypted_gtube.sh +++ /dev/null @@ -1,9 +0,0 @@ -# Test rspamd encrypted using gtube - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/trivial.conf" -run_rspamd -run_rspamc symbols --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/gtube.eml" -check_output 'Action: reject' \ No newline at end of file diff --git a/test/functional/cases/general.robot b/test/functional/cases/general.robot new file mode 100644 index 000000000..4016b9a6a --- /dev/null +++ b/test/functional/cases/general.robot @@ -0,0 +1,38 @@ +*** Settings *** +Library ${TESTDIR}/lib/rspamd.py +Resource ${TESTDIR}/lib/rspamd.robot +Suite Setup Generic Setup +Suite Teardown Generic Teardown + +*** Variables *** +${CONFIG} ${TESTDIR}/configs/trivial.conf +${GTUBE} ${TESTDIR}/messages/gtube.eml +&{RSPAMD_KEYWORDS} KEY_PUBLIC=${KEY_PUB1} KEY_PRIVATE=${KEY_PVT1} LOCAL_ADDR=${LOCAL_ADDR} PORT_NORMAL=${PORT_NORMAL} TESTDIR=${TESTDIR} +${RSPAMD_SCOPE} Suite + +*** Test Cases *** +GTUBE + ${result} = Scan Message With Rspamc ${GTUBE} + Follow Rspamd Log + Should Contain ${result.stdout} GTUBE ( + +GTUBE - Encrypted + ${result} = Run Rspamc -p -h ${LOCAL_ADDR}:${PORT_NORMAL} --key ${KEY_PUB1} ${GTUBE} + Follow Rspamd Log + Should Contain ${result.stdout} GTUBE ( + +GTUBE - Scan File feature + ${result} = Scan File ${LOCAL_ADDR} ${PORT_NORMAL} ${GTUBE} + Follow Rspamd Log + Should Contain ${result} GTUBE + +GTUBE - Scan File feature (encoded) + ${encoded} = Encode Filename ${GTUBE} + ${result} = Scan File ${LOCAL_ADDR} ${PORT_NORMAL} ${encoded} + Follow Rspamd Log + Should Contain ${result} GTUBE + +GTUBE - SPAMC + ${result} = Spamc ${LOCAL_ADDR} ${PORT_NORMAL} ${GTUBE} + Follow Rspamd Log + Should Contain ${result} GTUBE diff --git a/test/functional/cases/gtube.sh b/test/functional/cases/gtube.sh deleted file mode 100644 index 795b0dc45..000000000 --- a/test/functional/cases/gtube.sh +++ /dev/null @@ -1,8 +0,0 @@ -# Test rspamd using gtube - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/trivial.conf" -run_rspamd -run_rspamc symbols "$TEST_DIRNAME/messages/gtube.eml" -check_output "$output" 'Action: reject' \ No newline at end of file diff --git a/test/functional/cases/http_streamline.pl b/test/functional/cases/http_streamline.pl deleted file mode 100644 index e5afc5aff..000000000 --- a/test/functional/cases/http_streamline.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env perl - -use warnings; -use strict; - -use Socket; - -my $host = "127.0.0.1"; -my $port = 56789; -my $input = shift; - -open(INPUT, "< $input") or die "Can't open input file $input\n"; - -socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) - or die "Can't create a socket $!\n"; -connect(SOCKET, pack_sockaddr_in($port, inet_aton($host))) - or die "Can't connect to port $port! \n"; - -print SOCKET "POST /symbols HTTP/1.0\r\n\r\n"; - -while (my $line = ) { - print SOCKET $line; -} - -SOCKET->autoflush(1); - -shutdown(SOCKET, 1); - -close(INPUT); - -while (my $line = ) { - print $line; -} - -close(SOCKET); diff --git a/test/functional/cases/learn_bad.sh b/test/functional/cases/learn_bad.sh deleted file mode 100644 index 5c5410c91..000000000 --- a/test/functional/cases/learn_bad.sh +++ /dev/null @@ -1,12 +0,0 @@ -# Test rspamd learn with bad stats - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=/non/existent - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'cannot open backend' \ No newline at end of file diff --git a/test/functional/cases/learn_empty.sh b/test/functional/cases/learn_empty.sh deleted file mode 100644 index 855979fd3..000000000 --- a/test/functional/cases/learn_empty.sh +++ /dev/null @@ -1,17 +0,0 @@ -# Test rspamd learn empty part - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$BATS_TEST_DIRNAME/messages/empty_part.eml" -check_output $output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$BATS_TEST_DIRNAME/messages/empty_part.eml" -check_output $output 'BAYES_SPAM' \ No newline at end of file diff --git a/test/functional/cases/learn_simple.sh b/test/functional/cases/learn_simple.sh deleted file mode 100644 index d44056918..000000000 --- a/test/functional/cases/learn_simple.sh +++ /dev/null @@ -1,17 +0,0 @@ -# Test rspamd learn - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_SPAM' \ No newline at end of file diff --git a/test/functional/cases/learn_siphash.sh b/test/functional/cases/learn_siphash.sh deleted file mode 100644 index dcab7410a..000000000 --- a/test/functional/cases/learn_siphash.sh +++ /dev/null @@ -1,18 +0,0 @@ -# Test rspamd learn using siphash - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} \ - STATS_HASH="siphash" - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_SPAM' \ No newline at end of file diff --git a/test/functional/cases/learn_xxhash.sh b/test/functional/cases/learn_xxhash.sh deleted file mode 100644 index 2b75b9aa5..000000000 --- a/test/functional/cases/learn_xxhash.sh +++ /dev/null @@ -1,18 +0,0 @@ -# Test rspamd learn using xxhash - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} \ - STATS_HASH="xxh" - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_SPAM' \ No newline at end of file diff --git a/test/functional/cases/lua.robot b/test/functional/cases/lua.robot new file mode 100644 index 000000000..b8005cd8f --- /dev/null +++ b/test/functional/cases/lua.robot @@ -0,0 +1,31 @@ +*** Settings *** +Library ${TESTDIR}/lib/rspamd.py +Resource ${TESTDIR}/lib/rspamd.robot + +*** Variables *** +${CONFIG} ${TESTDIR}/configs/lua_test.conf +${MESSAGE} ${TESTDIR}/messages/spam_message.eml +${RSPAMD_SCOPE} Test + +*** Keywords *** +Lua Setup + [Arguments] ${lua_script} + &{RSPAMD_KEYWORDS} = Create Dictionary LOCAL_ADDR=${LOCAL_ADDR} LUA_SCRIPT=${lua_script} PORT_CONTROLLER=${PORT_CONTROLLER} PORT_NORMAL=${PORT_NORMAL} TESTDIR=${TESTDIR} + Set Test Variable &{RSPAMD_KEYWORDS} + Generic Setup + +*** Test Cases *** +Flags + [Setup] Lua Setup ${TESTDIR}/lua/flags.lua + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} stat + Should Contain ${result.stdout} Messages scanned: 0 + [Teardown] Generic Teardown + +Dependencies + [Setup] Lua Setup ${TESTDIR}/lua/deps.lua + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} DEP10 + [Teardown] Generic Teardown diff --git a/test/functional/cases/relearn-sqlite.sh b/test/functional/cases/relearn-sqlite.sh deleted file mode 100644 index f678b319c..000000000 --- a/test/functional/cases/relearn-sqlite.sh +++ /dev/null @@ -1,28 +0,0 @@ -# Test rspamd re-learn sqlite3 backend - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} \ - STATS_BACKEND="sqlite3" - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_SPAM' - -run_rspamc learn_ham \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_HAM' \ No newline at end of file diff --git a/test/functional/cases/relearn.sh b/test/functional/cases/relearn.sh deleted file mode 100644 index 9d52e4310..000000000 --- a/test/functional/cases/relearn.sh +++ /dev/null @@ -1,27 +0,0 @@ -# Test rspamd re-learn - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/stats.conf" \ - STATSDIR=${TMPDIR} - -run_rspamd -run_rspamc learn_spam \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_SPAM' - -run_rspamc learn_ham \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'success.*true' - -run_rspamc symbols \ - --key y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'BAYES_HAM' \ No newline at end of file diff --git a/test/functional/cases/reload.sh b/test/functional/cases/reload.sh deleted file mode 100644 index cb1ce0ba3..000000000 --- a/test/functional/cases/reload.sh +++ /dev/null @@ -1,23 +0,0 @@ -# Test rspamd reload - -. ${TEST_DIRNAME}/functions.sh - -sed -e 's|@@LUA_SCRIPT@@|${TESTDIR}/cases/deps.lua|' < \ - "$TEST_DIRNAME/configs/lua_test.conf" > \ - "$TMPDIR/rspamd.conf" -export RSPAMD_CONFIG="$TMPDIR/rspamd.conf" \ - STATSDIR=${TMPDIR} -run_rspamd - -run_rspamc symbols \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'DEP10' - -kill -HUP `cat ${TMPDIR}/rspamd.pid` -sleep 0.5 -kill -HUP `cat ${TMPDIR}/rspamd.pid` -sleep 0.5 - -run_rspamc symbols \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'DEP10' \ No newline at end of file diff --git a/test/functional/cases/scan_file.pl b/test/functional/cases/scan_file.pl deleted file mode 100644 index 674d4aee6..000000000 --- a/test/functional/cases/scan_file.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env perl - -use warnings; -use strict; - -use Socket; - -my $host = "127.0.0.1"; -my $port = 56789; -my $input_file = shift; - -socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) - or die "Can't create a socket $!\n"; -connect(SOCKET, pack_sockaddr_in($port, inet_aton($host))) - or die "Can't connect to port $port! \n"; - -print SOCKET "GET /symbols?${input_file} HTTP/1.0\r\n\r\n"; - -SOCKET->autoflush(1); - -shutdown(SOCKET, 1); - -while (my $line = ) { - print $line; -} - -close(SOCKET); - diff --git a/test/functional/cases/scan_file.sh b/test/functional/cases/scan_file.sh deleted file mode 100644 index 107d335e4..000000000 --- a/test/functional/cases/scan_file.sh +++ /dev/null @@ -1,24 +0,0 @@ -# Test rspamd gtube using scan file feature - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/trivial.conf" -run_rspamd -run perl "$TEST_DIRNAME/cases/scan_file.pl" "file=$TEST_DIRNAME/messages/gtube.eml" -check_output 'GTUBE' - -run perl "$TEST_DIRNAME/cases/scan_file.pl" "path=$TEST_DIRNAME/messages/gtube.eml" -check_output 'GTUBE' - -run perl "$TEST_DIRNAME/cases/scan_file.pl" "path=\"$TEST_DIRNAME/messages/gtube.eml\"" -check_output 'GTUBE' - -# Hex encode every character -_hex_name=`printf "$TEST_DIRNAME/messages/gtube.eml" | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'` - -run perl "$TEST_DIRNAME/cases/scan_file.pl" "file=${_hex_name}" -check_output 'GTUBE' - -_hex_name=`printf "\"$TEST_DIRNAME/messages/gtube.eml\"" | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'` -run perl "$TEST_DIRNAME/cases/scan_file.pl" "path=${_hex_name}" -check_output 'GTUBE' diff --git a/test/functional/cases/spamc.pl b/test/functional/cases/spamc.pl deleted file mode 100644 index abeefb8b4..000000000 --- a/test/functional/cases/spamc.pl +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env perl - -use warnings; -use strict; - -use Socket; - -my $host = "127.0.0.1"; -my $port = 56789; -my $input = shift; - -open(INPUT, "< $input") or die "Can't open input file $input\n"; - -socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) - or die "Can't create a socket $!\n"; -connect(SOCKET, pack_sockaddr_in($port, inet_aton($host))) - or die "Can't connect to port $port! \n"; - -print SOCKET "SYMBOLS SPAMC/1.0\r\n"; - -my $msg; -while (my $line = ) { - $msg .= $line; -} - -my $dlen = length($msg); -print SOCKET "Content-length: $dlen\r\n\r\n$msg"; - -SOCKET->autoflush(1); - -shutdown(SOCKET, 1); - -close(INPUT); - -while (my $line = ) { - print $line; -} - -close(SOCKET); - diff --git a/test/functional/cases/spamc_gtube.sh b/test/functional/cases/spamc_gtube.sh deleted file mode 100644 index ffad990eb..000000000 --- a/test/functional/cases/spamc_gtube.sh +++ /dev/null @@ -1,8 +0,0 @@ -# Test rspamd spamc gtube - -. ${TEST_DIRNAME}/functions.sh - -export RSPAMD_CONFIG="$TEST_DIRNAME/configs/trivial.conf" -run_rspamd -run perl "$TEST_DIRNAME/cases/spamc.pl" "$TEST_DIRNAME/messages/gtube.eml" -check_output 'GTUBE' \ No newline at end of file diff --git a/test/functional/cases/statistics.robot b/test/functional/cases/statistics.robot new file mode 100644 index 000000000..d9df49813 --- /dev/null +++ b/test/functional/cases/statistics.robot @@ -0,0 +1,99 @@ +*** Settings *** +Library ${TESTDIR}/lib/rspamd.py +Resource ${TESTDIR}/lib/rspamd.robot + +*** Variables *** +@{ALIASES} STATSDIR +${CONFIG} ${TESTDIR}/configs/stats.conf +${MESSAGE} ${TESTDIR}/messages/spam_message.eml +${RSPAMD_SCOPE} Test + +*** Keywords *** +Statistics Setup + [Arguments] @{aliases} &{kw} + &{RSPAMD_KEYWORDS} = Create Dictionary KEY_PRIVATE=${KEY_PVT1} KEY_PUBLIC=${KEY_PUB1} LOCAL_ADDR=${LOCAL_ADDR} PORT_CONTROLLER=${PORT_CONTROLLER} PORT_NORMAL=${PORT_NORMAL} TESTDIR=${TESTDIR} + Update Dictionary ${RSPAMD_KEYWORDS} ${kw} + Set Test Variable &{RSPAMD_KEYWORDS} + ${TMPDIR} ${RSPAMD_PID} ${RSPAMD_LOGPOS} = Run Rspamd @{aliases} &{RSPAMD_KEYWORDS} + Export Rspamd Vars To Test ${TMPDIR} ${RSPAMD_LOGPOS} ${RSPAMD_PID} + +*** Test Cases *** +Sqlite Learn - Keyed, siphash + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=sqlite3 STATS_HASH=siphash STATS_KEY=${KEY_PVT1} + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Should Contain ${result.stdout} success = true + Follow Rspamd Log + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + [Teardown] Generic Teardown + +Sqlite Learn - Keyed, xxhash + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=sqlite3 STATS_HASH=xxh STATS_KEY=${KEY_PVT1} + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + [Teardown] Generic Teardown + +Sqlite Learn - Broken Stats Directory + [Setup] Statistics Setup @{EMPTY} STATS_BACKEND=sqlite3 STATS_HASH=xxh STATS_KEY=${KEY_PVT1} STATSDIR=/does/not/exist + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Not Contain ${result.stdout} success = true + [Teardown] Generic Teardown + +Sqlite Learn - Empty part + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=sqlite3 STATS_HASH=xxh STATS_KEY=${KEY_PVT1} + Set Test Variable ${MESSAGE} ${TESTDIR}/messages/empty_part.eml + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + [Teardown] Generic Teardown + +Sqlite Relearn + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=sqlite3 STATS_HASH=xxh STATS_KEY=${KEY_PVT1} + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_ham ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_HAM + [Teardown] Generic Teardown + +Mmap Learn + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=mmap STATS_HASH=compat STATS_KEY=${KEY_PVT1} + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + [Teardown] Generic Teardown + +Mmap Relearn + [Setup] Statistics Setup @{ALIASES} STATS_BACKEND=mmap STATS_HASH=compat STATS_KEY=${KEY_PVT1} + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_spam ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_SPAM + ${result} = Run Rspamc -h ${LOCAL_ADDR}:${PORT_CONTROLLER} learn_ham ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} success = true + ${result} = Scan Message With Rspamc ${MESSAGE} + Follow Rspamd Log + Should Contain ${result.stdout} BAYES_HAM + [Teardown] Generic Teardown diff --git a/test/functional/cases/symbol_depends.sh b/test/functional/cases/symbol_depends.sh deleted file mode 100644 index bcf718f7f..000000000 --- a/test/functional/cases/symbol_depends.sh +++ /dev/null @@ -1,14 +0,0 @@ -# Test rspamd symbol dependencies - -. ${TEST_DIRNAME}/functions.sh - -sed -e 's|@@LUA_SCRIPT@@|${TESTDIR}/cases/deps.lua|' < \ - "$TEST_DIRNAME/configs/lua_test.conf" > \ - "$TMPDIR/rspamd.conf" -export RSPAMD_CONFIG="$TMPDIR/rspamd.conf" \ - STATSDIR=${TMPDIR} -run_rspamd - -run_rspamc symbols \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'DEP10' \ No newline at end of file diff --git a/test/functional/cases/task_flags.sh b/test/functional/cases/task_flags.sh deleted file mode 100644 index 501d242cb..000000000 --- a/test/functional/cases/task_flags.sh +++ /dev/null @@ -1,17 +0,0 @@ -# Test rspamd_task:get|set_flags functions - -. ${TEST_DIRNAME}/functions.sh - -sed -e 's|@@LUA_SCRIPT@@|${TESTDIR}/cases/flags.lua|' < \ - "$TEST_DIRNAME/configs/lua_test.conf" > \ - "$TMPDIR/rspamd.conf" -export RSPAMD_CONFIG="$TMPDIR/rspamd.conf" \ - STATSDIR=${TMPDIR} -run_rspamd - -run_rspamc symbols \ - "$TEST_DIRNAME/messages/spam_message.eml" -check_output 'skip,extended_urls,no_log,no_stat' - -run_rspamc stat -check_output 'Messages scanned: 0' \ No newline at end of file diff --git a/test/functional/configs/lua_test.conf b/test/functional/configs/lua_test.conf index f43ceb49a..bcb1c3323 100644 --- a/test/functional/configs/lua_test.conf +++ b/test/functional/configs/lua_test.conf @@ -18,22 +18,14 @@ metric = { worker { type = normal - bind_socket = localhost:56789 + bind_socket = ${LOCAL_ADDR}:${PORT_NORMAL} count = 1 - keypair { - pubkey = "y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty"; - privkey = "oswsyqndpj3swqa4yqm4yzoyih83otqkeoxpo9km95o46ixh6quy"; - } } worker { type = controller - bind_socket = localhost:56790 + bind_socket = ${LOCAL_ADDR}:${PORT_CONTROLLER} count = 1 - keypair { - pubkey = "y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty"; - privkey = "oswsyqndpj3swqa4yqm4yzoyih83otqkeoxpo9km95o46ixh6quy"; - } secure_ip = ["127.0.0.1", "::1"]; } -lua = @@LUA_SCRIPT@@; +lua = ${LUA_SCRIPT}; diff --git a/test/functional/configs/stats.conf b/test/functional/configs/stats.conf index 06c1884aa..144b7a886 100644 --- a/test/functional/configs/stats.conf +++ b/test/functional/configs/stats.conf @@ -18,25 +18,26 @@ metric = { worker { type = normal - bind_socket = localhost:56789 + bind_socket = ${LOCAL_ADDR}:${PORT_NORMAL} count = 1 keypair { - pubkey = "y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty"; - privkey = "oswsyqndpj3swqa4yqm4yzoyih83otqkeoxpo9km95o46ixh6quy"; + pubkey = "${KEY_PUBLIC}"; + privkey = "${KEY_PRIVATE}"; } } worker { type = controller - bind_socket = localhost:56790 + bind_socket = ${LOCAL_ADDR}:${PORT_CONTROLLER} count = 1 keypair { - pubkey = "y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty"; - privkey = "oswsyqndpj3swqa4yqm4yzoyih83otqkeoxpo9km95o46ixh6quy"; + pubkey = "${KEY_PUBLIC}"; + privkey = "${KEY_PRIVATE}"; } secure_ip = ["127.0.0.1", "::1"]; } classifier { + languages_enabled = true; tokenizer { name = "osb"; hash = ${STATS_HASH} @@ -47,16 +48,18 @@ classifier { symbol = BAYES_SPAM; path = ${STATSDIR}/rspamd-bats-bayes.spam; size = 1M; + write_servers = ${REDIS_SERVER} } statfile { symbol = BAYES_HAM; path = ${STATSDIR}/rspamd-bats-bayes.ham; size = 1M; + write_servers = ${REDIS_SERVER} } cache { - name = "sqlite3"; path = ${STATSDIR}/rspamd-bats-cache.sqlite; + write_servers = ${REDIS_SERVER} } } diff --git a/test/functional/configs/trivial.conf b/test/functional/configs/trivial.conf index 1233b479b..03fb11e0f 100644 --- a/test/functional/configs/trivial.conf +++ b/test/functional/configs/trivial.conf @@ -18,10 +18,10 @@ metric = { worker { type = normal - bind_socket = localhost:56789 + bind_socket = ${LOCAL_ADDR}:${PORT_NORMAL} count = 1 keypair { - pubkey = "y3ms1knmetxf8gdeixkf74b6tbpxqugmxzqksnjodiqei7tksyty"; - privkey = "oswsyqndpj3swqa4yqm4yzoyih83otqkeoxpo9km95o46ixh6quy"; + pubkey = "${KEY_PUBLIC}"; + privkey = "${KEY_PRIVATE}"; } } diff --git a/test/functional/functions.sh b/test/functional/functions.sh deleted file mode 100644 index b604f7dc5..000000000 --- a/test/functional/functions.sh +++ /dev/null @@ -1,118 +0,0 @@ -save_error() { - _where=$1 - _reason=$2 - - printf 'Failed in %s: %s\n' "$_where" "$_reason" > ${TMPDIR}/test.err - mkdir -p /tmp/rspamd-failed-tests/${TEST_NAME} || true - # Save logs - RSPAMD_PID=`cat ${TMPDIR}/rspamd.pid` - - if [ F"${RSPAMD_PID}" != F"" ] ; then - kill -USR1 ${RSPAMD_PID} > /dev/null 2>&1 - sleep 0.5 - fi - cp -rf ${TMPDIR}/* /tmp/rspamd-failed-tests/${TEST_NAME} - - exit 1 -} - -run_rspamd() { - RSPAMD_USER=${RSPAMD_USER:-"nobody"} - RSPAMD_GROUP=${RSPAMD_GROUP:-"nogroup"} - RSPAMD=${RSPAMD:-"$TEST_DIRNAME/../../src/rspamd"} - STATS_BACKEND=${STATS_BACKEND:-"mmap"} - STATS_HASH=${STATS_HASH:-"compat"} - STATS_KEY=${STATS_KEY:-"osipg87ms5gzsis33fdrhaqn5wocp6qfofzxjbw8k1wh9yb6adty"} - - ${RSPAMD} -c ${RSPAMD_CONFIG} -u ${RSPAMD_USER} -g ${RSPAMD_GROUP} \ - TMPDIR=${TMPDIR} \ - STATSDIR=${STATSDIR} \ - LUADIR=${LUADIR} \ - STATS_BACKEND=${STATS_BACKEND} \ - STATS_HASH=${STATS_HASH} \ - TESTDIR=${TEST_DIRNAME} \ - STATS_KEY=${STATS_KEY} >> ${TMPDIR}/rspamd.out 2>&1 - - if [ $? -eq 0 ] ; then - export RSPAMD_PID=`cat ${TMPDIR}/rspamd.pid` - else - save_error 'rspamd' 'cannot start rspamd' - fi -} - - -teardown() { - RSPAMD_PID=`cat ${TMPDIR}/rspamd.pid` - - if [ F"${RSPAMD_PID}" != F"" ] ; then - kill -TERM ${RSPAMD_PID} > /dev/null 2>&1 - - while [ $? -eq 0 ] ; do - sleep 0.1 - kill -0 ${RSPAMD_PID} > /dev/null 2>&1 - if [ $? -eq 0 ] ; then - kill -TERM ${RSPAMD_PID} > /dev/null 2>&1 - fi - kill -0 ${RSPAMD_PID} > /dev/null 2>&1 - done - fi - - if [ -d "${TMPDIR}" ] ; then - (echo "${TMPDIR}" | egrep '^/tmp.*$' > /dev/null 2>&1) && rm -fr "${TMPDIR}" - fi -} - -check_output() { - _pattern="$1" - - echo "$output" | egrep "$_pattern" > /dev/null 2>&1 - - _saved_exit=$? - if [ $_saved_exit -ne 0 ] ; then - echo "$output" > ${TMPDIR}/rspamc.err - save_error 'rspamc' "Expected pattern $_pattern is not found" - return $_saved_exit - fi - - return 0 -} - -run_rspamc() { - _command=$1 - shift - _rspamc="$TEST_DIRNAME/../../src/client/rspamc" - - case $_command in - learn_spam|learn_ham|fuzzy_add|fuzzy_del|stat) _host="localhost:56790" ;; - *) _host="localhost:56789" ;; - esac - - output=`$_rspamc -h $_host $_command $@ 2>&1` - echo "$output" > ${TMPDIR}/rspamc.output - - if [ $? -eq 0 ] ; then - export output - return 0 - else - save_error 'rspamc' "Wrong exit code" - fi - - return 1 -} - -run() { - _command=$1 - shift - - output=`$_command $@ 2>&1` - echo "$output" > "${TMPDIR}/${_command}.output" - - if [ $? -eq 0 ] ; then - export output - return 0 - else - save_error "${_command}" "Wrong exit code" - fi - - return 1 -} \ No newline at end of file diff --git a/test/functional/lib/.gitignore b/test/functional/lib/.gitignore new file mode 100644 index 000000000..0d20b6487 --- /dev/null +++ b/test/functional/lib/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/test/functional/lib/rspamd.py b/test/functional/lib/rspamd.py new file mode 100644 index 000000000..998eb6960 --- /dev/null +++ b/test/functional/lib/rspamd.py @@ -0,0 +1,87 @@ +import grp +import os +import os.path +import pwd +import shutil +import signal +import socket +import string +import tempfile +import time +import urllib2 + +def cleanup_temporary_directory(directory): + shutil.rmtree(directory) + +def encode_filename(filename): + return "".join(['%%%0X' % ord(b) for b in filename]) + +def get_test_directory(): + return os.path.abspath(os.path.dirname(os.path.realpath(__file__)) + "../..") + +def make_temporary_directory(): + return tempfile.mkdtemp() + +def populate_rspamd_config(template_file, temporary_dir, **config): + t = string.Template(open(template_file).read()) + f = open("%s/rspamd.conf" % temporary_dir, "w") + f.write(t.safe_substitute(config)) + f.close() + +def process_should_exist(pid): + pid = int(pid) + os.kill(pid, 0) + +def read_log_from_position(filename, offset): + offset = long(offset) + f = open(filename, 'rb') + f.seek(offset) + goo = f.read() + size = len(goo) + return [goo, size+offset] + +def scan_file(addr, port, filename): + req = urllib2.Request("http://%s:%s/symbols?%s" % (addr, port, filename)) + response = urllib2.urlopen(req) + return response.read() + +def Send_SIGUSR1(pid): + pid = int(pid) + os.kill(pid, signal.SIGUSR1) + +def set_directory_ownership(path, username, groupname): + uid=pwd.getpwnam(username).pw_uid + gid=grp.getgrnam(groupname).gr_gid + os.chown(path, uid, gid) + +def spamc(addr, port, filename): + goo = open(filename, 'rb').read() + length = len(goo) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((addr, port)) + s.send("SYMBOLS SPAMC/1.0\r\nContent-length: %s\r\n\r\n%s" % (length, goo)) + s.shutdown(socket.SHUT_WR) + r = s.recv(2048) + return r + +def update_dictionary(a, b): + a.update(b) + return a + +def shutdown_rspamd(pid): + pid = int(pid) + process_should_exist(pid) + i = 0 + while i < 5: + try: + os.kill(pid, signal.SIGTERM) + time.sleep(0.1) + except: + break + if i >= 5: + while True: + try: + os.kill(pid, signal.SIGTERM) + time.sleep(0.1) + except: + break diff --git a/test/functional/lib/rspamd.robot b/test/functional/lib/rspamd.robot new file mode 100644 index 000000000..a5ddca20e --- /dev/null +++ b/test/functional/lib/rspamd.robot @@ -0,0 +1,65 @@ +*** Settings *** +Library Collections +Library OperatingSystem +Library Process + +*** Keywords *** +Export Rspamd Vars To Suite + [Arguments] ${TMPDIR} ${RSPAMD_LOGPOS} ${RSPAMD_PID} + Set Suite Variable ${TMPDIR} + Set Suite Variable ${RSPAMD_LOGPOS} + Set Suite Variable ${RSPAMD_PID} + +Export Rspamd Vars To Test + [Arguments] ${TMPDIR} ${RSPAMD_LOGPOS} ${RSPAMD_PID} + Set Test Variable ${TMPDIR} + Set Test Variable ${RSPAMD_LOGPOS} + Set Test Variable ${RSPAMD_PID} + +Follow Rspamd Log + ${RSPAMD_LOGPOS} = Log Logs ${TMPDIR}/rspamd.log ${RSPAMD_LOGPOS} + Run Keyword If '${RSPAMD_SCOPE}' == 'Test' Set Test Variable ${RSPAMD_LOGPOS} + ... ELSE IF '${RSPAMD_SCOPE}' == 'Suite' Set Suite Variable ${RSPAMD_LOGPOS} + ... ELSE Fail 'RSPAMD_SCOPE must be Test or Suite' + +Generic Setup + ${TMPDIR} ${RSPAMD_PID} ${RSPAMD_LOGPOS} = Run Rspamd + Run Keyword If '${RSPAMD_SCOPE}' == 'Test' Export Rspamd Vars To Test ${TMPDIR} ${RSPAMD_LOGPOS} ${RSPAMD_PID} + ... ELSE IF '${RSPAMD_SCOPE}' == 'Suite' Export Rspamd Vars To Suite ${TMPDIR} ${RSPAMD_LOGPOS} ${RSPAMD_PID} + ... ELSE Fail 'RSPAMD_SCOPE must be Test or Suite' + +Generic Teardown + Shutdown Rspamd ${RSPAMD_PID} + Cleanup Temporary Directory ${TMPDIR} + +Log Logs + [Arguments] ${logfile} ${position} + ${the_log} ${position} = Read Log From Position ${logfile} ${position} + Log ${the_log} + [Return] ${position} + +Run Rspamc + [Arguments] @{args} + ${result} = Run Process ${RSPAMC} @{args} + Should Be Equal As Integers ${result.rc} 0 + [Return] ${result} + +Run Rspamd + [Arguments] @{args} &{kw} + ${tmpdir} = Make Temporary Directory + Set Directory Ownership ${tmpdir} ${RSPAMD_USER} ${RSPAMD_GROUP} + Set To Dictionary ${RSPAMD_KEYWORDS} TMPDIR=${tmpdir} + Update Dictionary ${RSPAMD_KEYWORDS} ${kw} + :FOR ${i} IN @{args} + \ Set To Dictionary ${RSPAMD_KEYWORDS} ${i} ${tmpdir} + Populate Rspamd Config ${CONFIG} ${tmpdir} &{RSPAMD_KEYWORDS} + ${result} = Run Process ${RSPAMD} -u ${RSPAMD_USER} -g ${RSPAMD_GROUP} -c ${tmpdir}/rspamd.conf + ${rspamd_logpos} = Log Logs ${tmpdir}/rspamd.log 0 + Should Be Equal As Integers ${result.rc} 0 + ${rspamd_pid} = Get File ${tmpdir}/rspamd.pid + [Return] ${tmpdir} ${rspamd_pid} ${rspamd_logpos} + +Scan Message With Rspamc + [Arguments] ${msg_file} + ${result} = Run Rspamc -p -h ${LOCAL_ADDR}:${PORT_NORMAL} ${msg_file} + [Return] ${result} diff --git a/test/functional/lib/vars.py b/test/functional/lib/vars.py new file mode 100644 index 000000000..78151bd37 --- /dev/null +++ b/test/functional/lib/vars.py @@ -0,0 +1,7 @@ +KEY_PVT1 = 'ekd3x36tfa5gd76t6pa8hqif3ott7n1siuux68exbkk7ukscte9y' +KEY_PUB1 = 'm8kneubpcjsb8sbsoj7jy7azj9fdd3xmj63txni86a8ye9ncomny' +LOCAL_ADDR = 'localhost' +PORT_CONTROLLER = 56790 +PORT_NORMAL = 56789 +RSPAMD_GROUP = 'nogroup' +RSPAMD_USER = 'nobody' diff --git a/test/functional/cases/deps.lua b/test/functional/lua/deps.lua similarity index 100% rename from test/functional/cases/deps.lua rename to test/functional/lua/deps.lua diff --git a/test/functional/cases/flags.lua b/test/functional/lua/flags.lua similarity index 100% rename from test/functional/cases/flags.lua rename to test/functional/lua/flags.lua diff --git a/test/functional/tests.sh b/test/functional/tests.sh deleted file mode 100644 index 245ac7dd7..000000000 --- a/test/functional/tests.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -TMPDIR= -RSPAMD_PID= -TEST_DIRNAME=`cd $(dirname $0) ; pwd` -TEST_NAME='top' -TEST_DESCRIPTION='no description' -FAILED_TESTS=0 -SUCCESSFUL_TESTS=0 -SKIPPED_TESTS=0 - -. ${TEST_DIRNAME}/functions.sh - -make_tempdir() { - export TMPDIR=`mktemp -d /tmp/rspamd-test-XXXXXX` -} - -run_test() { - TEST_NAME=`basename $1 | sed -e 's/.sh$//'` - TEST_DESCRIPTION=`head -1 $1 | sed -e 's/^# *//'` - - printf '%s: ' "${TEST_DESCRIPTION}" - - egrep '^skip$' $1 - if [ $? -eq 0 ] ; then - SKIPPED_TESTS=$(($SKIPPED_TESTS + 1)) - echo "SKIP" - return 0 - fi - - make_tempdir - export TEST_NAME TMPDIR TEST_DESCRIPTION TEST_DIRNAME - sh "$1" - - if [ $? -ne 0 ] ; then - FAILED_TESTS=$(($FAILED_TESTS + 1)) - echo "FAIL" - else - SUCCESSFUL_TESTS=$(($SUCCESSFUL_TESTS + 1)) - if [ -d /tmp/rspamd-failed-tests/${TEST_NAME} ] ; then - rm -fr /tmp/rspamd-failed-tests/${TEST_NAME} - fi - echo "OK" - fi - - teardown -} - -if [ $# -ne 0 ] ; then - for _test in $@ ; do - run_test $_test - done -else - for _test in ${TEST_DIRNAME}/cases/*.sh ; do - run_test $_test - done - -fi - -echo "Successful tests: $SUCCESSFUL_TESTS; failed tests: $FAILED_TESTS, skipped tests: $SKIPPED_TESTS" \ No newline at end of file -- 2.39.5