2 Unix SMB/CIFS implementation.
3 SMB torture UI functions
5 Copyright (C) Jelmer Vernooij 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "torture/ui.h"
23 #include "torture/torture.h"
24 #include "lib/util/dlinklist.h"
25 #include "param/param.h"
26 #include "system/filesys.h"
27 #include "auth/credentials/credentials.h"
28 #include "lib/cmdline/popt_common.h"
30 struct torture_context
*torture_context_init(TALLOC_CTX
*mem_ctx
,
31 const struct torture_ui_ops
*ui_ops
)
33 struct torture_context
*torture
= talloc_zero(mem_ctx
,
34 struct torture_context
);
35 torture
->ui_ops
= ui_ops
;
36 torture
->returncode
= true;
37 torture
->ev
= cli_credentials_get_event_context(cmdline_credentials
);
40 ui_ops
->init(torture
);
46 create a temporary directory.
48 _PUBLIC_ NTSTATUS
torture_temp_dir(struct torture_context
*tctx
,
52 SMB_ASSERT(tctx
->outputdir
!= NULL
);
54 *tempdir
= talloc_asprintf(tctx
, "%s/%s.XXXXXX", tctx
->outputdir
,
56 NT_STATUS_HAVE_NO_MEMORY(*tempdir
);
58 if (mkdtemp(*tempdir
) == NULL
) {
59 return map_nt_error_from_unix(errno
);
65 void torture_comment(struct torture_context
*context
, const char *comment
, ...)
70 if (!context
->ui_ops
->comment
)
73 va_start(ap
, comment
);
74 tmp
= talloc_vasprintf(context
, comment
, ap
);
76 context
->ui_ops
->comment(context
, tmp
);
81 void torture_warning(struct torture_context
*context
, const char *comment
, ...)
86 if (!context
->ui_ops
->warning
)
89 va_start(ap
, comment
);
90 tmp
= talloc_vasprintf(context
, comment
, ap
);
92 context
->ui_ops
->warning(context
, tmp
);
97 void torture_result(struct torture_context
*context
,
98 enum torture_result result
, const char *fmt
, ...)
104 if (context
->last_reason
) {
105 torture_warning(context
, "%s", context
->last_reason
);
106 talloc_free(context
->last_reason
);
109 context
->last_result
= result
;
110 context
->last_reason
= talloc_vasprintf(context
, fmt
, ap
);
114 struct torture_suite
*torture_suite_create(TALLOC_CTX
*ctx
, const char *name
)
116 struct torture_suite
*suite
= talloc_zero(ctx
, struct torture_suite
);
118 suite
->name
= talloc_strdup(suite
, name
);
119 suite
->testcases
= NULL
;
120 suite
->children
= NULL
;
125 void torture_tcase_set_fixture(struct torture_tcase
*tcase
,
126 bool (*setup
) (struct torture_context
*, void **),
127 bool (*teardown
) (struct torture_context
*, void *))
129 tcase
->setup
= setup
;
130 tcase
->teardown
= teardown
;
133 static bool wrap_test_with_testcase_const(struct torture_context
*torture_ctx
,
134 struct torture_tcase
*tcase
,
135 struct torture_test
*test
)
137 bool (*fn
) (struct torture_context
*,
138 const void *tcase_data
,
139 const void *test_data
);
143 return fn(torture_ctx
, tcase
->data
, test
->data
);
146 struct torture_test
*torture_tcase_add_test_const(struct torture_tcase
*tcase
,
148 bool (*run
) (struct torture_context
*, const void *tcase_data
,
149 const void *test_data
),
152 struct torture_test
*test
= talloc(tcase
, struct torture_test
);
154 test
->name
= talloc_strdup(test
, name
);
155 test
->description
= NULL
;
156 test
->run
= wrap_test_with_testcase_const
;
158 test
->dangerous
= false;
161 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
167 bool torture_suite_init_tcase(struct torture_suite
*suite
,
168 struct torture_tcase
*tcase
,
171 tcase
->name
= talloc_strdup(tcase
, name
);
172 tcase
->description
= NULL
;
174 tcase
->teardown
= NULL
;
175 tcase
->fixture_persistent
= true;
178 DLIST_ADD_END(suite
->testcases
, tcase
, struct torture_tcase
*);
184 struct torture_tcase
*torture_suite_add_tcase(struct torture_suite
*suite
,
187 struct torture_tcase
*tcase
= talloc(suite
, struct torture_tcase
);
189 if (!torture_suite_init_tcase(suite
, tcase
, name
))
195 bool torture_run_suite(struct torture_context
*context
,
196 struct torture_suite
*suite
)
199 struct torture_tcase
*tcase
;
200 struct torture_suite
*tsuite
;
204 if (context
->ui_ops
->suite_start
)
205 context
->ui_ops
->suite_start(context
, suite
);
207 old_testname
= context
->active_testname
;
208 if (old_testname
!= NULL
)
209 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
210 old_testname
, suite
->name
);
212 context
->active_testname
= talloc_strdup(context
, suite
->name
);
214 for (tcase
= suite
->testcases
; tcase
; tcase
= tcase
->next
) {
215 ret
&= torture_run_tcase(context
, tcase
);
218 for (tsuite
= suite
->children
; tsuite
; tsuite
= tsuite
->next
) {
219 ret
&= torture_run_suite(context
, tsuite
);
222 talloc_free(context
->active_testname
);
223 context
->active_testname
= old_testname
;
225 if (context
->ui_ops
->suite_finish
)
226 context
->ui_ops
->suite_finish(context
, suite
);
233 void torture_ui_test_start(struct torture_context
*context
,
234 struct torture_tcase
*tcase
,
235 struct torture_test
*test
)
237 if (context
->ui_ops
->test_start
)
238 context
->ui_ops
->test_start(context
, tcase
, test
);
241 int str_list_match(const char *name
, char **list
)
247 for (i
= 0; list
[i
]; i
++) {
248 if (gen_fnmatch(list
[i
], name
) == 0)
254 void torture_ui_test_result(struct torture_context
*context
,
255 enum torture_result result
,
258 if (context
->ui_ops
->test_result
)
259 context
->ui_ops
->test_result(context
, result
, comment
);
261 if (result
== TORTURE_ERROR
|| result
== TORTURE_FAIL
)
262 context
->returncode
= false;
265 static bool internal_torture_run_test(struct torture_context
*context
,
266 struct torture_tcase
*tcase
,
267 struct torture_test
*test
,
273 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
274 old_testname
= context
->active_testname
;
275 context
->active_testname
= talloc_asprintf(context
, "%s-%s", old_testname
, test
->name
);
278 context
->active_tcase
= tcase
;
279 context
->active_test
= test
;
281 torture_ui_test_start(context
, tcase
, test
);
283 context
->last_reason
= NULL
;
284 context
->last_result
= TORTURE_OK
;
286 if (!already_setup
&& tcase
->setup
&&
287 !tcase
->setup(context
, &(tcase
->data
))) {
288 if (context
->last_reason
== NULL
)
289 context
->last_reason
= talloc_strdup(context
, "Setup failure");
290 context
->last_result
= TORTURE_ERROR
;
292 } else if (test
->dangerous
&&
293 !torture_setting_bool(context
, "dangerous", false)) {
294 context
->last_result
= TORTURE_SKIP
;
295 context
->last_reason
= talloc_asprintf(context
,
296 "disabled %s - enable dangerous tests to use", test
->name
);
299 success
= test
->run(context
, tcase
, test
);
301 if (!success
&& context
->last_result
== TORTURE_OK
) {
302 if (context
->last_reason
== NULL
)
303 context
->last_reason
= talloc_strdup(context
, "Unknown error/failure");
304 context
->last_result
= TORTURE_ERROR
;
308 if (!already_setup
&& tcase
->teardown
&& !tcase
->teardown(context
, tcase
->data
)) {
309 if (context
->last_reason
== NULL
)
310 context
->last_reason
= talloc_strdup(context
, "Setup failure");
311 context
->last_result
= TORTURE_ERROR
;
315 torture_ui_test_result(context
, context
->last_result
,
316 context
->last_reason
);
318 talloc_free(context
->last_reason
);
320 if (tcase
== NULL
|| strcmp(test
->name
, tcase
->name
) != 0) {
321 talloc_free(context
->active_testname
);
322 context
->active_testname
= old_testname
;
324 context
->active_test
= NULL
;
325 context
->active_tcase
= NULL
;
330 bool torture_run_tcase(struct torture_context
*context
,
331 struct torture_tcase
*tcase
)
335 struct torture_test
*test
;
339 context
->active_tcase
= tcase
;
340 if (context
->ui_ops
->tcase_start
)
341 context
->ui_ops
->tcase_start(context
, tcase
);
343 if (tcase
->fixture_persistent
&& tcase
->setup
344 && !tcase
->setup(context
, &tcase
->data
)) {
345 /* FIXME: Use torture ui ops for reporting this error */
346 fprintf(stderr
, "Setup failed: ");
347 if (context
->last_reason
!= NULL
)
348 fprintf(stderr
, "%s", context
->last_reason
);
349 fprintf(stderr
, "\n");
354 old_testname
= context
->active_testname
;
355 context
->active_testname
= talloc_asprintf(context
, "%s-%s",
356 old_testname
, tcase
->name
);
357 for (test
= tcase
->tests
; test
; test
= test
->next
) {
358 ret
&= internal_torture_run_test(context
, tcase
, test
,
359 tcase
->fixture_persistent
);
361 talloc_free(context
->active_testname
);
362 context
->active_testname
= old_testname
;
364 if (tcase
->fixture_persistent
&& tcase
->teardown
&&
365 !tcase
->teardown(context
, tcase
->data
))
369 context
->active_tcase
= NULL
;
371 if (context
->ui_ops
->tcase_finish
)
372 context
->ui_ops
->tcase_finish(context
, tcase
);
379 bool torture_run_test(struct torture_context
*context
,
380 struct torture_tcase
*tcase
,
381 struct torture_test
*test
)
383 return internal_torture_run_test(context
, tcase
, test
, false);
386 int torture_setting_int(struct torture_context
*test
, const char *name
,
389 return lp_parm_int(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
392 double torture_setting_double(struct torture_context
*test
, const char *name
,
393 double default_value
)
395 return lp_parm_double(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
398 bool torture_setting_bool(struct torture_context
*test
, const char *name
,
401 return lp_parm_bool(test
->lp_ctx
, NULL
, "torture", name
, default_value
);
404 const char *torture_setting_string(struct torture_context
*test
,
406 const char *default_value
)
410 SMB_ASSERT(test
!= NULL
);
411 SMB_ASSERT(test
->lp_ctx
!= NULL
);
413 ret
= lp_parm_string(test
->lp_ctx
, NULL
, "torture", name
);
416 return default_value
;
421 static bool wrap_test_with_simple_tcase_const (
422 struct torture_context
*torture_ctx
,
423 struct torture_tcase
*tcase
,
424 struct torture_test
*test
)
426 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
430 return fn(torture_ctx
, test
->data
);
433 struct torture_tcase
*torture_suite_add_simple_tcase_const(
434 struct torture_suite
*suite
, const char *name
,
435 bool (*run
) (struct torture_context
*test
, const void *),
438 struct torture_tcase
*tcase
;
439 struct torture_test
*test
;
441 tcase
= torture_suite_add_tcase(suite
, name
);
443 test
= talloc(tcase
, struct torture_test
);
445 test
->name
= talloc_strdup(test
, name
);
446 test
->description
= NULL
;
447 test
->run
= wrap_test_with_simple_tcase_const
;
450 test
->dangerous
= false;
452 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
457 static bool wrap_simple_test(struct torture_context
*torture_ctx
,
458 struct torture_tcase
*tcase
,
459 struct torture_test
*test
)
461 bool (*fn
) (struct torture_context
*);
465 return fn(torture_ctx
);
468 struct torture_tcase
*torture_suite_add_simple_test(
469 struct torture_suite
*suite
,
471 bool (*run
) (struct torture_context
*test
))
473 struct torture_test
*test
;
474 struct torture_tcase
*tcase
;
476 tcase
= torture_suite_add_tcase(suite
, name
);
478 test
= talloc(tcase
, struct torture_test
);
480 test
->name
= talloc_strdup(test
, name
);
481 test
->description
= NULL
;
482 test
->run
= wrap_simple_test
;
484 test
->dangerous
= false;
486 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
491 bool torture_suite_add_suite(struct torture_suite
*suite
,
492 struct torture_suite
*child
)
497 DLIST_ADD_END(suite
->children
, child
, struct torture_suite
*);
499 /* FIXME: Check for duplicates and return false if the
500 * added suite already exists as a child */
506 struct torture_suite
*torture_find_suite(struct torture_suite
*parent
,
509 struct torture_suite
*child
;
511 for (child
= parent
->children
; child
; child
= child
->next
)
512 if (!strcmp(child
->name
, name
))
518 static bool wrap_test_with_simple_test_const(struct torture_context
*torture_ctx
,
519 struct torture_tcase
*tcase
,
520 struct torture_test
*test
)
522 bool (*fn
) (struct torture_context
*, const void *tcase_data
);
526 return fn(torture_ctx
, tcase
->data
);
529 struct torture_test
*torture_tcase_add_simple_test_const(
530 struct torture_tcase
*tcase
,
532 bool (*run
) (struct torture_context
*test
,
533 const void *tcase_data
))
535 struct torture_test
*test
;
537 test
= talloc(tcase
, struct torture_test
);
539 test
->name
= talloc_strdup(test
, name
);
540 test
->description
= NULL
;
541 test
->run
= wrap_test_with_simple_test_const
;
544 test
->dangerous
= false;
546 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);
551 static bool wrap_test_with_simple_test(struct torture_context
*torture_ctx
,
552 struct torture_tcase
*tcase
,
553 struct torture_test
*test
)
555 bool (*fn
) (struct torture_context
*, void *tcase_data
);
559 return fn(torture_ctx
, tcase
->data
);
562 struct torture_test
*torture_tcase_add_simple_test(struct torture_tcase
*tcase
,
564 bool (*run
) (struct torture_context
*test
, void *tcase_data
))
566 struct torture_test
*test
;
568 test
= talloc(tcase
, struct torture_test
);
570 test
->name
= talloc_strdup(test
, name
);
571 test
->description
= NULL
;
572 test
->run
= wrap_test_with_simple_test
;
575 test
->dangerous
= false;
577 DLIST_ADD_END(tcase
->tests
, test
, struct torture_test
*);