1 /* Copyright (C) 2007-2010 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  * \author Breno Silva <breno.silva@gmail.com>
23  *
24  * Unit test framework
25  */
26 
27 /**
28  * \defgroup Testing Testing
29  *
30  * \brief Unit testing support functions.
31  *
32  * @{
33  */
34 
35 #include "suricata-common.h"
36 #include "runmodes.h"
37 #include "util-unittest.h"
38 #include "util-debug.h"
39 #include "util-time.h"
40 #include "conf.h"
41 
42 #include "stream-tcp.h"
43 #include "stream-tcp-reassemble.h"
44 
45 #ifdef UNITTESTS
46 
47 static pcre *parse_regex;
48 static pcre_extra *parse_regex_study;
49 
50 static UtTest *ut_list;
51 
52 int unittests_fatal = 0;
53 
54 /**
55  * \brief Allocate UtTest list member
56  *
57  * \retval ut Pointer to UtTest
58  */
59 
UtAllocTest(void)60 static UtTest *UtAllocTest(void)
61 {
62     UtTest *ut = SCMalloc(sizeof(UtTest));
63     if (unlikely(ut == NULL))
64         return NULL;
65 
66     memset(ut, 0, sizeof(UtTest));
67 
68     return ut;
69 }
70 
71 /**
72  * \brief Append test in UtTest list
73  *
74  * \param list Pointer to the start of the IP packet
75  * \param test Pointer to unit test
76  *
77  * \retval 0 Function always returns zero
78  */
79 
UtAppendTest(UtTest ** list,UtTest * test)80 static int UtAppendTest(UtTest **list, UtTest *test)
81 {
82     if (*list == NULL) {
83         *list = test;
84     } else {
85         UtTest *tmp = *list;
86 
87         while (tmp->next != NULL) {
88             tmp = tmp->next;
89         }
90         tmp->next = test;
91     }
92 
93     return 0;
94 }
95 
96 /**
97  * \brief Register unit test
98  *
99  * \param name Unit test name
100  * \param TestFn Unit test function
101  */
102 
UtRegisterTest(const char * name,int (* TestFn)(void))103 void UtRegisterTest(const char *name, int(*TestFn)(void))
104 {
105     UtTest *ut = UtAllocTest();
106     if (ut == NULL)
107         return;
108 
109     ut->name = name;
110     ut->TestFn = TestFn;
111     ut->next = NULL;
112 
113     /* append */
114     UtAppendTest(&ut_list, ut);
115 }
116 
117 /**
118  * \brief Compile a regex to run a specific unit test
119  *
120  * \param regex_arg The regular expression
121  *
122  * \retval 1  Regex compiled
123  * \retval -1 Regex error
124  */
UtRegex(const char * regex_arg)125 static int UtRegex (const char *regex_arg)
126 {
127     const char *eb;
128     int eo;
129     int opts = PCRE_CASELESS;;
130 
131     if(regex_arg == NULL)
132         return -1;
133 
134     parse_regex = pcre_compile(regex_arg, opts, &eb, &eo, NULL);
135     if(parse_regex == NULL)
136     {
137         printf("pcre compile of \"%s\" failed at offset %" PRId32 ": %s\n", regex_arg, eo, eb);
138         goto error;
139     }
140 
141     parse_regex_study = pcre_study(parse_regex, 0, &eb);
142     if(eb != NULL)
143     {
144         printf("pcre study failed: %s\n", eb);
145         goto error;
146     }
147 
148     return 1;
149 
150 error:
151     return -1;
152 }
153 
154 #define MAX_SUBSTRINGS 30
155 
156 /** \brief List all registered unit tests.
157  *
158  *  \param regex_arg Regular expression to limit listed tests.
159  */
UtListTests(const char * regex_arg)160 void UtListTests(const char *regex_arg)
161 {
162     UtTest *ut;
163     int ret = 0, rcomp = 0;
164     int ov[MAX_SUBSTRINGS];
165 
166     rcomp = UtRegex(regex_arg);
167 
168     for (ut = ut_list; ut != NULL; ut = ut->next) {
169         if (rcomp == 1)  {
170             ret = pcre_exec(parse_regex, parse_regex_study, ut->name,
171                 strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS);
172             if (ret >= 1) {
173                 printf("%s\n", ut->name);
174             }
175         }
176         else {
177             printf("%s\n", ut->name);
178         }
179     }
180 }
181 
182 /** \brief Run all registered unittests.
183  *
184  *  \param regex_arg The regular expression
185  *
186  *  \retval 0 all successful
187  *  \retval result number of tests that failed
188  */
189 
UtRunTests(const char * regex_arg)190 uint32_t UtRunTests(const char *regex_arg)
191 {
192     UtTest *ut;
193     uint32_t good = 0, bad = 0, matchcnt = 0;
194     int ret = 0, rcomp = 0;
195     int ov[MAX_SUBSTRINGS];
196 
197     StreamTcpInitMemuse();
198     StreamTcpReassembleInitMemuse();
199 
200     rcomp = UtRegex(regex_arg);
201 
202     if(rcomp == 1){
203         for (ut = ut_list; ut != NULL; ut = ut->next) {
204             ret = pcre_exec(parse_regex, parse_regex_study, ut->name, strlen(ut->name), 0, 0, ov, MAX_SUBSTRINGS);
205             if( ret >= 1 )  {
206                 printf("Test %-60.60s : ", ut->name);
207                 matchcnt++;
208                 fflush(stdout); /* flush so in case of a segv we see the testname */
209 
210                 /* reset the time */
211                 TimeModeSetOffline();
212                 TimeSetToCurrentTime();
213 
214                 ret = ut->TestFn();
215 
216                 if (StreamTcpMemuseCounter() != 0) {
217                     printf("STREAM MEMORY IN USE %"PRIu64"\n", StreamTcpMemuseCounter());
218                     ret = 0;
219                 }
220                 if (FlowGetMemuse() != 0) {
221                     printf("FLOW MEMORY IN USE %"PRIu64"\n", FlowGetMemuse());
222                     ret = 0;
223                 }
224 
225                 if (StreamTcpReassembleMemuseGlobalCounter() != 0) {
226                     printf("STREAM REASSEMBLY MEMORY IN USE %"PRIu64"\n", StreamTcpReassembleMemuseGlobalCounter());
227                     ret = 0;
228                 }
229 
230                 printf("%s\n", ret ? "pass" : "FAILED");
231 
232                 if (!ret) {
233                     if (unittests_fatal == 1) {
234                         fprintf(stderr, "ERROR: unittest failed.\n");
235                         exit(EXIT_FAILURE);
236                     }
237                     bad++;
238                 } else {
239                     good++;
240                 }
241             }
242         }
243         if(matchcnt > 0){
244             printf("==== TEST RESULTS ====\n");
245             printf("PASSED: %" PRIu32 "\n", good);
246             printf("FAILED: %" PRIu32 "\n", bad);
247             printf("======================\n");
248         } else {
249             SCLogInfo("UtRunTests: regex provided regex_arg: %s did not match any tests",regex_arg);
250         }
251     } else {
252         SCLogInfo("UtRunTests: pcre compilation failed");
253     }
254     return bad;
255 }
256 /**
257  * \brief Initialize unit test list
258  */
259 
UtInitialize(void)260 void UtInitialize(void)
261 {
262     ut_list = NULL;
263 }
264 
265 /**
266  * \brief Cleanup unit test list
267  */
268 
UtCleanup(void)269 void UtCleanup(void)
270 {
271 
272     UtTest *tmp = ut_list, *otmp;
273 
274     while (tmp != NULL) {
275         otmp = tmp->next;
276         SCFree(tmp);
277         tmp = otmp;
278     }
279 
280     ut_list = NULL;
281 }
282 
UtRunModeRegister(void)283 void UtRunModeRegister(void)
284 {
285     RunModeRegisterNewRunMode(RUNMODE_UNITTEST,
286                               "unittest",
287                               "Unittest mode",
288                               NULL);
289 
290     return;
291 }
292 
293 /*
294  * unittests for the unittests code
295  */
296 
297 /** \brief True test
298  *
299  *  \retval 1 True
300  *  \retval 0 False
301  */
UtSelftestTrue(void)302 static int UtSelftestTrue(void)
303 {
304     if (1)return 1;
305     else  return 0;
306 }
307 
308 /** \brief False test
309  *
310  *  \retval 1 False
311  *  \retval 0 True
312  */
UtSelftestFalse(void)313 static int UtSelftestFalse(void)
314 {
315     if (0)return 0;
316     else  return 1;
317 }
318 
319 /** \brief Run self tests
320  *
321  *  \param regex_arg The regular expression
322  *
323  *  \retval 0 all successful
324  */
325 
UtRunSelftest(const char * regex_arg)326 int UtRunSelftest (const char *regex_arg)
327 {
328     printf("* Running Unittesting subsystem selftests...\n");
329 
330     UtInitialize();
331 
332     UtRegisterTest("true", UtSelftestTrue);
333     UtRegisterTest("false", UtSelftestFalse);
334 
335     int ret = UtRunTests(regex_arg);
336     if (ret == 0)
337         printf("* Done running Unittesting subsystem selftests...\n");
338     else
339         printf("* ERROR running Unittesting subsystem selftests failed...\n");
340 
341     UtCleanup();
342     return 0;
343 }
344 #endif /* UNITTESTS */
345 
346 /**
347  * @}
348  */
349