suricata
util-unittest.c
Go to the documentation of this file.
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"
44
45#ifdef UNITTESTS
46
47static pcre2_code *parse_regex;
48static pcre2_match_data *parse_regex_match;
49
50static UtTest *ut_list;
51
53
54/**
55 * \brief Allocate UtTest list member
56 *
57 * \retval ut Pointer to UtTest
58 */
59
60static 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
80static 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
103void 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 */
125static int UtRegex (const char *regex_arg)
126{
127 int en;
128 PCRE2_SIZE eo;
129 int opts = PCRE2_CASELESS;
130
131 if(regex_arg == NULL)
132 return -1;
133
134 parse_regex =
135 pcre2_compile((PCRE2_SPTR8)regex_arg, PCRE2_ZERO_TERMINATED, opts, &en, &eo, NULL);
136 if(parse_regex == NULL)
137 {
138 PCRE2_UCHAR errbuffer[256];
139 pcre2_get_error_message(en, errbuffer, sizeof(errbuffer));
140 SCLogError("pcre2 compile of \"%s\" failed at "
141 "offset %d: %s",
142 regex_arg, (int)eo, errbuffer);
143 goto error;
144 }
145 parse_regex_match = pcre2_match_data_create_from_pattern(parse_regex, NULL);
146
147 return 1;
148
149error:
150 return -1;
151}
152
153/** \brief List all registered unit tests.
154 *
155 * \param regex_arg Regular expression to limit listed tests.
156 */
157void UtListTests(const char *regex_arg)
158{
159 UtTest *ut;
160 int ret = 0, rcomp = 0;
161
162 rcomp = UtRegex(regex_arg);
163
164 for (ut = ut_list; ut != NULL; ut = ut->next) {
165 if (rcomp == 1) {
166 ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0,
167 parse_regex_match, NULL);
168 if (ret >= 1) {
169 printf("%s\n", ut->name);
170 }
171 }
172 else {
173 printf("%s\n", ut->name);
174 }
175 }
176 pcre2_code_free(parse_regex);
177 pcre2_match_data_free(parse_regex_match);
178}
179
180/** \brief Run all registered unittests.
181 *
182 * \param regex_arg The regular expression
183 *
184 * \retval 0 all successful
185 * \retval result number of tests that failed
186 */
187
188uint32_t UtRunTests(const char *regex_arg)
189{
190 UtTest *ut;
191 uint32_t good = 0, bad = 0, matchcnt = 0;
192 int ret = 0, rcomp = 0;
193
196
197 rcomp = UtRegex(regex_arg);
198
199 if(rcomp == 1){
200 for (ut = ut_list; ut != NULL; ut = ut->next) {
201 ret = pcre2_match(parse_regex, (PCRE2_SPTR8)ut->name, strlen(ut->name), 0, 0,
202 parse_regex_match, NULL);
203 if( ret >= 1 ) {
204 printf("Test %-60.60s : ", ut->name);
205 matchcnt++;
206 fflush(stdout); /* flush so in case of a segv we see the testname */
207
208 /* reset the time */
211
212 ret = ut->TestFn();
213
214 if (StreamTcpMemuseCounter() != 0) {
215 printf("STREAM MEMORY IN USE %"PRIu64"\n", StreamTcpMemuseCounter());
216 ret = 0;
217 }
218 if (FlowGetMemuse() != 0) {
219 printf("FLOW MEMORY IN USE %"PRIu64"\n", FlowGetMemuse());
220 ret = 0;
221 }
222
224 printf("STREAM REASSEMBLY MEMORY IN USE %"PRIu64"\n", StreamTcpReassembleMemuseGlobalCounter());
225 ret = 0;
226 }
227
228 printf("%s\n", ret ? "pass" : "FAILED");
229
230 if (!ret) {
231 if (unittests_fatal == 1) {
232 fprintf(stderr, "ERROR: unittest failed.\n");
233 exit(EXIT_FAILURE);
234 }
235 bad++;
236 } else {
237 good++;
238 }
239 }
240 }
241 if(matchcnt > 0){
242 printf("==== TEST RESULTS ====\n");
243 printf("PASSED: %" PRIu32 "\n", good);
244 printf("FAILED: %" PRIu32 "\n", bad);
245 printf("======================\n");
246 } else {
247 SCLogInfo("UtRunTests: regex provided regex_arg: %s did not match any tests",regex_arg);
248 }
249 } else {
250 SCLogInfo("UtRunTests: pcre compilation failed");
251 }
252 pcre2_code_free(parse_regex);
253 pcre2_match_data_free(parse_regex_match);
254 return bad;
255}
256/**
257 * \brief Initialize unit test list
258 */
259
260void UtInitialize(void)
261{
262 ut_list = NULL;
263}
264
265/**
266 * \brief Cleanup unit test list
267 */
268
269void 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
284{
285 RunModeRegisterNewRunMode(RUNMODE_UNITTEST, "unittest", "Unittest mode", NULL, NULL);
286}
287
288/*
289 * unittests for the unittests code
290 */
291
292/** \brief True test
293 *
294 * \retval 1 True
295 * \retval 0 False
296 */
297static int UtSelftestTrue(void)
298{
299 if (1)return 1;
300 else return 0;
301}
302
303/** \brief False test
304 *
305 * \retval 1 False
306 * \retval 0 True
307 */
308static int UtSelftestFalse(void)
309{
310 if (0)return 0;
311 else return 1;
312}
313
314/** \brief Run self tests
315 *
316 * \param regex_arg The regular expression
317 *
318 * \retval 0 all successful
319 */
320
321int UtRunSelftest (const char *regex_arg)
322{
323 printf("* Running Unittesting subsystem selftests...\n");
324
325 UtInitialize();
326
327 UtRegisterTest("true", UtSelftestTrue);
328 UtRegisterTest("false", UtSelftestFalse);
329
330 int ret = UtRunTests(regex_arg);
331 if (ret == 0)
332 printf("* Done running Unittesting subsystem selftests...\n");
333 else
334 printf("* ERROR running Unittesting subsystem selftests failed...\n");
335
336 UtCleanup();
337 return 0;
338}
339#endif /* UNITTESTS */
340
341/**
342 * @}
343 */
uint64_t FlowGetMemuse(void)
Definition flow.c:128
int UtRunSelftest(const char *regex_arg)
Run self tests.
int unittests_fatal
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
void UtCleanup(void)
Cleanup unit test list.
void UtRunModeRegister(void)
void UtInitialize(void)
Initialize unit test list.
uint32_t UtRunTests(const char *regex_arg)
Run all registered unittests.
void UtListTests(const char *regex_arg)
List all registered unit tests.
const char * regex_arg
void RunModeRegisterNewRunMode(enum SCRunModes runmode, const char *name, const char *description, int(*RunModeFunc)(void), int(*RunModeIsIPSEnabled)(void))
Registers a new runmode.
Definition runmodes.c:486
@ RUNMODE_UNITTEST
Definition runmodes.h:41
uint64_t StreamTcpReassembleMemuseGlobalCounter(void)
void StreamTcpReassembleInitMemuse(void)
void StreamTcpInitMemuse(void)
Definition stream-tcp.c:223
uint64_t StreamTcpMemuseCounter(void)
Definition stream-tcp.c:254
const char * name
struct UtTest_ * next
int(* TestFn)(void)
const char * name
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define unlikely(expr)
void TimeSetToCurrentTime(void)
set the time to "gettimeofday" meant for testing
Definition util-time.c:140
void TimeModeSetOffline(void)
Definition util-time.c:105