1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Support routines for Unit Tests.
21  */
22 
23 /*
24  * This is an example how to use unittests in your code:
25 
26 int main()
27 {
28    int rc;
29 
30    prolog("app_test");
31 
32    ( ... your test application goes here ...)
33 
34    rc = report();
35    epilog();
36    return rc;
37 }
38 
39  * and a C++ approach for any C++ geeks:
40 
41 int main()
42 {
43    Unittests tests("app_test");
44 
45    ( ... your test application goes here ...)
46 
47    return report();
48 }
49 
50  */
51 
52 #include <stdio.h>
53 #include "bacula.h"
54 #include "unittests.h"
55 
56 static int err=0;
57 static int nb=0;
58 static bool lmgrinit = false;
59 static bool quiet = false;
60 static bool print_var = false;
61 
Unittests(const char * name,bool lmgr,bool motd)62 Unittests::Unittests(const char *name, bool lmgr/*=false*/, bool motd/*=true*/)
63 {
64    if (getenv("UNITTEST_PRINT_VAR")) {
65       print_var = true;
66    }
67    prolog(name, lmgr, motd);
68 };
69 
configure_test(uint64_t options)70 void configure_test(uint64_t options)
71 {
72    if (options & TEST_QUIET) {
73       quiet = true;
74    }
75    if (options & TEST_PRINT_LOCAL) {
76       print_var = true;
77    }
78 }
79 
80 /* Get the total number of tests */
unittest_get_nb_tests()81 int unittest_get_nb_tests()
82 {
83    return nb;
84 }
85 
86 /* Get the total number of tests in error */
unittest_get_nb_errors()87 int unittest_get_nb_errors()
88 {
89    return err;
90 }
91 
92 /*
93  * Test success if value is not zero.
94  */
_ok(const char * file,int l,const char * op,int value,const char * label)95 bool _ok(const char *file, int l, const char *op, int value, const char *label)
96 {
97    nb++;
98    if (!value) {
99       err++;
100       if (err < 1000) {
101          Pmsg4(-1, "ERR %.80s %s:%i on %s\n", label, file, l, op);
102       } else if (err == 1000) {
103          Pmsg0(-1, "ERR Too much errors\n");
104       }
105       if (print_var) {
106          gdb_print_local(1);
107       }
108    } else if (!quiet) {
109       Pmsg1(-1, "OK  %.80s\n", label);
110    }
111    return value;
112 }
113 
114 /*
115  * Test success if value is zero.
116  */
_nok(const char * file,int l,const char * op,int value,const char * label)117 bool _nok(const char *file, int l, const char *op, int value, const char *label)
118 {
119    nb++;
120    if (value) {
121       err++;
122       if (err < 1000) {
123          Pmsg4(-1, "ERR %.80s %s:%i on !%s\n", label, file, l, op);
124       } else if (err == 1000) {
125          Pmsg0(-1, "ERR Too much errors\n");
126       }
127       if (print_var) {
128          gdb_print_local(1);
129       }
130    } else if (!quiet) {
131       Pmsg1(-1, "OK  %.80s\n", label);
132    }
133    return !value;
134 }
135 
136 /*
137  * Test success if value is different
138  */
_is(const char * file,int l,const char * op,const char * str,const char * str2,const char * label)139 bool _is(const char *file, int l, const char *op, const char *str, const char *str2, const char *label)
140 {
141    nb++;
142    bool value = (strcmp(str, str2) == 0);
143    if (!value) {
144       err++;
145       if (err < 1000) {
146          Pmsg6(-1, "ERR %.80s %s:%i on %s %s == %s\n", label, file, l, op, str, str2);
147       } else if (err == 1000) {
148          Pmsg0(-1, "ERR Too much errors\n");
149       }
150       if (print_var) {
151          gdb_print_local(1);
152       }
153    } else if (!quiet) {
154       Pmsg1(-1, "OK  %.80s\n", label);
155    }
156    return value;
157 }
158 
159 /*
160  * Test success if value is different
161  */
_is(const char * file,int l,const char * op,int64_t v,int64_t v2,const char * label)162 bool _is(const char *file, int l, const char *op, int64_t v, int64_t v2, const char *label)
163 {
164    nb++;
165    bool value = (v == v2);
166    if (!value) {
167       err++;
168       if (err < 1000) {
169          Pmsg6(-1, "ERR %.80s %s:%i on %s %lld == %lld\n", label, file, l, op, v, v2);
170       } else if (err == 1000) {
171          Pmsg0(-1, "ERR Too much errors\n");
172       }
173       if (print_var) {
174          gdb_print_local(1);
175       }
176    } else if (!quiet) {
177       Pmsg1(-1, "OK  %.80s\n", label);
178    }
179    return value;
180 }
181 
182 /*
183  * Test success if value is different
184  */
_isnt(const char * file,int l,const char * op,const char * str,const char * str2,const char * label)185 bool _isnt(const char *file, int l, const char *op, const char *str, const char *str2, const char *label)
186 {
187    nb++;
188    bool value = (strcmp(str, str2) != 0);
189    if (!value) {
190       err++;
191       if (err < 1000) {
192          Pmsg6(-1, "ERR %.80s %s:%i on %s %s == %s\n", label, file, l, op, str, str2);
193       } else if (err == 1000) {
194          Pmsg0(-1, "ERR Too much errors\n");
195       }
196       if (print_var) {
197          gdb_print_local(1);
198       }
199    } else if (!quiet) {
200       Pmsg1(-1, "OK  %.80s\n", label);
201    }
202    return value;
203 }
204 
205 /*
206  * Test success if value is different
207  */
_isnt(const char * file,int l,const char * op,int64_t v,int64_t v2,const char * label)208 bool _isnt(const char *file, int l, const char *op, int64_t v, int64_t v2, const char *label)
209 {
210    nb++;
211    bool value = (v != v2);
212    if (!value) {
213       err++;
214       if (err < 1000) {
215          Pmsg6(-1, "ERR %.80s %s:%i on %s == %lld\n", label, file, l, op, v, v2);
216       } else if (err == 1000) {
217          Pmsg0(-1, "ERR Too much errors\n");
218       }
219       if (print_var) {
220          gdb_print_local(1);
221       }
222    } else if (!quiet) {
223       Pmsg1(-1, "OK  %.80s\n", label);
224    }
225    return value;
226 }
227 
228 /*
229  * Short report of successful/all tests.
230  */
report()231 int report()
232 {
233    Pmsg0(-1, "==== Report ====\n");
234    Pmsg2(-1, "Result %i/%i OK\n", nb - err, nb);
235    return err > 0;
236 }
237 
terminate(int sig)238 void terminate(int sig) {};
239 
240 /*
241  * Initializes the application env, including lockmanager.
242  */
prolog(const char * name,bool lmgr,bool motd)243 void prolog(const char *name, bool lmgr, bool motd)
244 {
245    if (motd) {
246       Pmsg1(-1, "==== Starting %s ... ====\n", name);
247    }
248    my_name_is(0, NULL, name);
249    init_signals(terminate);
250 
251 #ifdef HAVE_WIN32
252    InitWinAPIWrapper();
253    WSA_Init();
254 #endif
255 
256    init_stack_dump();
257 
258    if (lmgr){
259       lmgr_init_thread();     /* initialize the lockmanager stack */
260       lmgrinit = true;
261    }
262 };
263 
264 /*
265  * Finish the application, shows report about memory leakage and terminates the lockmanager.
266  */
epilog()267 void epilog()
268 {
269    Pmsg0(-1, "\n");
270    stop_watchdog();
271    if (lmgrinit) {
272       lmgr_cleanup_main();
273    }
274    close_memory_pool();
275    sm_dump(false);
276    Pmsg0(-1, "==== Finish ====\n");
277 };
278