From ce6b7e86cdd63ba1540d20aa22403d2b13d2e59f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 3 Apr 2009 17:54:09 +0200 Subject: improved test suite and added test for new output module interface The testbench has now a generic driver that can run a whole class of test suites just by providing a config file and test cases. This does not cover all testing needs, but a lot. We have now added one test for the new array-passing output plugin interface. --- plugins/omstdout/omstdout.c | 2 + tests/Makefile.am | 28 ++-- tests/omod-if-array.sh | 1 + tests/parsertest.c | 269 --------------------------------- tests/parsertest.sh | 1 + tests/testruns/1.parse1 | 3 - tests/testruns/parser.conf | 9 -- tests/testruns/rfc3164.parse1 | 4 - tests/testruns/rfc5424-1.parse1 | 3 - tests/testruns/rfc5424-2.parse1 | 4 - tests/testruns/rfc5424-3.parse1 | 4 - tests/testruns/rfc5424-4.parse1 | 4 - tests/testsuites/1.omod-if-array | 2 + tests/testsuites/1.parse1 | 3 + tests/testsuites/omod-if-array.conf | 14 ++ tests/testsuites/parse1.conf | 9 ++ tests/testsuites/rfc3164.parse1 | 4 + tests/testsuites/rfc5424-1.parse1 | 3 + tests/testsuites/rfc5424-2.parse1 | 4 + tests/testsuites/rfc5424-3.parse1 | 4 + tests/testsuites/rfc5424-4.parse1 | 4 + tests/udptester.c | 291 ++++++++++++++++++++++++++++++++++++ 22 files changed, 358 insertions(+), 312 deletions(-) create mode 100755 tests/omod-if-array.sh delete mode 100644 tests/parsertest.c create mode 100755 tests/parsertest.sh delete mode 100644 tests/testruns/1.parse1 delete mode 100644 tests/testruns/parser.conf delete mode 100644 tests/testruns/rfc3164.parse1 delete mode 100644 tests/testruns/rfc5424-1.parse1 delete mode 100644 tests/testruns/rfc5424-2.parse1 delete mode 100644 tests/testruns/rfc5424-3.parse1 delete mode 100644 tests/testruns/rfc5424-4.parse1 create mode 100644 tests/testsuites/1.omod-if-array create mode 100644 tests/testsuites/1.parse1 create mode 100644 tests/testsuites/omod-if-array.conf create mode 100644 tests/testsuites/parse1.conf create mode 100644 tests/testsuites/rfc3164.parse1 create mode 100644 tests/testsuites/rfc5424-1.parse1 create mode 100644 tests/testsuites/rfc5424-2.parse1 create mode 100644 tests/testsuites/rfc5424-3.parse1 create mode 100644 tests/testsuites/rfc5424-4.parse1 create mode 100644 tests/udptester.c diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index e491005c..7c63b5c4 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -107,6 +107,8 @@ CODESTARTdoAction iParam = 0; iBuf = 0; while(szParams[iParam] != NULL) { + if(iParam > 0) + szBuf[iBuf++] = ','; /* all but first need a delimiter */ iParamVal = 0; while(szParams[iParam][iParamVal] != '\0' && iBuf < sizeof(szBuf)) { szBuf[iBuf++] = szParams[iParam][iParamVal++]; diff --git a/tests/Makefile.am b/tests/Makefile.am index 09d1a0b6..ab1c5a62 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,6 @@ -TESTRUNS = rt_init rscript parsertest -check_PROGRAMS = $(TESTRUNS) ourtail -TESTS = $(TESTRUNS) cfg.sh +TESTRUNS = rt_init rscript +check_PROGRAMS = $(TESTRUNS) ourtail udptester +TESTS = $(TESTRUNS) cfg.sh parsertest.sh omod-if-array.sh TESTS_ENVIRONMENT = RSYSLOG_MODDIR='$(abs_top_builddir)'/runtime/.libs/ DISTCLEANFILES=rsyslog.pid test_files = testbench.h runtime-dummy.c @@ -17,19 +17,23 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ DevNull.cfgtest \ err1.rstest \ NoExistFile.cfgtest \ - testruns/parser.conf \ - testruns/1.parse1 \ - testruns/rfc3164.parse1 \ - testruns/rfc5424-1.parse1 \ - testruns/rfc5424-2.parse1 \ - testruns/rfc5424-3.parse1 \ - testruns/rfc5424-4.parse1 \ + testsuites/parse1.conf \ + testsuites/1.parse1 \ + testsuites/rfc3164.parse1 \ + testsuites/rfc5424-1.parse1 \ + testsuites/rfc5424-2.parse1 \ + testsuites/rfc5424-3.parse1 \ + testsuites/rfc5424-4.parse1 \ + testsuites/omod-if-array.conf \ + testsuites/1.omod-if-array \ + parsertest.sh \ + omod-if-array.sh \ cfg.sh ourtail_SOURCES = ourtail.c -parsertest_SOURCES = parsertest.c getline.c -parsertest_LDADD = $(SOL_LIBS) +udptester_SOURCES = udptester.c getline.c +udptester_LDADD = $(SOL_LIBS) rt_init_SOURCES = rt-init.c $(test_files) rt_init_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) diff --git a/tests/omod-if-array.sh b/tests/omod-if-array.sh new file mode 100755 index 00000000..cac08928 --- /dev/null +++ b/tests/omod-if-array.sh @@ -0,0 +1 @@ +./udptester omod-if-array diff --git a/tests/parsertest.c b/tests/parsertest.c deleted file mode 100644 index 6c2221e8..00000000 --- a/tests/parsertest.c +++ /dev/null @@ -1,269 +0,0 @@ -/* Runs a test suite on the rsyslog parser (and later potentially - * other things). - * - * Please note that this - * program works together with the config file AND easily extensible - * test case files (*.parse1) to run a number of checks. All test - * cases are executed, even if there is a failure early in the - * process. When finished, the numberof failed tests will be given. - * - * Part of the testbench for rsyslog. - * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define EXIT_FAILURE 1 - - -void readLine(int fd, char *ln) -{ - char c; - int lenRead; - lenRead = read(fd, &c, 1); - while(lenRead == 1 && c != '\n') { - *ln++ = c; - lenRead = read(fd, &c, 1); - } - *ln = '\0'; -} - - -/* send a message via UDP - * returns 0 if ok, something else otherwise. - */ -int -udpSend(char *buf, int lenBuf) -{ - struct sockaddr_in si_other; - int s, slen=sizeof(si_other); - - if((s=socket(AF_INET, SOCK_DGRAM, 0))==-1) { - perror("socket()"); - return(1); - } - - memset((char *) &si_other, 0, sizeof(si_other)); - si_other.sin_family = AF_INET; - si_other.sin_port = htons(12514); - if(inet_aton("127.0.0.1", &si_other.sin_addr)==0) { - fprintf(stderr, "inet_aton() failed\n"); - return(1); - } - - if(sendto(s, buf, lenBuf, 0, (struct sockaddr*) &si_other, slen)==-1) { - perror("sendto"); - fprintf(stderr, "sendto() failed\n"); - return(1); - } - - close(s); - return 0; -} - -/* open pipe to test candidate - so far, this is - * always rsyslogd and with a fixed config. Later, we may - * change this. Returns 0 if ok, something else otherwise. - * rgerhards, 2009-03-31 - */ -int openPipe(pid_t *pid, int *pfd) -{ - int pipefd[2]; - pid_t cpid; - char *newargv[] = {"../tools/rsyslogd", "dummy", "-c4", "-u2", "-n", "-irsyslog.pid", - "-M../runtime//.libs", NULL }; - char confFile[1024]; - char *newenviron[] = { NULL }; - - - sprintf(confFile, "-f%s/testruns/parser.conf", getenv("srcdir")); - newargv[1] = confFile; - - if (pipe(pipefd) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - - cpid = fork(); - if (cpid == -1) { - perror("fork"); - exit(EXIT_FAILURE); - } - - if(cpid == 0) { /* Child reads from pipe */ - fclose(stdout); - dup(pipefd[1]); - close(pipefd[1]); - close(pipefd[0]); - fclose(stdin); - execve("../tools/rsyslogd", newargv, newenviron); - } else { - close(pipefd[1]); - *pid = cpid; - *pfd = pipefd[0]; - } - - return(0); -} - - -/* Process a specific test case. File name is provided. - * Needs to return 0 if all is OK, something else otherwise. - */ -int -processTestFile(int fd, char *pszFileName) -{ - FILE *fp; - char *testdata = NULL; - char *expected = NULL; - int ret = 0; - size_t lenLn; - char buf[4096]; - - if((fp = fopen((char*)pszFileName, "r")) == NULL) { - perror((char*)pszFileName); - return(2); - } - - /* skip comments at start of file */ - - getline(&testdata, &lenLn, fp); - while(!feof(fp)) { - if(*testdata == '#') - getline(&testdata, &lenLn, fp); - else - break; /* first non-comment */ - } - - - testdata[strlen(testdata)-1] = '\0'; /* remove \n */ - /* now we have the test data to send */ - if(udpSend(testdata, strlen(testdata)) != 0) - return(2); - - /* next line is expected output - * we do not care about EOF here, this will lead to a failure and thus - * draw enough attention. -- rgerhards, 2009-03-31 - */ - getline(&expected, &lenLn, fp); - expected[strlen(expected)-1] = '\0'; /* remove \n */ - - /* pull response from server and then check if it meets our expectation */ - readLine(fd, buf); - if(strcmp(expected, buf)) { - printf("\nExpected Response:\n'%s'\nActual Response:\n'%s'\n", - expected, buf); - ret = 1; - } - - free(testdata); - free(expected); - fclose(fp); - return(ret); -} - - -/* carry out all tests. Tests are specified via a file name - * wildcard. Each of the files is read and the test carried - * out. - * Returns the number of tests that failed. Zero means all - * success. - */ -int -doTests(int fd, char *files) -{ - int iFailed = 0; - int iTests = 0; - int ret; - char *testFile; - glob_t testFiles; - size_t i = 0; - struct stat fileInfo; - - glob(files, GLOB_MARK, NULL, &testFiles); - - for(i = 0; i < testFiles.gl_pathc; i++) { - testFile = testFiles.gl_pathv[i]; - - if(stat((char*) testFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ - - ++iTests; - /* all regular files are run through the test logic. Symlinks don't work. */ - if(S_ISREG(fileInfo.st_mode)) { /* config file */ - printf("processing test case '%s' ... ", testFile); - ret = processTestFile(fd, testFile); - if(ret == 0) { - printf("successfully completed\n"); - } else { - printf("failed!\n"); - ++iFailed; - } - } - } - globfree(&testFiles); - - if(iTests == 0) { - printf("Error: no test cases found, no tests executed.\n"); - iFailed = 1; - } else { - printf("Number of tests run: %d, number of failures: %d\n", iTests, iFailed); - } - - return(iFailed); -} - - -/* */ -int main(int argc, char *argv[]) -{ - int fd; - pid_t pid; - int ret = 0; - char buf[4096]; - char testcases[4096]; - - printf("running rsyslog parser tests ($srcdir=%s)\n", getenv("srcdir")); - - openPipe(&pid, &fd); - readLine(fd, buf); - - /* generate filename */ - sprintf(testcases, "%s/testruns/*.parse1", getenv("srcdir")); - if(doTests(fd, testcases) != 0) - ret = 1; - - /* cleanup */ - kill(pid, SIGTERM); - printf("End of parser tests.\n"); - exit(ret); -} diff --git a/tests/parsertest.sh b/tests/parsertest.sh new file mode 100755 index 00000000..e7985bb0 --- /dev/null +++ b/tests/parsertest.sh @@ -0,0 +1 @@ +./udptester parse1 diff --git a/tests/testruns/1.parse1 b/tests/testruns/1.parse1 deleted file mode 100644 index 5ae655e6..00000000 --- a/tests/testruns/1.parse1 +++ /dev/null @@ -1,3 +0,0 @@ -<167>Mar 6 16:57:54 172.20.245.8 %PIX-7-710005: UDP request discarded from SERVER1/2741 to test_app:255.255.255.255/61601 -167,local4,debug,Mar 6 16:57:54,172.20.245.8,%PIX-7-710005,%PIX-7-710005:, UDP request discarded from SERVER1/2741 to test_app:255.255.255.255/61601 -#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testruns/parser.conf b/tests/testruns/parser.conf deleted file mode 100644 index 0fb7d16d..00000000 --- a/tests/testruns/parser.conf +++ /dev/null @@ -1,9 +0,0 @@ -$ModLoad ../plugins/omstdout/.libs/omstdout -$ModLoad ../plugins/imudp/.libs/imudp -$UDPServerRun 12514 - -$ErrorMessagesToStderr off - -# use a special format that we can easily parse in expect -$template expect,"%PRI%,%syslogfacility-text%,%syslogseverity-text%,%timestamp%,%hostname%,%programname%,%syslogtag%,%msg%\n" -*.* :omstdout:;expect diff --git a/tests/testruns/rfc3164.parse1 b/tests/testruns/rfc3164.parse1 deleted file mode 100644 index e7a5fa18..00000000 --- a/tests/testruns/rfc3164.parse1 +++ /dev/null @@ -1,4 +0,0 @@ -<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8 -34,auth,crit,Oct 11 22:14:15,mymachine,su,su:, 'su root' failed for lonvick on /dev/pts/8 -#Example from RFC3164, section 5.4 -#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testruns/rfc5424-1.parse1 b/tests/testruns/rfc5424-1.parse1 deleted file mode 100644 index 23836c9f..00000000 --- a/tests/testruns/rfc5424-1.parse1 +++ /dev/null @@ -1,3 +0,0 @@ -#Example from RFC5424, section 6.5 / sample 1 -<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8 -34,auth,crit,Oct 11 22:14:15,mymachine.example.com,,su,- BOM'su root' failed for lonvick on /dev/pts/8 diff --git a/tests/testruns/rfc5424-2.parse1 b/tests/testruns/rfc5424-2.parse1 deleted file mode 100644 index a86fbc35..00000000 --- a/tests/testruns/rfc5424-2.parse1 +++ /dev/null @@ -1,4 +0,0 @@ -<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts. -165,local4,notice,Aug 24 05:14:15,192.0.2.1,,myproc[8710],- %% It's time to make the do-nuts. -#Example from RFC5424, section 6.5 / sample 2 -#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testruns/rfc5424-3.parse1 b/tests/testruns/rfc5424-3.parse1 deleted file mode 100644 index 6ad4073d..00000000 --- a/tests/testruns/rfc5424-3.parse1 +++ /dev/null @@ -1,4 +0,0 @@ -<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"] -165,local4,notice,Oct 11 22:14:15,mymachine.example.com,,evntslog, -#Example from RFC5424, section 6.5 / sample 4 -#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testruns/rfc5424-4.parse1 b/tests/testruns/rfc5424-4.parse1 deleted file mode 100644 index ecf27e14..00000000 --- a/tests/testruns/rfc5424-4.parse1 +++ /dev/null @@ -1,4 +0,0 @@ -<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"] BOMAn application event log entry... -165,local4,notice,Oct 11 22:14:15,mymachine.example.com,,evntslog,BOMAn application event log entry... -#Example from RFC5424, section 6.5 / sample 3 -#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testsuites/1.omod-if-array b/tests/testsuites/1.omod-if-array new file mode 100644 index 00000000..c464b19c --- /dev/null +++ b/tests/testsuites/1.omod-if-array @@ -0,0 +1,2 @@ +<167>Mar 6 16:57:54 172.20.245.8 %PIX-7-710005: UDP request discarded from SERVER1/2741 to test_app:255.255.255.255/61601 +167,Mar 6 16:57:54,172.20.245.8,%PIX-7-710005,%PIX-7-710005:, diff --git a/tests/testsuites/1.parse1 b/tests/testsuites/1.parse1 new file mode 100644 index 00000000..5ae655e6 --- /dev/null +++ b/tests/testsuites/1.parse1 @@ -0,0 +1,3 @@ +<167>Mar 6 16:57:54 172.20.245.8 %PIX-7-710005: UDP request discarded from SERVER1/2741 to test_app:255.255.255.255/61601 +167,local4,debug,Mar 6 16:57:54,172.20.245.8,%PIX-7-710005,%PIX-7-710005:, UDP request discarded from SERVER1/2741 to test_app:255.255.255.255/61601 +#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testsuites/omod-if-array.conf b/tests/testsuites/omod-if-array.conf new file mode 100644 index 00000000..e6c05a52 --- /dev/null +++ b/tests/testsuites/omod-if-array.conf @@ -0,0 +1,14 @@ +# Test config for array-passing output module interface +# (stanard string passing is already tested via the other test inside +# the testbench, so we do not need to focus on that) +# rgerhards, 2009-04-03 +$ModLoad ../plugins/omstdout/.libs/omstdout +$ModLoad ../plugins/imudp/.libs/imudp +$UDPServerRun 12514 + +$ActionOMStdoutArrayInterface on +$ErrorMessagesToStderr off + +# do NOT remove \n, that would hang the test driver! +$template expect,"%PRI%%timestamp%%hostname%%programname%%syslogtag%\n" +*.* :omstdout:;expect diff --git a/tests/testsuites/parse1.conf b/tests/testsuites/parse1.conf new file mode 100644 index 00000000..0fb7d16d --- /dev/null +++ b/tests/testsuites/parse1.conf @@ -0,0 +1,9 @@ +$ModLoad ../plugins/omstdout/.libs/omstdout +$ModLoad ../plugins/imudp/.libs/imudp +$UDPServerRun 12514 + +$ErrorMessagesToStderr off + +# use a special format that we can easily parse in expect +$template expect,"%PRI%,%syslogfacility-text%,%syslogseverity-text%,%timestamp%,%hostname%,%programname%,%syslogtag%,%msg%\n" +*.* :omstdout:;expect diff --git a/tests/testsuites/rfc3164.parse1 b/tests/testsuites/rfc3164.parse1 new file mode 100644 index 00000000..e7a5fa18 --- /dev/null +++ b/tests/testsuites/rfc3164.parse1 @@ -0,0 +1,4 @@ +<34>Oct 11 22:14:15 mymachine su: 'su root' failed for lonvick on /dev/pts/8 +34,auth,crit,Oct 11 22:14:15,mymachine,su,su:, 'su root' failed for lonvick on /dev/pts/8 +#Example from RFC3164, section 5.4 +#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testsuites/rfc5424-1.parse1 b/tests/testsuites/rfc5424-1.parse1 new file mode 100644 index 00000000..23836c9f --- /dev/null +++ b/tests/testsuites/rfc5424-1.parse1 @@ -0,0 +1,3 @@ +#Example from RFC5424, section 6.5 / sample 1 +<34>1 2003-10-11T22:14:15.003Z mymachine.example.com su - ID47 - BOM'su root' failed for lonvick on /dev/pts/8 +34,auth,crit,Oct 11 22:14:15,mymachine.example.com,,su,- BOM'su root' failed for lonvick on /dev/pts/8 diff --git a/tests/testsuites/rfc5424-2.parse1 b/tests/testsuites/rfc5424-2.parse1 new file mode 100644 index 00000000..a86fbc35 --- /dev/null +++ b/tests/testsuites/rfc5424-2.parse1 @@ -0,0 +1,4 @@ +<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts. +165,local4,notice,Aug 24 05:14:15,192.0.2.1,,myproc[8710],- %% It's time to make the do-nuts. +#Example from RFC5424, section 6.5 / sample 2 +#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testsuites/rfc5424-3.parse1 b/tests/testsuites/rfc5424-3.parse1 new file mode 100644 index 00000000..6ad4073d --- /dev/null +++ b/tests/testsuites/rfc5424-3.parse1 @@ -0,0 +1,4 @@ +<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"][examplePriority@32473 class="high"] +165,local4,notice,Oct 11 22:14:15,mymachine.example.com,,evntslog, +#Example from RFC5424, section 6.5 / sample 4 +#Only the first two lines are important, you may place anything behind them! diff --git a/tests/testsuites/rfc5424-4.parse1 b/tests/testsuites/rfc5424-4.parse1 new file mode 100644 index 00000000..ecf27e14 --- /dev/null +++ b/tests/testsuites/rfc5424-4.parse1 @@ -0,0 +1,4 @@ +<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource= "Application" eventID="1011"] BOMAn application event log entry... +165,local4,notice,Oct 11 22:14:15,mymachine.example.com,,evntslog,BOMAn application event log entry... +#Example from RFC5424, section 6.5 / sample 3 +#Only the first two lines are important, you may place anything behind them! diff --git a/tests/udptester.c b/tests/udptester.c new file mode 100644 index 00000000..ea642db6 --- /dev/null +++ b/tests/udptester.c @@ -0,0 +1,291 @@ +/* Runs a test suite on the rsyslog (and later potentially + * other things). + * + * The name of the test suite must be given as argv[1]. In this config, + * rsyslogd is loaded with config ./testsuites/.conf and then + * test cases ./testsuites/ *. are executed on it. This test driver is + * suitable for testing cases where a message sent (via UDP) results in + * exactly one response. It can not be used in cases where no response + * is expected (that would result in a hang of the test driver). + * Note: each test suite can contain many tests, but they all need to work + * with the same rsyslog configuration. + * + * Part of the testbench for rsyslog. + * + * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EXIT_FAILURE 1 + +static char *srcdir; /* global $srcdir, set so that we can run outside of "make check" */ +static char *testSuite; /* name of current test suite */ + + +void readLine(int fd, char *ln) +{ + char c; + int lenRead; + lenRead = read(fd, &c, 1); + while(lenRead == 1 && c != '\n') { + *ln++ = c; + lenRead = read(fd, &c, 1); + } + *ln = '\0'; +} + + +/* send a message via UDP + * returns 0 if ok, something else otherwise. + */ +int +udpSend(char *buf, int lenBuf) +{ + struct sockaddr_in si_other; + int s, slen=sizeof(si_other); + + if((s=socket(AF_INET, SOCK_DGRAM, 0))==-1) { + perror("socket()"); + return(1); + } + + memset((char *) &si_other, 0, sizeof(si_other)); + si_other.sin_family = AF_INET; + si_other.sin_port = htons(12514); + if(inet_aton("127.0.0.1", &si_other.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + return(1); + } + + if(sendto(s, buf, lenBuf, 0, (struct sockaddr*) &si_other, slen)==-1) { + perror("sendto"); + fprintf(stderr, "sendto() failed\n"); + return(1); + } + + close(s); + return 0; +} + + +/* open pipe to test candidate - so far, this is + * always rsyslogd and with a fixed config. Later, we may + * change this. Returns 0 if ok, something else otherwise. + * rgerhards, 2009-03-31 + */ +int openPipe(char *configFile, pid_t *pid, int *pfd) +{ + int pipefd[2]; + pid_t cpid; + char *newargv[] = {"../tools/rsyslogd", "dummy", "-c4", "-u2", "-n", "-irsyslog.pid", + "-M../runtime//.libs", NULL }; + char confFile[1024]; + char *newenviron[] = { NULL }; + + + sprintf(confFile, "-f%s/testsuites/%s.conf", srcdir, configFile); + newargv[1] = confFile; + + if (pipe(pipefd) == -1) { + perror("pipe"); + exit(EXIT_FAILURE); + } + + cpid = fork(); + if (cpid == -1) { + perror("fork"); + exit(EXIT_FAILURE); + } + + if(cpid == 0) { /* Child reads from pipe */ + fclose(stdout); + dup(pipefd[1]); + close(pipefd[1]); + close(pipefd[0]); + fclose(stdin); + execve("../tools/rsyslogd", newargv, newenviron); + } else { + close(pipefd[1]); + *pid = cpid; + *pfd = pipefd[0]; + } + + return(0); +} + + +/* Process a specific test case. File name is provided. + * Needs to return 0 if all is OK, something else otherwise. + */ +int +processTestFile(int fd, char *pszFileName) +{ + FILE *fp; + char *testdata = NULL; + char *expected = NULL; + int ret = 0; + size_t lenLn; + char buf[4096]; + + if((fp = fopen((char*)pszFileName, "r")) == NULL) { + perror((char*)pszFileName); + return(2); + } + + /* skip comments at start of file */ + + getline(&testdata, &lenLn, fp); + while(!feof(fp)) { + if(*testdata == '#') + getline(&testdata, &lenLn, fp); + else + break; /* first non-comment */ + } + + + testdata[strlen(testdata)-1] = '\0'; /* remove \n */ + /* now we have the test data to send */ + if(udpSend(testdata, strlen(testdata)) != 0) + return(2); + + /* next line is expected output + * we do not care about EOF here, this will lead to a failure and thus + * draw enough attention. -- rgerhards, 2009-03-31 + */ + getline(&expected, &lenLn, fp); + expected[strlen(expected)-1] = '\0'; /* remove \n */ + + /* pull response from server and then check if it meets our expectation */ + readLine(fd, buf); + if(strcmp(expected, buf)) { + printf("\nExpected Response:\n'%s'\nActual Response:\n'%s'\n", + expected, buf); + ret = 1; + } + + free(testdata); + free(expected); + fclose(fp); + return(ret); +} + + +/* carry out all tests. Tests are specified via a file name + * wildcard. Each of the files is read and the test carried + * out. + * Returns the number of tests that failed. Zero means all + * success. + */ +int +doTests(int fd, char *files) +{ + int iFailed = 0; + int iTests = 0; + int ret; + char *testFile; + glob_t testFiles; + size_t i = 0; + struct stat fileInfo; + + glob(files, GLOB_MARK, NULL, &testFiles); + + for(i = 0; i < testFiles.gl_pathc; i++) { + testFile = testFiles.gl_pathv[i]; + + if(stat((char*) testFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + ++iTests; + /* all regular files are run through the test logic. Symlinks don't work. */ + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + printf("processing test case '%s' ... ", testFile); + ret = processTestFile(fd, testFile); + if(ret == 0) { + printf("successfully completed\n"); + } else { + printf("failed!\n"); + ++iFailed; + } + } + } + globfree(&testFiles); + + if(iTests == 0) { + printf("Error: no test cases found, no tests executed.\n"); + iFailed = 1; + } else { + printf("Number of tests run: %d, number of failures: %d\n", iTests, iFailed); + } + + return(iFailed); +} + + +/* Run the test suite. This must be called with exactly one parameter, the + * name of the test suite. For details, see file header comment at the top + * of this file. + * rgerhards, 2009-04-03 + */ +int main(int argc, char *argv[]) +{ + int fd; + pid_t pid; + int ret = 0; + char buf[4096]; + char testcases[4096]; + + if(argc != 2) { + printf("Invalid call of udptester\n"); + printf("Usage: udptester testsuite-name\n"); + exit(1); + } + + testSuite = argv[1]; + + if((srcdir = getenv("srcdir")) == NULL) + srcdir = "."; + + printf("Start of udptester run ($srcdir=%s, testsuite=%s)\n", srcdir, testSuite); + + openPipe(argv[1], &pid, &fd); + readLine(fd, buf); + + /* generate filename */ + sprintf(testcases, "%s/testsuites/*.%s", srcdir, testSuite); + if(doTests(fd, testcases) != 0) + ret = 1; + + /* cleanup */ + kill(pid, SIGTERM); + printf("End of udptester run.\n"); + exit(ret); +} -- cgit