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