From 52e3f69a36b6ba6a589a8f768fbee77ee06b281c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 16 Oct 2006 20:05:19 +0000 Subject: r19343: Add support for external scripts/binaries that write results using the 'subunit' protocol. This allows us to easily plug EJS scripts or binaries that can't depend on -ltorture into smbtorture. The protocol is very simple: - write "comments" to stderr Example output on stdout: test: foo success: foo test: bar success: bar test: blah failure: blah [ dummy.c:30: Expression 1 != 2 failed! ] test: blie skip: blie [ Iconv support not built in ] I've already converted the talloc testsuite. (This used to be commit e1742c14a247fabba969f8698108e73997d3f420) --- source4/build/smb_build/makefile.pm | 19 +- source4/dynconfig.c | 3 + source4/dynconfig.h | 1 + source4/dynconfig.mk | 1 + source4/lib/talloc/config.mk | 4 + source4/lib/talloc/testsuite.c | 436 ++++++++++++++++++++---------------- source4/main.mk | 12 +- source4/script/tests/mktestsetup.sh | 3 +- source4/torture/config.mk | 3 +- source4/torture/local/config.mk | 1 - source4/torture/local/local.c | 5 - source4/torture/smbtorture.c | 27 ++- source4/torture/subunit.c | 239 ++++++++++++++++++++ source4/torture/ui.c | 48 ++-- source4/torture/ui.h | 9 + 15 files changed, 589 insertions(+), 222 deletions(-) create mode 100644 source4/torture/subunit.c diff --git a/source4/build/smb_build/makefile.pm b/source4/build/smb_build/makefile.pm index 97cfd7770f..0d448773a6 100644 --- a/source4/build/smb_build/makefile.pm +++ b/source4/build/smb_build/makefile.pm @@ -22,6 +22,7 @@ sub new($$$) $self->{manpages} = []; $self->{sbin_progs} = []; $self->{bin_progs} = []; + $self->{torture_progs} = []; $self->{static_libs} = []; $self->{shared_libs} = []; $self->{installable_shared_libs} = []; @@ -79,6 +80,7 @@ BASEDIR = $self->{config}->{prefix} BINDIR = $self->{config}->{bindir} SBINDIR = $self->{config}->{sbindir} LIBDIR = $self->{config}->{libdir} +TORTUREDIR = $self->{config}->{libdir}/torture MODULESDIR = $self->{config}->{modulesdir} INCLUDEDIR = $self->{config}->{includedir} CONFIGDIR = $self->{config}->{sysconfdir} @@ -364,11 +366,18 @@ sub Binary($$) my ($self,$ctx) = @_; my $installdir; + my $localdir; + + if (defined($ctx->{INSTALLDIR}) && $ctx->{INSTALLDIR} eq "TORTUREDIR") { + $localdir = "bin/torture"; + } else { + $localdir = "bin"; + } if ($self->{duplicate_build}) { $installdir = "bin/install"; } else { - $installdir = "bin"; + $installdir = $localdir; } push(@{$self->{all_objs}}, "\$($ctx->{TYPE}_$ctx->{NAME}_FULL_OBJ_LIST)"); @@ -378,9 +387,12 @@ sub Binary($$) push (@{$self->{sbin_progs}}, "$installdir/$ctx->{BINARY}"); } elsif ($ctx->{INSTALLDIR} eq "BINDIR") { push (@{$self->{bin_progs}}, "$installdir/$ctx->{BINARY}"); + } elsif ($ctx->{INSTALLDIR} eq "TORTUREDIR") { + push (@{$self->{torture_progs}}, "$installdir/$ctx->{BINARY}"); } - push (@{$self->{binaries}}, "bin/$ctx->{BINARY}"); + + push (@{$self->{binaries}}, "$localdir/$ctx->{BINARY}"); $self->_prepare_list($ctx, "OBJ_LIST"); $self->_prepare_list($ctx, "FULL_OBJ_LIST"); @@ -390,7 +402,7 @@ sub Binary($$) if ($self->{duplicate_build}) { $self->output(<< "__EOD__" # -bin/$ctx->{BINARY}: \$($ctx->{TYPE}_$ctx->{NAME}_DEPEND_LIST) \$($ctx->{TYPE}_$ctx->{NAME}_FULL_OBJ_LIST) +$localdir/$ctx->{BINARY}: \$($ctx->{TYPE}_$ctx->{NAME}_DEPEND_LIST) \$($ctx->{TYPE}_$ctx->{NAME}_FULL_OBJ_LIST) \@echo Linking \$\@ \@\$(LD) \$(LDFLAGS) -o \$\@ \$(LOCAL_LINK_FLAGS) \$(INSTALL_LINK_FLAGS) \\ \$\($ctx->{TYPE}_$ctx->{NAME}_LINK_FLAGS) @@ -511,6 +523,7 @@ sub write($$) $self->output("MANPAGES = ".array2oneperline($self->{manpages})."\n"); $self->output("BIN_PROGS = " . array2oneperline($self->{bin_progs}) . "\n"); $self->output("SBIN_PROGS = " . array2oneperline($self->{sbin_progs}) . "\n"); + $self->output("TORTURE_PROGS = " . array2oneperline($self->{torture_progs}) . "\n"); $self->output("BINARIES = " . array2oneperline($self->{binaries}) . "\n"); $self->output("STATIC_LIBS = " . array2oneperline($self->{static_libs}) . "\n"); $self->output("SHARED_LIBS = " . array2oneperline($self->{shared_libs}) . "\n"); diff --git a/source4/dynconfig.c b/source4/dynconfig.c index 41728af57d..5b1074382c 100644 --- a/source4/dynconfig.c +++ b/source4/dynconfig.c @@ -88,3 +88,6 @@ _PUBLIC_ const char *dyn_JSDIR = JSDIR; /** Where to find the winbindd socket */ _PUBLIC_ const char *dyn_WINBINDD_SOCKET_DIR = WINBINDD_SOCKET_DIR; + +/** Directory with subunit torture tests */ +_PUBLIC_ const char *dyn_TORTUREDIR = TORTUREDIR; diff --git a/source4/dynconfig.h b/source4/dynconfig.h index b1a7fff191..312283c5fb 100644 --- a/source4/dynconfig.h +++ b/source4/dynconfig.h @@ -40,3 +40,4 @@ extern const char *dyn_SWATDIR; extern const char *dyn_JSDIR; extern const char *dyn_SETUPDIR; extern const char *dyn_WINBINDD_SOCKET_DIR; +extern const char *dyn_TORTUREDIR; diff --git a/source4/dynconfig.mk b/source4/dynconfig.mk index 2743bc2b29..180333693d 100644 --- a/source4/dynconfig.mk +++ b/source4/dynconfig.mk @@ -10,6 +10,7 @@ PATH_FLAGS = -DCONFIGFILE=\"$(CONFIGFILE)\" \ -DCONFIGDIR=\"$(CONFIGDIR)\" -DNCALRPCDIR=\"$(NCALRPCDIR)\" \ -DSWATDIR=\"$(SWATDIR)\" -DPRIVATE_DIR=\"$(PRIVATEDIR)\" \ -DMODULESDIR=\"$(MODULESDIR)\" -DJSDIR=\"$(JSDIR)\" \ + -DTORTUREDIR=\"$(TORTUREDIR)\" \ -DSETUPDIR=\"$(SETUPDIR)\" -DWINBINDD_SOCKET_DIR=\"$(WINBINDD_SOCKET_DIR)\" dynconfig.o: dynconfig.c Makefile diff --git a/source4/lib/talloc/config.mk b/source4/lib/talloc/config.mk index 3a8a22aa57..19059ca4dc 100644 --- a/source4/lib/talloc/config.mk +++ b/source4/lib/talloc/config.mk @@ -12,3 +12,7 @@ DESCRIPTION = A hierarchical pool based memory system with destructors # End LIBRARY LIBTALLOC ################################################ +[BINARY::LOCAL-TALLOC] +OBJ_FILES = testsuite.o +PRIVATE_DEPENDENCIES = LIBTALLOC +INSTALLDIR = TORTUREDIR diff --git a/source4/lib/talloc/testsuite.c b/source4/lib/talloc/testsuite.c index f2e61157e4..14222c75af 100644 --- a/source4/lib/talloc/testsuite.c +++ b/source4/lib/talloc/testsuite.c @@ -27,17 +27,6 @@ #include "replace.h" #include "system/time.h" #include "talloc.h" -#ifdef _SAMBA_BUILD_ -#include "includes.h" -#include "torture/ui.h" -#else -#define torture_comment printf -#define torture_assert(tctx, expr, str) if (!(expr)) { printf str; return false; } -#define torture_suite_add_simple_tcase(suite,name,fn) \ - ret &= printf("TESTING %s\n", name), fn(); -#define torture_out stdout - -struct torture_suite; static struct timeval timeval_current(void) { @@ -52,7 +41,18 @@ static double timeval_elapsed(struct timeval *tv) return (tv2.tv_sec - tv->tv_sec) + (tv2.tv_usec - tv->tv_usec)*1.0e-6; } -#endif /* _SAMBA_BUILD_ */ + +#define torture_assert(expr, str) if (!(expr)) { \ + printf("failure: xx [\n%s: Expression %s failed: %s\n]\n", \ + __location__, #expr, str); \ + return false; \ +} + +#define torture_assert_str_equal(arg1, arg2, desc) if (strcmp(arg1, arg2)) { \ + printf("failure: xx [\n%s: Expected %s, got %s: %s\n]\n", \ + __location__, arg1, arg2, desc); \ + return false; \ +} #if _SAMBA_BUILD_==3 #ifdef malloc @@ -65,10 +65,10 @@ static double timeval_elapsed(struct timeval *tv) #define CHECK_SIZE(ptr, tsize) do { \ if (talloc_total_size(ptr) != (tsize)) { \ - torture_comment(tctx, talloc_asprintf(tctx, "failed: wrong '%s' tree size: got %u expected %u\n", \ + fprintf(stderr, "failed: wrong '%s' tree size: got %u expected %u\n", \ #ptr, \ (unsigned)talloc_total_size(ptr), \ - (unsigned)tsize)); \ + (unsigned)tsize); \ talloc_report_full(ptr, stdout); \ return false; \ } \ @@ -76,10 +76,10 @@ static double timeval_elapsed(struct timeval *tv) #define CHECK_BLOCKS(ptr, tblocks) do { \ if (talloc_total_blocks(ptr) != (tblocks)) { \ - torture_comment(tctx, talloc_asprintf(tctx, "failed: wrong '%s' tree blocks: got %u expected %u\n", \ + fprintf(stderr, "failed: wrong '%s' tree blocks: got %u expected %u\n", \ #ptr, \ (unsigned)talloc_total_blocks(ptr), \ - (unsigned)tblocks)); \ + (unsigned)tblocks); \ talloc_report_full(ptr, stdout); \ return false; \ } \ @@ -87,10 +87,10 @@ static double timeval_elapsed(struct timeval *tv) #define CHECK_PARENT(ptr, parent) do { \ if (talloc_parent(ptr) != (parent)) { \ - torture_comment(tctx, talloc_asprintf(tctx, "failed: '%s' has wrong parent: got %p expected %p\n", \ + fprintf(stderr, "failed: '%s' has wrong parent: got %p expected %p\n", \ #ptr, \ talloc_parent(ptr), \ - (parent))); \ + (parent)); \ talloc_report_full(ptr, stdout); \ talloc_report_full(parent, stdout); \ talloc_report_full(NULL, stdout); \ @@ -102,10 +102,12 @@ static double timeval_elapsed(struct timeval *tv) /* test references */ -static bool test_ref1(struct torture_context *tctx) +static bool test_ref1(void) { void *root, *p1, *p2, *ref, *r1; + printf("test: SINGLE REFERENCE FREE\n"); + root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); p2 = talloc_named_const(p1, 1, "p2"); @@ -115,31 +117,31 @@ static bool test_ref1(struct torture_context *tctx) r1 = talloc_named_const(root, 1, "r1"); ref = talloc_reference(r1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 2); - torture_comment(tctx, "Freeing p2\n"); + fprintf(stderr, "Freeing p2\n"); talloc_free(p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p1\n"); + fprintf(stderr, "Freeing p1\n"); talloc_free(p1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing r1\n"); + fprintf(stderr, "Freeing r1\n"); talloc_free(r1); - talloc_report_full(NULL, torture_out); + talloc_report_full(NULL, stderr); - torture_comment(tctx, "Testing NULL\n"); + fprintf(stderr, "Testing NULL\n"); if (talloc_reference(root, NULL)) { return false; } @@ -149,16 +151,18 @@ static bool test_ref1(struct torture_context *tctx) CHECK_SIZE(root, 0); talloc_free(root); + printf("success: SINGLE REFERENCE FREE\n"); return true; } /* test references */ -static bool test_ref2(struct torture_context *tctx) +static bool test_ref2(void) { void *root, *p1, *p2, *ref, *r1; + printf("test: DOUBLE REFERENCE FREE\n"); root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); @@ -168,85 +172,92 @@ static bool test_ref2(struct torture_context *tctx) r1 = talloc_named_const(root, 1, "r1"); ref = talloc_reference(r1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 2); - torture_comment(tctx, "Freeing ref\n"); + fprintf(stderr, "Freeing ref\n"); talloc_free(ref); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p2\n"); + fprintf(stderr, "Freeing p2\n"); talloc_free(p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 4); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p1\n"); + fprintf(stderr, "Freeing p1\n"); talloc_free(p1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing r1\n"); + fprintf(stderr, "Freeing r1\n"); talloc_free(r1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_SIZE(root, 0); talloc_free(root); + printf("success: DOUBLE REFERENCE FREE\n"); return true; } /* test references */ -static bool test_ref3(struct torture_context *tctx) +static bool test_ref3(void) { void *root, *p1, *p2, *ref, *r1; + printf("test: PARENT REFERENCE FREE\n"); + root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); p2 = talloc_named_const(root, 1, "p2"); r1 = talloc_named_const(p1, 1, "r1"); ref = talloc_reference(p2, r1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 2); CHECK_BLOCKS(p2, 2); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p1\n"); + fprintf(stderr, "Freeing p1\n"); talloc_free(p1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p2, 2); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p2\n"); + fprintf(stderr, "Freeing p2\n"); talloc_free(p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_SIZE(root, 0); talloc_free(root); + + printf("success: PARENT REFERENCE FREE\n"); return true; } /* test references */ -static bool test_ref4(struct torture_context *tctx) +static bool test_ref4(void) { void *root, *p1, *p2, *ref, *r1; + printf("test: REFERRER REFERENCE FREE\n"); + root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); @@ -256,32 +267,34 @@ static bool test_ref4(struct torture_context *tctx) r1 = talloc_named_const(root, 1, "r1"); ref = talloc_reference(r1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 2); - torture_comment(tctx, "Freeing r1\n"); + fprintf(stderr, "Freeing r1\n"); talloc_free(r1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 5); CHECK_BLOCKS(p2, 1); - torture_comment(tctx, "Freeing p2\n"); + fprintf(stderr, "Freeing p2\n"); talloc_free(p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 4); - torture_comment(tctx, "Freeing p1\n"); + fprintf(stderr, "Freeing p1\n"); talloc_free(p1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_SIZE(root, 0); talloc_free(root); + + printf("success: REFERRER REFERENCE FREE\n"); return true; } @@ -289,10 +302,12 @@ static bool test_ref4(struct torture_context *tctx) /* test references */ -static bool test_unlink1(struct torture_context *tctx) +static bool test_unlink1(void) { void *root, *p1, *p2, *ref, *r1; + printf("test: UNLINK\n"); + root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "p1"); talloc_named_const(p1, 1, "x1"); @@ -302,27 +317,29 @@ static bool test_unlink1(struct torture_context *tctx) r1 = talloc_named_const(p1, 1, "r1"); ref = talloc_reference(r1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 7); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 2); - torture_comment(tctx, "Unreferencing r1\n"); + fprintf(stderr, "Unreferencing r1\n"); talloc_unlink(r1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p1, 6); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(r1, 1); - torture_comment(tctx, "Freeing p1\n"); + fprintf(stderr, "Freeing p1\n"); talloc_free(p1); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_SIZE(root, 0); talloc_free(root); + + printf("success: UNLINK\n"); return true; } @@ -334,17 +351,19 @@ static int fail_destructor(void *ptr) /* miscellaneous tests to try to get a higher test coverage percentage */ -static bool test_misc(struct torture_context *tctx) +static bool test_misc(void) { void *root, *p1; char *p2; double *d; const char *name; + printf("test: MISCELLANEOUS\n"); + root = talloc_new(NULL); p1 = talloc_size(root, 0x7fffffff); - torture_assert(tctx, !p1, "failed: large talloc allowed\n"); + torture_assert(!p1, "failed: large talloc allowed\n"); p1 = talloc_strdup(root, "foo"); talloc_increase_ref_count(p1); @@ -359,65 +378,65 @@ static bool test_misc(struct torture_context *tctx) CHECK_BLOCKS(p1, 1); CHECK_BLOCKS(root, 2); p2 = talloc_strdup(p1, "foo"); - torture_assert(tctx, talloc_unlink(root, p2) == -1, + torture_assert(talloc_unlink(root, p2) == -1, "failed: talloc_unlink() of non-reference context should return -1\n"); - torture_assert(tctx, talloc_unlink(p1, p2) == 0, + torture_assert(talloc_unlink(p1, p2) == 0, "failed: talloc_unlink() of parent should succeed\n"); talloc_free(p1); CHECK_BLOCKS(p1, 1); CHECK_BLOCKS(root, 2); name = talloc_set_name(p1, "my name is %s", "foo"); - torture_assert_str_equal(tctx, talloc_get_name(p1), "my name is foo", + torture_assert_str_equal(talloc_get_name(p1), "my name is foo", "failed: wrong name after talloc_set_name(my name is foo)"); CHECK_BLOCKS(p1, 2); CHECK_BLOCKS(root, 3); talloc_set_name_const(p1, NULL); - torture_assert_str_equal (tctx, talloc_get_name(p1), "UNNAMED", + torture_assert_str_equal (talloc_get_name(p1), "UNNAMED", "failed: wrong name after talloc_set_name(NULL)"); CHECK_BLOCKS(p1, 2); CHECK_BLOCKS(root, 3); - torture_assert(tctx, talloc_free(NULL) == -1, + torture_assert(talloc_free(NULL) == -1, "talloc_free(NULL) should give -1\n"); talloc_set_destructor(p1, fail_destructor); - torture_assert(tctx, talloc_free(p1) == -1, + torture_assert(talloc_free(p1) == -1, "Failed destructor should cause talloc_free to fail\n"); talloc_set_destructor(p1, NULL); - talloc_report(root, torture_out); + talloc_report(root, stderr); p2 = (char *)talloc_zero_size(p1, 20); - torture_assert(tctx, p2[19] == 0, "Failed to give zero memory\n"); + torture_assert(p2[19] == 0, "Failed to give zero memory\n"); talloc_free(p2); - torture_assert(tctx, talloc_strdup(root, NULL) == NULL, + torture_assert(talloc_strdup(root, NULL) == NULL, "failed: strdup on NULL should give NULL\n"); p2 = talloc_strndup(p1, "foo", 2); - torture_assert(tctx, strcmp("fo", p2) == 0, "failed: strndup doesn't work\n"); + torture_assert(strcmp("fo", p2) == 0, "failed: strndup doesn't work\n"); p2 = talloc_asprintf_append(p2, "o%c", 'd'); - torture_assert(tctx, strcmp("food", p2) == 0, + torture_assert(strcmp("food", p2) == 0, "failed: talloc_asprintf_append doesn't work\n"); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(p1, 3); p2 = talloc_asprintf_append(NULL, "hello %s", "world"); - torture_assert(tctx, strcmp("hello world", p2) == 0, + torture_assert(strcmp("hello world", p2) == 0, "failed: talloc_asprintf_append doesn't work\n"); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(p1, 3); talloc_free(p2); d = talloc_array(p1, double, 0x20000000); - torture_assert(tctx, !d, "failed: integer overflow not detected\n"); + torture_assert(!d, "failed: integer overflow not detected\n"); d = talloc_realloc(p1, d, double, 0x20000000); - torture_assert(tctx, !d, "failed: integer overflow not detected\n"); + torture_assert(!d, "failed: integer overflow not detected\n"); talloc_free(p1); CHECK_BLOCKS(root, 1); @@ -429,7 +448,7 @@ static bool test_misc(struct torture_context *tctx) p1 = talloc_init("%d bytes", 200); p2 = talloc_asprintf(p1, "my test '%s'", "string"); - torture_assert_str_equal(tctx, p2, "my test 'string'", + torture_assert_str_equal(p2, "my test 'string'", "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\""); CHECK_BLOCKS(p1, 3); CHECK_SIZE(p2, 17); @@ -439,9 +458,9 @@ static bool test_misc(struct torture_context *tctx) p1 = talloc_named_const(root, 10, "p1"); p2 = (char *)talloc_named_const(root, 20, "p2"); (void)talloc_reference(p1, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); talloc_unlink(root, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(p1, 2); CHECK_BLOCKS(root, 3); @@ -451,9 +470,9 @@ static bool test_misc(struct torture_context *tctx) p1 = talloc_named_const(root, 10, "p1"); p2 = (char *)talloc_named_const(root, 20, "p2"); (void)talloc_reference(NULL, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); talloc_unlink(root, p2); - talloc_report_full(root, torture_out); + talloc_report_full(root, stderr); CHECK_BLOCKS(p2, 1); CHECK_BLOCKS(p1, 1); CHECK_BLOCKS(root, 2); @@ -462,11 +481,11 @@ static bool test_misc(struct torture_context *tctx) /* Test that talloc_unlink is a no-op */ - torture_assert(tctx, talloc_unlink(root, NULL) == -1, + torture_assert(talloc_unlink(root, NULL) == -1, "failed: talloc_unlink(root, NULL) == -1\n"); - talloc_report(root, torture_out); - talloc_report(NULL, torture_out); + talloc_report(root, stderr); + talloc_report(NULL, stderr); CHECK_SIZE(root, 0); @@ -476,6 +495,9 @@ static bool test_misc(struct torture_context *tctx) talloc_enable_leak_report(); talloc_enable_leak_report_full(); + + printf("success: MISCELLANEOUS\n"); + return true; } @@ -483,10 +505,12 @@ static bool test_misc(struct torture_context *tctx) /* test realloc */ -static bool test_realloc(struct torture_context *tctx) +static bool test_realloc(void) { void *root, *p1, *p2; + printf("test: REALLOC\n"); + root = talloc_new(NULL); p1 = talloc_size(root, 10); @@ -511,7 +535,7 @@ static bool test_realloc(struct torture_context *tctx) CHECK_SIZE(p1, 60); talloc_increase_ref_count(p2); - torture_assert(tctx, talloc_realloc_size(NULL, p2, 5) == NULL, + torture_assert(talloc_realloc_size(NULL, p2, 5) == NULL, "failed: talloc_realloc() on a referenced pointer should fail\n"); CHECK_BLOCKS(p1, 4); @@ -519,7 +543,7 @@ static bool test_realloc(struct torture_context *tctx) talloc_realloc_size(NULL, p2, 0); CHECK_BLOCKS(p1, 3); - torture_assert(tctx, talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL, + torture_assert(talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL, "failed: oversize talloc should fail\n"); talloc_realloc_size(NULL, p1, 0); @@ -528,13 +552,16 @@ static bool test_realloc(struct torture_context *tctx) CHECK_SIZE(root, 0); talloc_free(root); + + printf("success: REALLOC\n"); + return true; } /* test realloc with a child */ -static bool test_realloc_child(struct torture_context *tctx) +static bool test_realloc_child(void) { void *root; struct el2 { @@ -545,6 +572,8 @@ static bool test_realloc_child(struct torture_context *tctx) struct el2 **list, **list2, **list3; } *el1; + printf("test: REALLOC WITH CHILD\n"); + root = talloc_new(NULL); el1 = talloc(root, struct el1); @@ -569,13 +598,15 @@ static bool test_realloc_child(struct torture_context *tctx) el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300); talloc_free(root); + + printf("success: REALLOC WITH CHILD\n"); return true; } /* test type checking */ -static bool test_type(struct torture_context *tctx) +static bool test_type(void) { void *root; struct el1 { @@ -586,31 +617,37 @@ static bool test_type(struct torture_context *tctx) }; struct el1 *el1; + printf("test: talloc type checking\n"); + root = talloc_new(NULL); el1 = talloc(root, struct el1); el1->count = 1; - torture_assert(tctx, talloc_get_type(el1, struct el1) == el1, + torture_assert(talloc_get_type(el1, struct el1) == el1, "type check failed on el1\n"); - torture_assert(tctx, talloc_get_type(el1, struct el2) == NULL, + torture_assert(talloc_get_type(el1, struct el2) == NULL, "type check failed on el1 with el2\n"); talloc_set_type(el1, struct el2); - torture_assert(tctx, talloc_get_type(el1, struct el2) == (struct el2 *)el1, + torture_assert(talloc_get_type(el1, struct el2) == (struct el2 *)el1, "type set failed on el1 with el2\n"); talloc_free(root); + + printf("success: talloc type checking\n"); return true; } /* test steal */ -static bool test_steal(struct torture_context *tctx) +static bool test_steal(void) { void *root, *p1, *p2; + printf("test: STEAL\n"); + root = talloc_new(NULL); p1 = talloc_array(root, char, 10); @@ -620,10 +657,10 @@ static bool test_steal(struct torture_context *tctx) CHECK_SIZE(p1, 10); CHECK_SIZE(root, 30); - torture_assert(tctx, talloc_steal(p1, NULL) == NULL, + torture_assert(talloc_steal(p1, NULL) == NULL, "failed: stealing NULL should give NULL\n"); - torture_assert(tctx, talloc_steal(p1, p1) == p1, + torture_assert(talloc_steal(p1, p1) == p1, "failed: stealing to ourselves is a nop\n"); CHECK_BLOCKS(root, 3); CHECK_SIZE(root, 30); @@ -646,16 +683,18 @@ static bool test_steal(struct torture_context *tctx) talloc_free(root); p1 = talloc_size(NULL, 3); - talloc_report_full(NULL, torture_out); + talloc_report_full(NULL, stderr); CHECK_SIZE(NULL, 3); talloc_free(p1); + + printf("success: STEAL\n"); return true; } /* test move */ -static bool test_move(struct torture_context *tctx) +static bool test_move(void) { void *root; struct t_move { @@ -663,6 +702,8 @@ static bool test_move(struct torture_context *tctx) int *x; } *t1, *t2; + printf("test: MOVE\n"); + root = talloc_new(NULL); t1 = talloc(root, struct t_move); @@ -673,22 +714,26 @@ static bool test_move(struct torture_context *tctx) t2->p = talloc_move(t2, &t1->p); t2->x = talloc_move(t2, &t1->x); - torture_assert(tctx, t1->p == NULL && t1->x == NULL && + torture_assert(t1->p == NULL && t1->x == NULL && strcmp(t2->p, "foo") == 0 && *t2->x == 42, "talloc move failed"); talloc_free(root); + printf("success: MOVE\n"); + return true; } /* test talloc_realloc_fn */ -static bool test_realloc_fn(struct torture_context *tctx) +static bool test_realloc_fn(void) { void *root, *p1; + printf("test: talloc_realloc_fn\n"); + root = talloc_new(NULL); p1 = talloc_realloc_fn(root, NULL, 10); @@ -702,14 +747,18 @@ static bool test_realloc_fn(struct torture_context *tctx) CHECK_SIZE(root, 0); talloc_free(root); + + printf("success: talloc_realloc_fn\n"); return true; } -static bool test_unref_reparent(struct torture_context *tctx) +static bool test_unref_reparent(void) { void *root, *p1, *p2, *c1; + printf("test: UNREFERENCE AFTER PARENT FREED\n"); + root = talloc_named_const(NULL, 0, "root"); p1 = talloc_named_const(root, 1, "orig parent"); p2 = talloc_named_const(root, 1, "parent by reference"); @@ -729,18 +778,22 @@ static bool test_unref_reparent(struct torture_context *tctx) talloc_free(p2); talloc_free(root); + + printf("success: UNREFERENCE AFTER PARENT FREED\n"); return true; } /* measure the speed of talloc versus malloc */ -static bool test_speed(struct torture_context *tctx) +static bool test_speed(void) { void *ctx = talloc_new(NULL); unsigned count; struct timeval tv; + printf("test: TALLOC VS MALLOC SPEED\n"); + tv = timeval_current(); count = 0; do { @@ -752,7 +805,7 @@ static bool test_speed(struct torture_context *tctx) count += 3; } while (timeval_elapsed(&tv) < 5.0); - torture_comment(tctx, talloc_asprintf(tctx, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv))); + fprintf(stderr, "talloc: %.0f ops/sec\n", count/timeval_elapsed(&tv)); talloc_free(ctx); @@ -769,27 +822,34 @@ static bool test_speed(struct torture_context *tctx) count += 3; } while (timeval_elapsed(&tv) < 5.0); - torture_comment(tctx, talloc_asprintf(tctx, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv))); + fprintf(stderr, "malloc: %.0f ops/sec\n", count/timeval_elapsed(&tv)); + + printf("success: TALLOC VS MALLOC SPEED\n"); + return true; } -static bool test_lifeless(struct torture_context *tctx) +static bool test_lifeless(void) { void *top = talloc_new(NULL); char *parent, *child; void *child_owner = talloc_new(NULL); + printf("test: TALLOC_UNLINK LOOP\n"); + parent = talloc_strdup(top, "parent"); child = talloc_strdup(parent, "child"); (void)talloc_reference(child, parent); (void)talloc_reference(child_owner, child); - talloc_report_full(top, torture_out); + talloc_report_full(top, stderr); talloc_unlink(top, parent); talloc_free(child); - talloc_report_full(top, torture_out); + talloc_report_full(top, stderr); talloc_free(top); talloc_free(child_owner); talloc_free(child); + + printf("success: TALLOC_UNLINK LOOP\n"); return true; } @@ -801,7 +861,7 @@ static int test_loop_destructor(char *ptr) return 0; } -static bool test_loop(struct torture_context *tctx) +static bool test_loop(void) { void *top = talloc_new(NULL); char *parent; @@ -809,21 +869,25 @@ static bool test_loop(struct torture_context *tctx) char *req2, *req3; } *req1; + printf("test: TALLOC LOOP DESTRUCTION\n"); + parent = talloc_strdup(top, "parent"); req1 = talloc(parent, struct req1); req1->req2 = talloc_strdup(req1, "req2"); talloc_set_destructor(req1->req2, test_loop_destructor); req1->req3 = talloc_strdup(req1, "req3"); (void)talloc_reference(req1->req3, req1); - talloc_report_full(top, torture_out); + talloc_report_full(top, stderr); talloc_free(parent); - talloc_report_full(top, torture_out); - talloc_report_full(NULL, torture_out); + talloc_report_full(top, stderr); + talloc_report_full(NULL, stderr); talloc_free(top); - torture_assert(tctx, loop_destructor_count == 1, + torture_assert(loop_destructor_count == 1, "FAILED TO FIRE LOOP DESTRUCTOR\n"); loop_destructor_count = 0; + + printf("success: TALLOC LOOP DESTRUCTION\n"); return true; } @@ -832,13 +896,15 @@ static int fail_destructor_str(char *ptr) return -1; } -static bool test_free_parent_deny_child(struct torture_context *tctx) +static bool test_free_parent_deny_child(void) { void *top = talloc_new(NULL); char *level1; char *level2; char *level3; + printf("test: TALLOC FREE PARENT DENY CHILD\n"); + level1 = talloc_strdup(top, "level1"); level2 = talloc_strdup(level1, "level2"); level3 = talloc_strdup(level2, "level3"); @@ -850,10 +916,12 @@ static bool test_free_parent_deny_child(struct torture_context *tctx) CHECK_PARENT(level3, top); talloc_free(top); + + printf("success: TALLOC FREE PARENT DENY CHILD\n"); return true; } -static bool test_talloc_ptrtype(struct torture_context *tctx) +static bool test_talloc_ptrtype(void) { void *top = talloc_new(NULL); struct struct1 { @@ -865,131 +933,123 @@ static bool test_talloc_ptrtype(struct torture_context *tctx) const char *location3; const char *location4; + printf("test: TALLOC PTRTYPE\n"); + s1 = talloc_ptrtype(top, s1);location1 = __location__; - torture_assert(tctx, talloc_get_size(s1) == sizeof(struct struct1), - talloc_asprintf(tctx, - "talloc_ptrtype() allocated the wrong size %lu " - "(should be %lu)\n", (unsigned long)talloc_get_size(s1), - (unsigned long)sizeof(struct struct1))); + if (talloc_get_size(s1) != sizeof(struct struct1)) { + printf("failure: TALLOC PTRTYPE [\n" + "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n" + "]\n", (unsigned long)talloc_get_size(s1), + (unsigned long)sizeof(struct struct1)); + return false; + } - torture_assert(tctx, strcmp(location1, talloc_get_name(s1)) == 0, - talloc_asprintf(tctx, - "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n", - talloc_get_name(s1), location1)); + if (strcmp(location1, talloc_get_name(s1)) != 0) { + printf("failure: TALLOC PTRTYPE [\n" + "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n", + talloc_get_name(s1), location1); + return false; + } s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__; - torture_assert(tctx, talloc_get_size(s2) == (sizeof(struct struct1) * 10), - talloc_asprintf(tctx, - "talloc_array_ptrtype() allocated the wrong size " - "%lu (should be %lu)\n", + if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) { + printf("failure: TALLOC PTRTYPE [\n" + "talloc_array_ptrtype() allocated the wrong size " + "%lu (should be %lu)\n]\n", (unsigned long)talloc_get_size(s2), - (unsigned long)(sizeof(struct struct1)*10))); + (unsigned long)(sizeof(struct struct1)*10)); + return false; + } - torture_assert(tctx, strcmp(location2, talloc_get_name(s2)) == 0, - talloc_asprintf(tctx, - "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n", - talloc_get_name(s2), location2)); + if (strcmp(location2, talloc_get_name(s2)) != 0) { + printf("failure: TALLOC PTRTYPE [\n" + "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n", + talloc_get_name(s2), location2); + return false; + } s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__; - torture_assert(tctx, talloc_get_size(s3) == (sizeof(struct struct1 *) * 10), - talloc_asprintf(tctx, - "talloc_array_ptrtype() allocated the wrong size " - "%lu (should be %lu)\n", + if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) { + printf("failure: TALLOC PTRTYPE [\n" + "talloc_array_ptrtype() allocated the wrong size " + "%lu (should be %lu)\n]\n", (unsigned long)talloc_get_size(s3), - (unsigned long)(sizeof(struct struct1 *)*10))); + (unsigned long)(sizeof(struct struct1 *)*10)); + return false; + } - torture_assert_str_equal(tctx, location3, talloc_get_name(s3), + torture_assert_str_equal(location3, talloc_get_name(s3), "talloc_array_ptrtype() sets the wrong name"); s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__; - torture_assert(tctx, talloc_get_size(s4) == (sizeof(struct struct1 **) * 10), - talloc_asprintf(tctx, + if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) { + printf("failure: TALLOC PTRTYPE [\n" "talloc_array_ptrtype() allocated the wrong size " - "%lu (should be %lu)\n", + "%lu (should be %lu)\n]\n", (unsigned long)talloc_get_size(s4), - (unsigned long)(sizeof(struct struct1 **)*10))); + (unsigned long)(sizeof(struct struct1 **)*10)); + return false; + } - torture_assert_str_equal(tctx, location4, talloc_get_name(s4), + torture_assert_str_equal(location4, talloc_get_name(s4), "talloc_array_ptrtype() sets the wrong name"); talloc_free(top); + + printf("success: TALLOC PTRTYPE\n"); return true; } -static bool test_autofree(struct torture_context *tctx) +static bool test_autofree(void) { -#if _SAMBA_BUILD_>=4 - /* - * we can't run this inside smbtorture in samba4 - * as smbtorture uses talloc_autofree_context() - */ - torture_skip(tctx, - "SKIPPING TALLOC AUTOFREE CONTEXT (not supported from smbtorture)"); -#else void *p; + printf("test: TALLOC AUTOFREE CONTEXT\n"); p = talloc_autofree_context(); talloc_free(p); p = talloc_autofree_context(); talloc_free(p); -#endif + + printf("success: TALLOC AUTOFREE CONTEXT\n"); return true; } -bool torture_local_talloc(struct torture_suite *tsuite) +int main(void) { bool ret = true; talloc_disable_null_tracking(); talloc_enable_null_tracking(); - torture_suite_add_simple_test(tsuite, "SINGLE REFERENCE FREE", test_ref1); - torture_suite_add_simple_test(tsuite, "DOUBLE REFERENCE FREE", test_ref2); - torture_suite_add_simple_test(tsuite, "PARENT REFERENCE FREE", test_ref3); - torture_suite_add_simple_test(tsuite, "REFERRER REFERENCE FREE", test_ref4); - torture_suite_add_simple_test(tsuite, "UNLINK", test_unlink1); - torture_suite_add_simple_test(tsuite, "MISCELLANEOUS", test_misc); - torture_suite_add_simple_test(tsuite, "REALLOC", test_realloc); - torture_suite_add_simple_test(tsuite, "REALLOC WITH CHILD", - test_realloc_child); - torture_suite_add_simple_test(tsuite, "STEAL", test_steal); - torture_suite_add_simple_test(tsuite, "MOVE", test_move); - torture_suite_add_simple_test(tsuite, "UNREFERENCE AFTER PARENT FREED", - test_unref_reparent); - torture_suite_add_simple_test(tsuite, "talloc_realloc_fn", - test_realloc_fn); - torture_suite_add_simple_test(tsuite, "talloc type checking", test_type); - torture_suite_add_simple_test(tsuite, "TALLOC_UNLINK LOOP", test_lifeless); - torture_suite_add_simple_test(tsuite, "TALLOC LOOP DESTRUCTION", test_loop); - torture_suite_add_simple_test(tsuite, "TALLOC FREE PARENT DENY CHILD", - test_free_parent_deny_child); - torture_suite_add_simple_test(tsuite, "TALLOC PTRTYPE", - test_talloc_ptrtype); + ret &= test_ref1(); + ret &= test_ref2(); + ret &= test_ref3(); + ret &= test_ref4(); + ret &= test_unlink1(); + ret &= test_misc(); + ret &= test_realloc(); + ret &= test_realloc_child(); + ret &= test_steal(); + ret &= test_move(); + ret &= test_unref_reparent(); + ret &= test_realloc_fn(); + ret &= test_type(); + ret &= test_lifeless(); + ret &= test_loop(); + ret &= test_free_parent_deny_child(); + ret &= test_talloc_ptrtype(); if (ret) { - torture_suite_add_simple_test(tsuite, "TALLOC VS MALLOC SPEED", - test_speed); + ret &= test_speed(); } - torture_suite_add_simple_test(tsuite, "TALLOC AUTOFREE CONTEXT", - test_autofree); + ret &= test_autofree(); - return ret; -} - - - -#if _SAMBA_BUILD_<4 - int main(void) -{ - if (!torture_local_talloc(NULL)) { - printf("ERROR: TESTSUITE FAILED\n"); + if (!ret) return -1; - } return 0; } -#endif diff --git a/source4/main.mk b/source4/main.mk index 7151ebb70b..42c471da80 100644 --- a/source4/main.mk +++ b/source4/main.mk @@ -61,6 +61,7 @@ showlayout: @echo ' jsdir: $(JSDIR)' @echo ' swatdir: $(SWATDIR)' @echo ' mandir: $(MANDIR)' + @echo ' torturedir: $(TORTUREDIR)' @echo ' datadir: $(DATADIR)' @echo ' winbindd_socket_dir: $(WINBINDD_SOCKET_DIR)' @@ -105,6 +106,7 @@ installdirs: $(DESTDIR)$(BASEDIR) \ $(DESTDIR)$(BINDIR) \ $(DESTDIR)$(SBINDIR) \ + $(DESTDIR)$(TORTUREDIR) \ $(DESTDIR)$(LIBDIR) \ $(DESTDIR)$(MODULESDIR) \ $(DESTDIR)$(MANDIR) \ @@ -134,6 +136,13 @@ installbin: $(SBIN_PROGS) $(BIN_PROGS) installdirs $(DESTDIR)$(LIBDIR) \ $(DESTDIR)$(VARDIR) \ $(BIN_PROGS) + @$(SHELL) $(srcdir)/script/installbin.sh \ + $(INSTALLPERMS) \ + $(DESTDIR)$(BASEDIR) \ + $(DESTDIR)$(TORTUREDIR) \ + $(DESTDIR)$(LIBDIR) \ + $(DESTDIR)$(VARDIR) \ + $(TORTURE_PROGS) installlib: $(INSTALLABLE_SHARED_LIBS) $(STATIC_LIBS) installdirs @$(SHELL) $(srcdir)/script/installlib.sh $(DESTDIR)$(LIBDIR) "$(SHLIBEXT)" $(INSTALLABLE_SHARED_LIBS) @@ -166,6 +175,7 @@ uninstallmisc: uninstallbin: @$(SHELL) $(srcdir)/script/uninstallbin.sh $(INSTALLPERMS) $(DESTDIR)$(BASEDIR) $(DESTDIR)$(SBINDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(VARDIR) $(DESTDIR)$(SBIN_PROGS) @$(SHELL) $(srcdir)/script/uninstallbin.sh $(INSTALLPERMS) $(DESTDIR)$(BASEDIR) $(DESTDIR)$(BINDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(VARDIR) $(DESTDIR)$(BIN_PROGS) + @$(SHELL) $(srcdir)/script/uninstallbin.sh $(INSTALLPERMS) $(DESTDIR)$(BASEDIR) $(DESTDIR)$(TORTUREDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(VARDIR) $(DESTDIR)$(TORTURE_PROGS) uninstalllib: @$(SHELL) $(srcdir)/script/uninstalllib.sh $(DESTDIR)$(LIBDIR) $(SHARED_LIBS) @@ -242,7 +252,7 @@ clean:: clean_pch @echo Removing hostcc objects @-find . -name '*.ho' -exec rm -f '{}' \; @echo Removing binaries - @-rm -f $(BIN_PROGS) $(SBIN_PROGS) $(BINARIES) + @-rm -f $(BIN_PROGS) $(SBIN_PROGS) $(BINARIES) $(TORTURE_PROGS) @echo Removing libraries @-rm -f $(STATIC_LIBRARIES) $(SHARED_LIBRARIES) @-rm -f bin/*.$(SHLIBEXT)* diff --git a/source4/script/tests/mktestsetup.sh b/source4/script/tests/mktestsetup.sh index 2d3422efc5..9a8c2677be 100755 --- a/source4/script/tests/mktestsetup.sh +++ b/source4/script/tests/mktestsetup.sh @@ -105,8 +105,9 @@ cat >$CONFFILE<active_test->name); + printf("success: %s", context->active_test->name); break; case TORTURE_FAIL: - printf("failure: %s [ %s ]\n", context->active_test->name, reason); + printf("failure: %s", context->active_test->name); break; case TORTURE_TODO: - printf("todo: %s\n", context->active_test->name); + printf("todo: %s", context->active_test->name); break; case TORTURE_SKIP: - printf("skip: %s\n", context->active_test->name); + printf("skip: %s", context->active_test->name); break; } + if (reason) + printf(" [ %s ]", reason); + printf("\n"); } static void subunit_comment (struct torture_context *test, const char *comment) { - /* FIXME Add # sign before each line */ - printf("%s", comment); + fprintf(stderr, "%s", comment); } const static struct torture_ui_ops subunit_ui_ops = { @@ -438,6 +441,7 @@ const static struct torture_ui_ops quiet_ui_ops = { char **argv_new; poptContext pc; static const char *target = "other"; + const char **subunit_dir; static const char *ui_ops_name = "simple"; enum {OPT_LOADFILE=1000,OPT_UNCLIST,OPT_TIMELIMIT,OPT_DNS, OPT_DANGEROUS,OPT_SMB_PORTS,OPT_ASYNC}; @@ -525,6 +529,17 @@ const static struct torture_ui_ops quiet_ui_ops = { } torture_init(); + + subunit_dir = lp_parm_string_list(-1, "torture", "subunitdir", ":"); + if (subunit_dir == NULL) + torture_subunit_load_testsuites(dyn_TORTUREDIR); + else { + for (i = 0; subunit_dir[i]; i++) + torture_subunit_load_testsuites(subunit_dir[i]); + } + + + ldb_global_init(); if (torture_seed == 0) { diff --git a/source4/torture/subunit.c b/source4/torture/subunit.c new file mode 100644 index 0000000000..72e39101e2 --- /dev/null +++ b/source4/torture/subunit.c @@ -0,0 +1,239 @@ +/* + Unix SMB/CIFS implementation. + Run subunit tests + Copyright (C) Jelmer Vernooij 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "system/dir.h" +#include "system/network.h" +#include "system/filesys.h" +#include "torture/ui.h" +#include "torture/proto.h" + +NTSTATUS torture_register_subunit_testsuite(const char *path) +{ + struct torture_suite *suite = talloc_zero(talloc_autofree_context(), + struct torture_suite); + + suite->path = talloc_strdup(suite, path); + suite->name = talloc_strdup(suite, strrchr(path, '/')?strrchr(path, '/')+1: + path); + suite->description = talloc_asprintf(suite, "Subunit test %s", suite->name); + + return torture_register_suite(suite); +} + +int torture_subunit_load_testsuites(const char *directory) +{ + DIR *dir; + struct dirent *entry; + char *filename; + int success = 0; + + dir = opendir(directory); + if (dir == NULL) + return -1; + + while((entry = readdir(dir))) { + if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name)) + continue; + + filename = talloc_asprintf(NULL, "%s/%s", directory, entry->d_name); + + if (NT_STATUS_IS_OK(torture_register_subunit_testsuite(filename))) { + success++; + } + + talloc_free(filename); + } + + closedir(dir); + + return success; +} + +static pid_t piped_child(char* const command[], int *f_in) +{ + pid_t pid; + int sock[2]; + + if (socketpair(PF_UNIX, SOCK_STREAM, AF_LOCAL, sock) == -1) { + DEBUG(0, ("socketpair: %s", strerror(errno))); + return -1; + } + + *f_in = sock[0]; + + fcntl(sock[0], F_SETFL, O_NONBLOCK); + + pid = fork(); + + if (pid == -1) { + DEBUG(0, ("fork: %s", strerror(errno))); + return -1; + } + + if (pid == 0) { + close(0); + close(1); + close(2); + close(sock[0]); + + dup2(sock[1], 0); + dup2(sock[1], 1); + execvp(command[0], command); + exit(-1); + } + + close(sock[1]); + + return pid; +} + +enum subunit_field { SUBUNIT_TEST, SUBUNIT_SUCCESS, SUBUNIT_FAILURE, + SUBUNIT_SKIP }; + +static void run_subunit_message(struct torture_context *context, + enum subunit_field field, + const char *name, + const char *comment) +{ + struct torture_test test; + + ZERO_STRUCT(test); + test.name = name; + + switch (field) { + case SUBUNIT_TEST: + torture_ui_test_start(context, NULL, &test); + break; + case SUBUNIT_FAILURE: + context->active_test = &test; + torture_ui_test_result(context, TORTURE_FAIL, comment); + context->active_test = NULL; + break; + case SUBUNIT_SUCCESS: + context->active_test = &test; + torture_ui_test_result(context, TORTURE_OK, comment); + context->active_test = NULL; + break; + case SUBUNIT_SKIP: + context->active_test = &test; + torture_ui_test_result(context, TORTURE_SKIP, comment); + context->active_test = NULL; + break; + } +} + +bool torture_subunit_run_suite(struct torture_context *context, + struct torture_suite *suite) +{ + static char *command[2]; + int fd; + pid_t pid; + size_t size; + char *p, *q; + char *comment = NULL; + char *name = NULL; + enum subunit_field lastfield; + int status; + char buffer[4096]; + size_t offset = 0; + + command[0] = talloc_strdup(context, suite->path); + command[1] = NULL; + + pid = piped_child(command, &fd); + if (pid == -1) + return false; + + if (waitpid(pid, &status, 0) == -1) { + torture_comment(context, "waitpid(%d) failed\n", pid); + return false; + } + + if (WEXITSTATUS(status) != 0) { + torture_comment(context, "failed with status %d\n", WEXITSTATUS(status)); + return false; + } + + while ((size = read(fd, buffer+offset, sizeof(buffer-offset) > 0))) { + char *eol; + buffer[offset+size] = '\0'; + + for (p = buffer; p; p = eol+1) { + eol = strchr(p, '\n'); + if (eol == NULL) + break; + + *eol = '\0'; + + if (comment != NULL && strcmp(p, "]") == 0) { + run_subunit_message(context, lastfield, name, comment); + talloc_free(name); name = NULL; + talloc_free(comment); comment = NULL; + } else if (comment != NULL) { + comment = talloc_append_string(context, comment, p); + } else { + q = strchr(p, ':'); + if (q == NULL) { + torture_comment(context, "Invalid line `%s'\n", p); + continue; + } + + *q = '\0'; + if (!strcmp(p, "test")) { + lastfield = SUBUNIT_TEST; + } else if (!strcmp(p, "failure")) { + lastfield = SUBUNIT_FAILURE; + } else if (!strcmp(p, "success")) { + lastfield = SUBUNIT_SUCCESS; + } else if (!strcmp(p, "skip")) { + lastfield = SUBUNIT_SKIP; + } else { + torture_comment(context, "Invalid subunit field `%s'\n", p); + continue; + } + + p = q+1; + + name = talloc_strdup(context, p+1); + + q = strrchr(p, '['); + if (q != NULL) { + *q = '\0'; + comment = talloc_strdup(context, ""); + } else { + run_subunit_message(context, lastfield, name, NULL); + talloc_free(name); + name = NULL; + } + } + } + + offset += size-(p-buffer); + memcpy(buffer, p, offset); + } + + if (name != NULL) { + torture_comment(context, "Interrupted during %s\n", name); + return false; + } + + return true; +} diff --git a/source4/torture/ui.c b/source4/torture/ui.c index c105f4ec9d..32b632a3e8 100644 --- a/source4/torture/ui.c +++ b/source4/torture/ui.c @@ -21,6 +21,7 @@ #include "includes.h" #include "torture/ui.h" +#include "torture/torture.h" #include "lib/util/dlinklist.h" void torture_comment(struct torture_context *context, @@ -67,7 +68,7 @@ void _torture_skip_ext(struct torture_context *context, struct torture_suite *torture_suite_create(TALLOC_CTX *ctx, const char *name) { - struct torture_suite *suite = talloc(ctx, struct torture_suite); + struct torture_suite *suite = talloc_zero(ctx, struct torture_suite); suite->name = talloc_strdup(suite, name); suite->testcases = NULL; @@ -146,6 +147,9 @@ BOOL torture_run_suite(struct torture_context *context, if (context->ui_ops->suite_start) context->ui_ops->suite_start(context, suite); + if (suite->path) + torture_subunit_run_suite(context, suite); + for (tcase = suite->testcases; tcase; tcase = tcase->next) { ret &= torture_run_tcase(context, tcase); } @@ -162,6 +166,30 @@ BOOL torture_run_suite(struct torture_context *context, return ret; } +void torture_ui_test_start(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test) +{ + if (context->ui_ops->test_start) + context->ui_ops->test_start(context, tcase, test); +} + +void torture_ui_test_result(struct torture_context *context, + enum torture_result result, + const char *comment) +{ + if (context->ui_ops->test_result) + context->ui_ops->test_result(context, result, comment); + + + switch (result) { + case TORTURE_SKIP: context->success++; break; + case TORTURE_FAIL: context->failed++; break; + case TORTURE_TODO: context->todo++; break; + case TORTURE_OK: context->success++; break; + } +} + static BOOL internal_torture_run_test(struct torture_context *context, struct torture_tcase *tcase, struct torture_test *test, @@ -182,8 +210,7 @@ static BOOL internal_torture_run_test(struct torture_context *context, context->active_tcase = tcase; context->active_test = test; - if (context->ui_ops->test_start) - context->ui_ops->test_start(context, tcase, test); + torture_ui_test_start(context, tcase, test); context->last_reason = NULL; context->last_result = TORTURE_OK; @@ -195,19 +222,8 @@ static BOOL internal_torture_run_test(struct torture_context *context, context->last_result = TORTURE_FAIL; } - if (context->ui_ops->test_result) - context->ui_ops->test_result(context, - context->last_result, - context->last_reason); - - - switch (context->last_result) { - case TORTURE_SKIP: context->success++; break; - case TORTURE_FAIL: context->failed++; break; - case TORTURE_TODO: context->todo++; break; - case TORTURE_OK: context->success++; break; - } - + torture_ui_test_result(context, context->last_result, context->last_reason); + talloc_free(context->last_reason); context->active_test = NULL; diff --git a/source4/torture/ui.h b/source4/torture/ui.h index 36457e6a84..b4e3585031 100644 --- a/source4/torture/ui.h +++ b/source4/torture/ui.h @@ -52,6 +52,14 @@ struct torture_ui_ops enum torture_result, const char *reason); }; +void torture_ui_test_start(struct torture_context *context, + struct torture_tcase *tcase, + struct torture_test *test); + +void torture_ui_test_result(struct torture_context *context, + enum torture_result result, + const char *comment); + /* * Holds information about a specific run of the testsuite. * The data in this structure should be considered private to @@ -121,6 +129,7 @@ struct torture_tcase { struct torture_suite { const char *name; + const char *path; /* Used by subunit tests only */ const char *description; struct torture_tcase *testcases; struct torture_suite *children; -- cgit