s4-torture: add smb2 nfs testing suite
authorGünther Deschner <gd@samba.org>
Thu, 9 Nov 2023 22:22:42 +0000 (23:22 +0100)
committerGünther Deschner <gd@samba.org>
Tue, 21 Nov 2023 12:40:12 +0000 (13:40 +0100)
This testsuite allows to explore filesystem behavior when data is shared
via NFS and SMB concurrently. It requires libnfs-devel to be installed.

For testing an export like /opt/test add this to Samba's /etc/samba/smb.conf:

[test]
        path = /opt/test
        read only = No

And this to NFS Ganesha's /etc/ganesha/ganesha.conf:

EXPORT
{
        Export_Id = 1;
        Path = /opt/test;
        Pseudo = /opt/test;
        Sectype = sys,krb5,krb5i,krb5p;
        Protocols = 3,4;
        Access_Type = RW;

        FSAL {
                Name = VFS;
        }

        CLIENT {
                Clients=*;
                Protocols=3,4;
        }
}

Run the testsuite like this:

smbtorture //192.168.3.1/test -U smbuser%password smb2.nfs --option=torture:nfs_path=/opt/test --option=torture:nfs_version=4

Guenther

Signed-off-by: Guenther Deschner <gd@samba.org>
source4/torture/nfs/nfs.c [new file with mode: 0644]
source4/torture/nfs/wscript [new file with mode: 0644]
source4/torture/smb2/smb2.c
source4/torture/wscript_build
wscript

diff --git a/source4/torture/nfs/nfs.c b/source4/torture/nfs/nfs.c
new file mode 100644 (file)
index 0000000..4e16783
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * test SMB2 and NFS interop
+ *
+ * Copyright (C) Guenther Deschner 2023
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "libcli/smb2/smb2.h"
+#include "libcli/smb2/smb2_calls.h"
+#include "torture/torture.h"
+#include "torture/util.h"
+#include "torture/smbtorture.h"
+#include "torture/smb2/proto.h"
+#include "libcli/security/security.h"
+#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/ndr_ioctl.h"
+#include "../libcli/smb/smbXcli_base.h"
+#include "lib/cmdline/cmdline.h"
+#include "libcli/security/security.h"
+#include "libcli/resolve/resolve.h"
+#include "lib/socket/socket.h"
+#include "lib/param/param.h"
+#include "lib/events/events.h"
+#include "../smb2/oplock_break_handler.h"
+#include "../smb2/lease_break_handler.h"
+#include "torture/smb2/block.h"
+
+#ifdef HAVE_NFSC_LIBNFS_H
+#include <nfsc/libnfs.h>
+#endif
+#ifdef HAVE_NFSC_LIBNFS_ZDR_H
+#include <nfsc/libnfs-zdr.h>
+#endif
+#ifdef HAVE_LINUX_NFS_H
+#include <linux/nfs.h>
+#endif
+
+#define BASEDIR "smbtorture-nfs"
+
+struct test_nfs_context {
+       struct nfs_context *nfs;
+       const char *host;
+       struct {
+               struct nfs_context *nfs;
+               const char *nfs_host;
+               const char *nfs_path;
+               struct AUTH *nfs_auth;
+               int nfs_version;
+       } n;
+       struct {
+               struct smb2_tree *tree;
+               const char *smb_host;
+               const char *smb_share;
+       } s;
+};
+
+#define torture_assert_nfs_equal(torture_ctx,got,expected,cmt)\
+       do { int __got = (got), __expected = (expected); \
+       if (__got != __expected) { \
+               torture_result(torture_ctx, TORTURE_FAIL, \
+                       __location__": result was %d, errno %d (%s), expected %d: %s (NFS error: %s): %s", \
+                                       __got, errno, strerror(errno), \
+                                       __expected, strerror(__expected), \
+                                       nfs_get_error(t->nfs), cmt); \
+               return false; \
+       } \
+       } while(0)
+
+#define torture_assert_nfs_ok(torture_ctx,got,cmt)\
+       torture_assert_nfs_equal(torture_ctx,got,0,cmt);
+
+static bool torture_nfs_teardown_common(struct torture_context *tctx,
+                                       struct test_nfs_context *t)
+{
+       torture_assert_nfs_ok(tctx,
+               nfs_umount(t->nfs),
+               talloc_asprintf(tctx, "Failed to unmount nfs path: //%s/%s",
+                       t->n.nfs_host, t->n.nfs_path));
+
+       nfs_destroy_context(t->nfs);
+
+       return true;
+}
+
+static bool torture_nfs_teardown(struct torture_context *tctx,
+                                void *data)
+{
+       struct test_nfs_context *t = talloc_get_type(data, struct test_nfs_context);
+       bool ret;
+
+       ret = torture_nfs_teardown_common(tctx, t);
+       talloc_free(t);
+
+       return ret;
+}
+
+static bool torture_nfs_setup_common(struct torture_context *tctx,
+                                    struct test_nfs_context *t)
+{
+       t->n.nfs_host = torture_setting_string(tctx, "nfs_host",
+                       torture_setting_string(tctx, "host", NULL));
+       t->n.nfs_path = torture_setting_string(tctx, "nfs_path", NULL);
+       t->n.nfs_version = torture_setting_int(tctx, "nfs_version", 4);
+
+       torture_assert(tctx,
+               t->n.nfs_path,
+               "Please define NFS path via \"--option=torture:nfs_path=/my/path\"");
+
+       t->nfs = t->n.nfs = nfs_init_context();
+       torture_assert(tctx, t->n.nfs, "failed to init NFS context");
+
+       nfs_set_debug(t->nfs, torture_setting_int(tctx, "nfs_debug", 0));
+
+       torture_assert_nfs_ok(tctx,
+               nfs_set_version(t->nfs, t->n.nfs_version),
+               "failed to set NFS version");
+
+#if 0
+       auth = libnfs_authunix_create_default();
+       auth = libnfs_authnone_create();
+#endif
+       t->n.nfs_auth = libnfs_authunix_create("localhorst", /* host */
+                              torture_setting_int(tctx, "nfs_auth_uid", 0),
+                              torture_setting_int(tctx, "nfs_auth_gid", 0),
+                              0, /* num_groups */
+                              NULL /* groups */);
+       torture_assert(tctx, t->n.nfs_auth, "failed to create auth");
+
+       nfs_set_auth(t->n.nfs, t->n.nfs_auth);
+
+       torture_comment(tctx,
+               "Establishing connection to %s using NFSv%d\n",
+               t->n.nfs_host, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mount(t->nfs, t->n.nfs_host, t->n.nfs_path),
+               talloc_asprintf(tctx, "Failed to mount NFS path: //%s/%s",
+                       t->n.nfs_host, t->n.nfs_path));
+
+       nfs_rmdir(t->nfs, BASEDIR);
+
+       return true;
+}
+
+static bool torture_nfs_setup(struct torture_context *tctx,
+                                  void **data)
+{
+       struct test_nfs_context *t;
+
+       *data = t = talloc_zero(tctx, struct test_nfs_context);
+
+       return torture_nfs_setup_common(tctx, t);
+}
+
+static bool torture_nfs_smb_teardown_common(struct torture_context *tctx,
+                                           struct test_nfs_context *t)
+{
+       talloc_free(t->s.tree);
+
+       return true;
+}
+
+static bool torture_nfs_smb_teardown(struct torture_context *tctx,
+                                    void *data)
+{
+       struct test_nfs_context *t = talloc_get_type(data, struct test_nfs_context);
+       bool ret;
+
+       torture_assert_goto(tctx,
+               torture_nfs_teardown_common(tctx, t),
+               ret, done,
+               "NFS teardown failed");
+
+       torture_assert_goto(tctx,
+               torture_nfs_smb_teardown_common(tctx, t),
+               ret, done,
+               "SMB teardown failed");
+ done:
+       talloc_free(t);
+
+       return ret;
+}
+
+static bool torture_nfs_smb_setup_common(struct torture_context *tctx,
+                                        struct test_nfs_context *t)
+{
+       t->s.smb_host = torture_setting_string(tctx, "host", NULL);
+       t->s.smb_share = torture_setting_string(tctx, "share", NULL);
+
+       torture_comment(tctx,
+               "Establishing connection to %s using SMB2\n",
+               t->s.smb_host);
+
+       torture_assert(tctx,
+               torture_smb2_connection(tctx, &t->s.tree),
+               talloc_asprintf(tctx, "Failed to mount SMB share: //%s/%s",
+                       t->s.smb_host, t->s.smb_share));
+
+       return true;
+}
+
+static bool torture_nfs_smb_setup(struct torture_context *tctx,
+                                  void **data)
+{
+       struct test_nfs_context *t;
+       bool ok;
+
+       *data = t = talloc_zero(tctx, struct test_nfs_context);
+
+       ok = torture_nfs_setup_common(tctx, t);
+       if (!ok) {
+               return false;
+       }
+       ok = torture_nfs_smb_setup_common(tctx, t);
+       if (!ok) {
+               return false;
+       }
+
+       return true;
+}
+
+/****************************************************************
+ very simple NFS test:
+ * mkdir(dir)
+ * open(file)
+ * close(file)
+ * unlink(file)
+ * rmdir(dir)
+****************************************************************/
+
+static bool test_nfs_simple(struct torture_context *tctx,
+                           void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct nfsfh *nfsfh = NULL;
+       const char *fname = BASEDIR"/testfile";
+
+       torture_comment(tctx, "Testing [%s/%s] using NFSv%d\n",
+               t->n.nfs_host, t->n.nfs_path, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_open(t->nfs, fname, O_CREAT | O_RDWR, &nfsfh),
+               "Failed to open file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_close(t->nfs, nfsfh),
+               "Failed to close file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_unlink(t->nfs, fname),
+               "Failed to unlink file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               "Failed to remove directory");
+
+       return ret;
+}
+
+/****************************************************************
+ very simple NFS test with error checks on repeats:
+ * mkdir(dir)
+ * mkdir(dir) -> -NFSERR_EXIST
+ * open(file)
+ * close(file)
+ * close(file) -> crash in libnfs currently
+ * unlink(file)
+ * unlink(file) -> -NFSERR_NOENT
+ * rmdir(dir)
+ * rmdir(dir) -> -NFSERR_NOENT
+****************************************************************/
+
+static bool test_nfs_simple_errors(struct torture_context *tctx,
+                                  void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct nfsfh *nfsfh = NULL;
+       const char *fname = BASEDIR"/testfile";
+
+       torture_comment(tctx, "Testing [%s/%s] using NFSv%d\n",
+               t->n.nfs_host, t->n.nfs_path, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_nfs_equal(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               -NFSERR_EXIST,
+               "Failed to create directory");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_open(t->nfs, fname, O_CREAT | O_RDWR, &nfsfh),
+               "Failed to open file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_close(t->nfs, nfsfh),
+               "Failed to close file");
+#if 0
+       /* crash bug in libnfs */
+
+       ZERO_STRUCT(nfsfh);
+
+       torture_assert_nfs_equal(tctx,
+               nfs_close(t->nfs, nfsfh),
+               -1,
+               "Failed to close file");
+#endif
+       torture_assert_nfs_ok(tctx,
+               nfs_unlink(t->nfs, fname),
+               "Failed to unlink file");
+
+       torture_assert_nfs_equal(tctx,
+               nfs_unlink(t->nfs, fname),
+               -NFSERR_NOENT,
+               "Failed to unlink file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               "Failed to remove directory");
+
+       torture_assert_nfs_equal(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               -NFSERR_NOENT,
+               "Failed to remove directory");
+
+       return ret;
+}
+
+/****************************************************************
+ very simple SMB test:
+ * mkdir(dir)
+ * open(file)
+ * close(file)
+ * unlink(file)
+ * rmdir(dir)
+****************************************************************/
+
+static bool test_nfs_simple_smb(struct torture_context *tctx,
+                               void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct smb2_handle smbfh;
+       const char *fname = BASEDIR"\\testfile";
+
+       torture_comment(tctx, "Testing [%s/%s] using SMB2\n",
+               t->s.smb_host, t->s.smb_share);
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_mkdir(t->s.tree, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_ntstatus_ok(tctx,
+               torture_smb2_testfile(t->s.tree, fname, &smbfh),
+               "Failed to open file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_close(t->s.tree, smbfh),
+               "Failed to close file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_unlink(t->s.tree, fname),
+               "Failed to unlink file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_rmdir(t->s.tree, BASEDIR),
+               "Failed to remove directory");
+
+       return ret;
+}
+
+/****************************************************************
+ very simple mixed NFS/SMB test:
+ * NFS: mkdir(dir)
+ * SMB: open(file)
+ * SMB: close(file)
+ * SMB: unlink(file)
+ * NFS: rmdir(dir)
+****************************************************************/
+
+static bool test_nfs_mix_smb(struct torture_context *tctx,
+                            void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct smb2_handle smbfh;
+
+       torture_comment(tctx, "Testing [%s/%s] using NFSv%d and SMB2\n",
+               t->s.smb_host, t->s.smb_share, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_ntstatus_ok_goto(tctx,
+               torture_smb2_testfile(t->s.tree, BASEDIR"\\testfile", &smbfh),
+               ret, done,
+               "Failed to open file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_close(t->s.tree, smbfh),
+               "Failed to close file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_unlink(t->s.tree, BASEDIR"\\testfile"),
+               "Failed to unlink file");
+ done:
+       torture_assert_nfs_ok(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               "Failed to remove directory");
+
+       return ret;
+}
+
+/****************************************************************
+ very simple mixed NFS/SMB test with I/O:
+ * NFS: mkdir(dir)
+ * SMB: open(file)
+ * SMB: write(file)
+ * SMB: close(file)
+ * NFS: open(file)
+ * NFS: read(file)
+ * NFS: close(file)
+ * SMB: unlink(file)
+ * NFS: rmdir(dir)
+****************************************************************/
+
+static bool test_nfs_mix_smb_with_io(struct torture_context *tctx,
+                                    void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct smb2_handle smbfh;
+       struct nfsfh *nfsfh;
+       DATA_BLOB blob_in, blob_out;
+       const char *str = "Hello other protocol!";
+       const char *fname = BASEDIR"/testfile";
+
+       torture_comment(tctx, "Testing [%s/%s] using NFSv%d and SMB2\n",
+               t->s.smb_host, t->s.smb_share, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_ntstatus_ok_goto(tctx,
+               torture_smb2_testfile(t->s.tree, BASEDIR"\\testfile", &smbfh),
+               ret, done,
+               "Failed to open file");
+
+       blob_in = data_blob_string_const(str);
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_write(t->s.tree, smbfh, blob_in.data, 0, blob_in.length),
+               "Failed to write file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_close(t->s.tree, smbfh),
+               "Failed to close file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_open(t->nfs, fname, O_RDONLY, &nfsfh),
+               "Failed to open file");
+
+       blob_out = data_blob_talloc(tctx, NULL, 0xff);
+
+       blob_out.length = nfs_read(t->nfs, nfsfh, 0xff, blob_out.data);
+
+       torture_assert_nfs_ok(tctx,
+               (blob_out.length < 0),
+               "Failed to read file");
+
+       dump_data(0, blob_in.data, blob_in.length);
+       dump_data(0, blob_out.data, blob_out.length);
+
+       torture_assert_data_blob_equal(tctx, blob_in, blob_out,
+               "Failed to compare written and read content");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_close(t->nfs, nfsfh),
+               "Failed to close file");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_unlink(t->s.tree, BASEDIR"\\testfile"),
+               "Failed to unlink file");
+ done:
+       torture_assert_nfs_ok(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               "Failed to remove directory");
+
+       return ret;
+}
+
+/****************************************************************
+ very simple mixed NFS/SMB test with I/O:
+ * NFS: mkdir(dir)
+ * SMB: open(file)
+ * SMB: write(file)
+ * NFS: unlink(file)
+ * NFS: unlink(file) -> fails
+ * NFS: open(file) -> fails
+ * SMB: read(file) -> succeeds?
+ * SMB: close(file) -> succeeds?
+ * SMB: unlink(file) -> fails
+ * NFS: rmdir(dir)
+****************************************************************/
+
+static bool test_nfs_mix_smb_with_io_and_unlink(struct torture_context *tctx,
+                                               void *private_data)
+{
+       struct test_nfs_context *t =
+               talloc_get_type_abort(private_data, struct test_nfs_context);
+
+       bool ret = true;
+       struct smb2_handle smbfh;
+       struct nfsfh *nfsfh;
+       DATA_BLOB blob_in;
+       const char *str = "Hello other protocol!";
+       const char *fname = BASEDIR"/testfile";
+       struct smb2_read rd;
+
+       torture_comment(tctx, "Testing [%s/%s] using NFSv%d and SMB2\n",
+               t->s.smb_host, t->s.smb_share, t->n.nfs_version);
+
+       torture_assert_nfs_ok(tctx,
+               nfs_mkdir(t->nfs, BASEDIR),
+               "Failed to create directory");
+
+       torture_assert_ntstatus_ok_goto(tctx,
+               torture_smb2_testfile(t->s.tree, BASEDIR"\\testfile", &smbfh),
+               ret, done,
+               "Failed to open file");
+
+       blob_in = data_blob_string_const(str);
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_write(t->s.tree, smbfh, blob_in.data, 0, blob_in.length),
+               "Failed to write file");
+
+       torture_assert_nfs_ok(tctx,
+               nfs_unlink(t->nfs, fname),
+               "Failed to unlink file");
+
+       torture_assert_nfs_equal(tctx,
+               nfs_unlink(t->nfs, fname),
+               -NFSERR_NOENT,
+               "Failed to unlink file");
+
+       torture_assert_nfs_equal(tctx,
+               nfs_open(t->nfs, fname, O_RDONLY, &nfsfh),
+               -NFSERR_NOENT,
+               "Failed to open file");
+
+       ZERO_STRUCT(rd);
+       rd.in.file.handle = smbfh;
+       rd.in.length      = 0xff;
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_read(t->s.tree, tctx, &rd),
+               "failed to read file");
+
+       dump_data(0, rd.out.data.data, rd.out.data.length);
+
+       torture_assert_data_blob_equal(tctx, blob_in, rd.out.data,
+               "Failed to compare written and read content");
+
+       torture_assert_ntstatus_ok(tctx,
+               smb2_util_close(t->s.tree, smbfh),
+               "Failed to close file");
+
+       torture_assert_ntstatus_equal(tctx,
+               smb2_util_unlink(t->s.tree, BASEDIR"\\testfile"),
+               NT_STATUS_OBJECT_NAME_NOT_FOUND,
+               "Failed to unlink file");
+ done:
+       torture_assert_nfs_ok(tctx,
+               nfs_rmdir(t->nfs, BASEDIR),
+               "Failed to remove directory");
+
+       return ret;
+}
+
+NTSTATUS torture_nfs_init(TALLOC_CTX *ctx);
+NTSTATUS torture_nfs_init(TALLOC_CTX *ctx)
+{
+       struct torture_suite *suite = torture_suite_create(ctx, "nfs");
+       struct torture_tcase *tcase;
+
+       tcase = torture_suite_add_tcase(suite, "sync_nfs");
+
+       torture_tcase_set_fixture(tcase,
+                                 torture_nfs_setup,
+                                 torture_nfs_teardown);
+
+       torture_tcase_add_simple_test(tcase,
+                                     "simple",
+                                     test_nfs_simple);
+       torture_tcase_add_simple_test(tcase,
+                                     "simple_errors",
+                                     test_nfs_simple_errors);
+
+       tcase = torture_suite_add_tcase(suite, "sync_nfs_smb");
+
+       torture_tcase_set_fixture(tcase,
+                                 torture_nfs_smb_setup,
+                                 torture_nfs_smb_teardown);
+
+       torture_tcase_add_simple_test(tcase,
+                                     "simple_smb",
+                                     test_nfs_simple_smb);
+       torture_tcase_add_simple_test(tcase,
+                                     "mix_smb",
+                                     test_nfs_mix_smb);
+       torture_tcase_add_simple_test(tcase,
+                                     "mix_smb_with_io",
+                                     test_nfs_mix_smb_with_io);
+       torture_tcase_add_simple_test(tcase,
+                                     "mix_smb_with_io_and_unlink",
+                                     test_nfs_mix_smb_with_io_and_unlink);
+#if 0
+       tcase = torture_suite_add_tcase(suite, "async");
+
+       torture_tcase_set_fixture(tcase,
+                                 torture_nfs_setup,
+                                 torture_nfs_teardown);
+
+       torture_tcase_add_simple_test(tcase,
+                                     "simple_async",
+                                     test_nfs_simple_async);
+#endif
+       suite->description = talloc_strdup(suite, "NFS tests");
+
+       torture_register_suite(ctx, suite);
+
+       return NT_STATUS_OK;
+}
diff --git a/source4/torture/nfs/wscript b/source4/torture/nfs/wscript
new file mode 100644 (file)
index 0000000..d577ef4
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+import sys
+from waflib import Logs, Options
+import samba3
+
+def configure(conf):
+    conf.CHECK_CFG(package='libnfs', args='--cflags --libs',
+                   msg='Checking for libnfs package')
+    conf.CHECK_HEADERS('nfsc/libnfs.h', lib='nfs')
+    conf.CHECK_HEADERS('nfsc/libnfs-zdr.h', lib='nfs')
+    conf.CHECK_LIB('nfs', shlib=True)
+    conf.CHECK_HEADERS('linux/nfs.h')
+
index 5b6477e47bc3f1a3e24a9ffcf1387923b454d3f5..a8c20a8e14674e86187014a546c1d1e163192fad 100644 (file)
@@ -221,7 +221,6 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
        torture_suite_add_suite(suite, torture_smb2_deny_init(suite));
        torture_suite_add_suite(suite, torture_smb2_ea(suite));
        torture_suite_add_suite(suite, torture_smb2_create_no_streams_init(suite));
-
        suite->description = talloc_strdup(suite, "SMB2-specific tests");
 
        torture_register_suite(ctx, suite);
index 1ddce713dfb90ca97455c35b07d000886da8697e..d0d80b7d27ec77029c99f695095455cfff22d4ce 100644 (file)
@@ -308,7 +308,24 @@ bld.SAMBA_MODULE('TORTURE_VFS',
        init_function='torture_vfs_init'
        )
 
-TORTURE_MODULES = 'TORTURE_BASIC TORTURE_RAW torture_rpc TORTURE_RAP TORTURE_AUTH TORTURE_NBENCH TORTURE_UNIX TORTURE_LDAP TORTURE_NBT TORTURE_NET TORTURE_NTP torture_registry TORTURE_VFS'
+nfs_specific = dict(source='', deps='')
+
+if bld.CONFIG_GET('HAVE_LIBNFS'):
+       nfs_specific['source'] += ' nfs/nfs.c'
+       nfs_specific['deps'] += ' nfs'
+
+bld.SAMBA_MODULE('TORTURE_NFS',
+                 source='''
+                        ''' + nfs_specific['source'],
+                 autoproto='nfs/proto.h',
+                 subsystem='smbtorture',
+                 init_function='torture_nfs_init',
+                 deps='''
+                      LIBCLI_SMB TORTURE_UTIL smbclient-raw TORTURE_RAW
+                      ''' + nfs_specific['deps'],
+                 internal_module=True)
+
+TORTURE_MODULES = 'TORTURE_BASIC TORTURE_RAW torture_rpc TORTURE_RAP TORTURE_AUTH TORTURE_NBENCH TORTURE_UNIX TORTURE_LDAP TORTURE_NBT TORTURE_NET TORTURE_NTP torture_registry TORTURE_VFS TORTURE_NFS'
 
 bld.SAMBA_SUBSYSTEM('torturemain',
                     source='smbtorture.c torture.c shell.c',
diff --git a/wscript b/wscript
index f144d9a421c9f0e127aed5b40a0e7f95d6eb16b9..d5de9cca27029862f1e4e9dd5a99c7b7d0b6187f 100644 (file)
--- a/wscript
+++ b/wscript
@@ -319,6 +319,7 @@ def configure(conf):
 
     conf.RECURSE('source4/dsdb/samdb/ldb_modules')
     conf.RECURSE('source4/ntvfs/sysdep')
+    conf.RECURSE('source4/torture/nfs')
     conf.RECURSE('lib/util')
     conf.RECURSE('lib/util/charset')
     conf.RECURSE('source4/auth')