2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1997-2003
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "lib/cmdline/popt_common.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "system/readline.h"
28 #include "lib/smbreadline/smbreadline.h"
29 #include "libcli/libcli.h"
30 #include "lib/ldb/include/ldb.h"
31 #include "lib/events/events.h"
32 #include "dynconfig.h"
34 #include "torture/torture.h"
36 #include "lib/util/dlinklist.h"
37 #include "librpc/rpc/dcerpc.h"
39 static bool run_matching(struct torture_context *torture,
42 struct torture_suite *suite,
48 struct torture_suite *o;
50 for (o = torture_root->children; o; o = o->next) {
51 if (gen_fnmatch(expr, o->name) == 0) {
54 ret &= torture_run_suite(torture, o);
58 ret &= run_matching(torture, o->name, expr, o, matched);
62 struct torture_suite *c;
63 struct torture_tcase *t;
65 for (c = suite->children; c; c = c->next) {
66 asprintf(&name, "%s-%s", prefix, c->name);
68 if (gen_fnmatch(expr, name) == 0) {
71 torture->active_testname = talloc_strdup(torture, prefix);
72 ret &= torture_run_suite(torture, c);
77 ret &= run_matching(torture, name, expr, c, matched);
82 for (t = suite->testcases; t; t = t->next) {
83 asprintf(&name, "%s-%s", prefix, t->name);
84 if (gen_fnmatch(expr, name) == 0) {
87 torture->active_testname = talloc_strdup(torture, prefix);
88 ret &= torture_run_tcase(torture, t);
89 talloc_free(torture->active_testname);
98 #define MAX_COLS 80 /* FIXME: Determine this at run-time */
100 /****************************************************************************
101 run a specified test or "ALL"
102 ****************************************************************************/
103 static bool run_test(struct torture_context *torture, const char *name)
106 bool matched = false;
107 struct torture_suite *o;
109 if (strequal(name, "ALL")) {
110 for (o = torture_root->children; o; o = o->next) {
111 ret &= torture_run_suite(torture, o);
116 ret = run_matching(torture, NULL, name, NULL, &matched);
119 printf("Unknown torture operation '%s'\n", name);
126 static void parse_dns(const char *dns)
128 char *userdn, *basedn, *secret;
131 /* retrievieng the userdn */
132 p = strchr_m(dns, '#');
134 lp_set_cmdline("torture:ldap_userdn", "");
135 lp_set_cmdline("torture:ldap_basedn", "");
136 lp_set_cmdline("torture:ldap_secret", "");
139 userdn = strndup(dns, p - dns);
140 lp_set_cmdline("torture:ldap_userdn", userdn);
142 /* retrieve the basedn */
144 p = strchr_m(d, '#');
146 lp_set_cmdline("torture:ldap_basedn", "");
147 lp_set_cmdline("torture:ldap_secret", "");
150 basedn = strndup(d, p - d);
151 lp_set_cmdline("torture:ldap_basedn", basedn);
153 /* retrieve the secret */
156 lp_set_cmdline("torture:ldap_secret", "");
160 lp_set_cmdline("torture:ldap_secret", secret);
162 printf ("%s - %s - %s\n", userdn, basedn, secret);
166 static void usage(poptContext pc)
168 struct torture_suite *o;
169 struct torture_suite *s;
170 struct torture_tcase *t;
173 poptPrintUsage(pc, stdout, 0);
176 printf("The binding format is:\n\n");
178 printf(" TRANSPORT:host[flags]\n\n");
180 printf(" where TRANSPORT is either ncacn_np for SMB, ncacn_ip_tcp for RPC/TCP\n");
181 printf(" or ncalrpc for local connections.\n\n");
183 printf(" 'host' is an IP or hostname or netbios name. If the binding string\n");
184 printf(" identifies the server side of an endpoint, 'host' may be an empty\n");
185 printf(" string.\n\n");
187 printf(" 'flags' can include a SMB pipe name if using the ncacn_np transport or\n");
188 printf(" a TCP port number if using the ncacn_ip_tcp transport, otherwise they\n");
189 printf(" will be auto-determined.\n\n");
191 printf(" other recognised flags are:\n\n");
193 printf(" sign : enable ntlmssp signing\n");
194 printf(" seal : enable ntlmssp sealing\n");
195 printf(" connect : enable rpc connect level auth (auth, but no sign or seal)\n");
196 printf(" validate: enable the NDR validator\n");
197 printf(" print: enable debugging of the packets\n");
198 printf(" bigendian: use bigendian RPC\n");
199 printf(" padcheck: check reply data for non-zero pad bytes\n\n");
201 printf(" For example, these all connect to the samr pipe:\n\n");
203 printf(" ncacn_np:myserver\n");
204 printf(" ncacn_np:myserver[samr]\n");
205 printf(" ncacn_np:myserver[\\pipe\\samr]\n");
206 printf(" ncacn_np:myserver[/pipe/samr]\n");
207 printf(" ncacn_np:myserver[samr,sign,print]\n");
208 printf(" ncacn_np:myserver[\\pipe\\samr,sign,seal,bigendian]\n");
209 printf(" ncacn_np:myserver[/pipe/samr,seal,validate]\n");
210 printf(" ncacn_np:\n");
211 printf(" ncacn_np:[/pipe/samr]\n\n");
213 printf(" ncacn_ip_tcp:myserver\n");
214 printf(" ncacn_ip_tcp:myserver[1024]\n");
215 printf(" ncacn_ip_tcp:myserver[1024,sign,seal]\n\n");
217 printf(" ncalrpc:\n\n");
219 printf("The UNC format is:\n\n");
221 printf(" //server/share\n\n");
223 printf("Tests are:");
225 for (o = torture_root->children; o; o = o->next) {
226 printf("\n%s (%s):\n ", o->description, o->name);
229 for (s = o->children; s; s = s->next) {
230 if (i + strlen(o->name) + strlen(s->name) >= (MAX_COLS - 3)) {
234 i+=printf("%s-%s ", o->name, s->name);
237 for (t = o->testcases; t; t = t->next) {
238 if (i + strlen(o->name) + strlen(t->name) >= (MAX_COLS - 3)) {
242 i+=printf("%s-%s ", o->name, t->name);
248 printf("\nThe default test is ALL.\n");
253 static bool is_binding_string(const char *binding_string)
255 TALLOC_CTX *mem_ctx = talloc_named_const(NULL, 0, "is_binding_string");
256 struct dcerpc_binding *binding_struct;
259 status = dcerpc_parse_binding(mem_ctx, binding_string, &binding_struct);
261 talloc_free(mem_ctx);
262 return NT_STATUS_IS_OK(status);
265 static void max_runtime_handler(int sig)
267 DEBUG(0,("maximum runtime exceeded for smbtorture - terminating\n"));
271 struct timeval last_suite_started;
273 static void simple_suite_start(struct torture_context *ctx,
274 struct torture_suite *suite)
276 last_suite_started = timeval_current();
277 printf("Running %s\n", suite->name);
280 static void simple_suite_finish(struct torture_context *ctx,
281 struct torture_suite *suite)
284 printf("%s took %g secs\n\n", suite->name,
285 timeval_elapsed(&last_suite_started));
288 static void simple_test_result (struct torture_context *context,
289 enum torture_result res, const char *reason)
294 printf("OK: %s\n", reason);
297 printf("TEST %s FAILED! - %s\n", context->active_test->name, reason);
300 printf("ERROR IN TEST %s! - %s\n", context->active_test->name, reason);
303 printf("SKIP: %s - %s\n", context->active_test->name, reason);
308 static void simple_comment (struct torture_context *test,
311 printf("%s", comment);
314 const static struct torture_ui_ops std_ui_ops = {
315 .comment = simple_comment,
316 .suite_start = simple_suite_start,
317 .suite_finish = simple_suite_finish,
318 .test_result = simple_test_result
322 static void subunit_test_start (struct torture_context *ctx,
323 struct torture_tcase *tcase,
324 struct torture_test *test)
326 printf("test: %s\n", test->name);
329 static void subunit_test_result (struct torture_context *context,
330 enum torture_result res, const char *reason)
334 printf("success: %s", context->active_test->name);
337 printf("failure: %s", context->active_test->name);
340 printf("error: %s", context->active_test->name);
343 printf("skip: %s", context->active_test->name);
347 printf(" [ %s ]", reason);
351 static void subunit_comment (struct torture_context *test,
354 fprintf(stderr, "%s", comment);
357 const static struct torture_ui_ops subunit_ui_ops = {
358 .comment = subunit_comment,
359 .test_start = subunit_test_start,
360 .test_result = subunit_test_result
363 static void harness_test_start (struct torture_context *ctx,
364 struct torture_tcase *tcase,
365 struct torture_test *test)
369 static void harness_test_result (struct torture_context *context,
370 enum torture_result res, const char *reason)
374 printf("ok %s - %s\n", context->active_test->name, reason);
378 printf("not ok %s - %s\n", context->active_test->name, reason);
381 printf("skip %s - %s\n", context->active_test->name, reason);
386 static void harness_comment (struct torture_context *test,
389 printf("# %s\n", comment);
392 const static struct torture_ui_ops harness_ui_ops = {
393 .comment = harness_comment,
394 .test_start = harness_test_start,
395 .test_result = harness_test_result
398 static void quiet_suite_start(struct torture_context *ctx,
399 struct torture_suite *suite)
403 for (i = 1; i < ctx->level; i++) putchar('\t');
404 printf("%s: ", suite->name);
408 static void quiet_suite_finish(struct torture_context *ctx,
409 struct torture_suite *suite)
414 static void quiet_test_result (struct torture_context *context,
415 enum torture_result res, const char *reason)
419 case TORTURE_OK: putchar('.'); break;
420 case TORTURE_FAIL: putchar('F'); break;
421 case TORTURE_ERROR: putchar('E'); break;
422 case TORTURE_SKIP: putchar('I'); break;
426 const static struct torture_ui_ops quiet_ui_ops = {
427 .suite_start = quiet_suite_start,
428 .suite_finish = quiet_suite_finish,
429 .test_result = quiet_test_result
432 void run_recipe(struct torture_context *tctx, const char *recipe)
434 int numlines, i, ret;
437 lines = file_lines_load(recipe, &numlines, NULL);
439 fprintf(stderr, "Unable to load file %s\n", recipe);
443 for (i = 0; i < numlines; i++) {
447 ret = poptParseArgvString(lines[i], &argc, &argv);
449 fprintf(stderr, "Error parsing line\n");
453 run_test(tctx, argv[0]);
459 void run_shell(struct torture_context *tctx)
467 cline = smb_readline("torture> ", NULL, NULL);
472 ret = poptParseArgvString(cline, &argc, &argv);
474 fprintf(stderr, "Error parsing line\n");
478 if (!strcmp(argv[0], "quit")) {
480 } else if (!strcmp(argv[0], "set")) {
482 fprintf(stderr, "Usage: set <variable> <value>\n");
484 char *name = talloc_asprintf(NULL, "torture:%s", argv[1]);
485 lp_set_cmdline(name, argv[2]);
488 } else if (!strcmp(argv[0], "help")) {
489 fprintf(stderr, "Available commands:\n"
490 " help - This help command\n"
492 " set - Change variables\n"
494 } else if (!strcmp(argv[0], "run")) {
496 fprintf(stderr, "Usage: run TEST-NAME [OPTIONS...]\n");
498 run_test(tctx, argv[1]);
504 /****************************************************************************
506 ****************************************************************************/
507 int main(int argc,char *argv[])
513 struct torture_context *torture;
514 const struct torture_ui_ops *ui_ops;
517 static const char *target = "other";
518 const char **subunit_dir;
520 static const char *ui_ops_name = "simple";
521 enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS,
522 OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC,OPT_NUMPROGS};
524 struct poptOption long_options[] = {
526 {"format", 0, POPT_ARG_STRING, &ui_ops_name, 0, "Output format (one of: simple, subunit, harness)", NULL },
527 {"smb-ports", 'p', POPT_ARG_STRING, NULL, OPT_SMB_PORTS, "SMB ports", NULL},
528 {"seed", 0, POPT_ARG_INT, &torture_seed, 0, "seed", NULL},
529 {"num-progs", 0, POPT_ARG_INT, NULL, OPT_NUMPROGS, "num progs", NULL},
530 {"num-ops", 0, POPT_ARG_INT, &torture_numops, 0, "num ops", NULL},
531 {"entries", 0, POPT_ARG_INT, &torture_entries, 0, "entries", NULL},
532 {"loadfile", 0, POPT_ARG_STRING, NULL, OPT_LOADFILE, "loadfile", NULL},
533 {"unclist", 0, POPT_ARG_STRING, NULL, OPT_UNCLIST, "unclist", NULL},
534 {"timelimit", 't', POPT_ARG_INT, NULL, OPT_TIMELIMIT, "timelimit", NULL},
535 {"failures", 'f', POPT_ARG_INT, &torture_failures, 0, "failures", NULL},
536 {"parse-dns", 'D', POPT_ARG_STRING, NULL, OPT_DNS, "parse-dns", NULL},
537 {"dangerous", 'X', POPT_ARG_NONE, NULL, OPT_DANGEROUS,
538 "run dangerous tests (eg. wiping out password database)", NULL},
539 {"shell", 0, POPT_ARG_NONE, &shell, True, "Run shell", NULL},
540 {"target", 'T', POPT_ARG_STRING, &target, 0, "samba3|samba4|other", NULL},
541 {"async", 'a', POPT_ARG_NONE, NULL, OPT_ASYNC,
542 "run async tests", NULL},
543 {"num-async", 0, POPT_ARG_INT, &torture_numasync, 0,
544 "number of simultaneous async requests", NULL},
545 {"maximum-runtime", 0, POPT_ARG_INT, &max_runtime, 0,
546 "set maximum time for smbtorture to live", "seconds"},
548 POPT_COMMON_CONNECTION
549 POPT_COMMON_CREDENTIALS
556 /* we are never interested in SIGPIPE */
557 BlockSignals(true, SIGPIPE);
559 pc = poptGetContext("smbtorture", argc, (const char **) argv, long_options,
560 POPT_CONTEXT_KEEP_FIRST);
562 poptSetOtherOptionHelp(pc, "<binding>|<unc> TEST1 TEST2 ...");
564 while((opt = poptGetNextOpt(pc)) != -1) {
567 lp_set_cmdline("torture:loadfile", poptGetOptArg(pc));
570 lp_set_cmdline("torture:unclist", poptGetOptArg(pc));
573 lp_set_cmdline("torture:timelimit", poptGetOptArg(pc));
576 lp_set_cmdline("torture:nprocs", poptGetOptArg(pc));
579 parse_dns(poptGetOptArg(pc));
582 lp_set_cmdline("torture:dangerous", "Yes");
585 lp_set_cmdline("torture:async", "Yes");
588 lp_set_cmdline("smb ports", poptGetOptArg(pc));
593 if (strcmp(target, "samba3") == 0) {
594 lp_set_cmdline("torture:samba3", "true");
595 lp_set_cmdline("torture:knownfail", "samba3-knownfail");
596 } else if (strcmp(target, "samba4") == 0) {
597 lp_set_cmdline("torture:samba4", "true");
598 lp_set_cmdline("torture:knownfail", "samba4-knownfail");
602 /* this will only work if nobody else uses alarm(),
603 which means it won't work for some tests, but we
604 can't use the event context method we use for smbd
605 as so many tests create their own event
606 context. This will at least catch most cases. */
607 signal(SIGALRM, max_runtime_handler);
614 subunit_dir = lp_parm_string_list(-1, "torture", "subunitdir", ":");
615 if (subunit_dir == NULL)
616 torture_subunit_load_testsuites(dyn_TORTUREDIR, true, NULL);
618 for (i = 0; subunit_dir[i]; i++)
619 torture_subunit_load_testsuites(subunit_dir[i], true, NULL);
622 if (torture_seed == 0) {
623 torture_seed = time(NULL);
625 printf("Using seed %d\n", torture_seed);
626 srandom(torture_seed);
628 argv_new = discard_const_p(char *, poptGetArgs(pc));
631 for (i=0; i<argc; i++) {
632 if (argv_new[i] == NULL) {
638 if (!(argc_new >= 3 || (shell && argc_new >= 2))) {
643 /* see if its a RPC transport specifier */
644 if (is_binding_string(argv_new[1])) {
645 lp_set_cmdline("torture:binding", argv_new[1]);
647 char *binding = NULL;
648 char *host = NULL, *share = NULL;
650 if (!smbcli_parse_unc(argv_new[1], NULL, &host, &share)) {
651 d_printf("Invalid option: %s is not a valid torture target (share or binding string)\n\n", argv_new[1]);
655 lp_set_cmdline("torture:host", host);
656 lp_set_cmdline("torture:share", share);
657 asprintf(&binding, "ncacn_np:%s", host);
658 lp_set_cmdline("torture:binding", binding);
661 if (!strcmp(ui_ops_name, "simple")) {
662 ui_ops = &std_ui_ops;
663 } else if (!strcmp(ui_ops_name, "subunit")) {
664 ui_ops = &subunit_ui_ops;
665 } else if (!strcmp(ui_ops_name, "harness")) {
666 ui_ops = &harness_ui_ops;
667 } else if (!strcmp(ui_ops_name, "quiet")) {
668 ui_ops = &quiet_ui_ops;
670 printf("Unknown output format '%s'\n", ui_ops_name);
674 torture = torture_context_init(talloc_autofree_context(),
675 lp_parm_string(-1, "torture", "knownfail"), ui_ops);
678 printf("You must specify a test to run, or 'ALL'\n");
684 int unexpected_failures;
685 for (i=2;i<argc_new;i++) {
686 if (argv_new[i][0] == '@') {
687 run_recipe(torture, argv_new[i]+1);
688 } else if (!run_test(torture, argv_new[i])) {
693 unexpected_failures = str_list_length(torture->results.unexpected_failures);
695 total = torture->results.skipped+torture->results.success+torture->results.failed+torture->results.errors;
697 printf("No tests run.\n");
699 rate = ((total - unexpected_failures - torture->results.errors) * (100.0 / total));
701 printf("Tests: %d, Failures: %d", total, torture->results.failed);
702 if (torture->results.failed - unexpected_failures) {
703 printf(" (%d expected)", torture->results.failed - unexpected_failures);
705 printf(", Errors: %d, Skipped: %d. Success rate: %.2f%%\n",
706 torture->results.errors, torture->results.skipped, rate);
709 if (unexpected_failures) {
710 printf("The following tests failed:\n");
711 for (i = 0; torture->results.unexpected_failures[i]; i++) {
712 printf(" %s\n", torture->results.unexpected_failures[i]);
717 if (str_list_length(torture->results.unexpected_errors)) {
718 printf("Errors occurred while running the following tests:\n");
719 for (i = 0; torture->results.unexpected_errors[i]; i++) {
720 printf(" %s\n", torture->results.unexpected_errors[i]);
725 if (str_list_length(torture->results.unexpected_successes)) {
726 printf("The following tests were expected to fail but succeeded:\n");
727 for (i = 0; torture->results.unexpected_successes[i]; i++) {
728 printf(" %s\n", torture->results.unexpected_successes[i]);
734 if (torture->results.returncode) {