r26238: Add a loadparm context parameter to torture_context, remove more uses of...
[gd/samba-autobuild/.git] / source4 / torture / raw / lock.c
index 547115c9f5e8b1c0a495ea330454128ee1bc6057..6eb43bd538e7d1392b5ebf12b988f039268f9103 100644 (file)
@@ -5,7 +5,7 @@
    
    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
+   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,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "torture/torture.h"
 #include "libcli/raw/libcliraw.h"
 #include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "libcli/composite/composite.h"
+#include "libcli/smb_composite/smb_composite.h"
+#include "lib/cmdline/popt_common.h"
+#include "param/param.h"
 
 #define CHECK_STATUS(status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
                printf("(%s) Incorrect status %s - should be %s\n", \
                       __location__, nt_errstr(status), nt_errstr(correct)); \
-               ret = False; \
-               goto done; \
-       }} while (0)
-
-#define CHECK_VALUE(v, correct) do { \
-       if ((v) != (correct)) { \
-               printf("(%s) Incorrect value %s=%d - should be %d\n", \
-                      __location__, #v, v, correct); \
-               ret = False; \
+               ret = false; \
                goto done; \
        }} while (0)
 
 /*
   test SMBlock and SMBunlock ops
 */
-static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_lock(struct torture_context *tctx, struct smbcli_state *cli)
 {
        union smb_lock io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
        const char *fname = BASEDIR "\\test.txt";
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Testing RAW_LOCK_LOCK\n");
@@ -62,13 +61,13 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        printf("Trying 0/0 lock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 0;
        io.lock.in.offset = 0;
        status = smb_raw_lock(cli->tree, &io);
@@ -83,7 +82,7 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying 0/1 lock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 1;
        io.lock.in.offset = 0;
        status = smb_raw_lock(cli->tree, &io);
@@ -101,7 +100,7 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying 0xEEFFFFFF lock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 4000;
        io.lock.in.offset = 0xEEFFFFFF;
        status = smb_raw_lock(cli->tree, &io);
@@ -119,7 +118,7 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying 0xEF000000 lock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 4000;
        io.lock.in.offset = 0xEEFFFFFF;
        status = smb_raw_lock(cli->tree, &io);
@@ -137,7 +136,7 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying max lock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 4000;
        io.lock.in.offset = 0xEF000000;
        status = smb_raw_lock(cli->tree, &io);
@@ -155,7 +154,7 @@ static BOOL test_lock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying wrong pid unlock\n");
        io.lock.level = RAW_LOCK_LOCK;
-       io.lock.in.fnum = fnum;
+       io.lock.in.file.fnum = fnum;
        io.lock.in.count = 4002;
        io.lock.in.offset = 10001;
        status = smb_raw_lock(cli->tree, &io);
@@ -179,17 +178,17 @@ done:
 /*
   test locking&X ops
 */
-static BOOL test_lockx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_lockx(struct torture_context *tctx, struct smbcli_state *cli)
 {
        union smb_lock io;
        struct smb_lock_entry lock[1];
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
        const char *fname = BASEDIR "\\test.txt";
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Testing RAW_LOCK_LOCKX\n");
@@ -198,12 +197,12 @@ static BOOL test_lockx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = fnum;
+       io.lockx.in.file.fnum = fnum;
        io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 0;
@@ -358,18 +357,19 @@ done:
 /*
   test high pid
 */
-static BOOL test_pidhigh(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_pidhigh(struct torture_context *tctx, 
+                                                struct smbcli_state *cli)
 {
        union smb_lock io;
        struct smb_lock_entry lock[1];
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
        const char *fname = BASEDIR "\\test.txt";
-       char c = 1;
+       uint8_t c = 1;
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Testing high pid\n");
@@ -380,18 +380,18 @@ static BOOL test_pidhigh(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        if (smbcli_write(cli->tree, fnum, 0, &c, 0, 1) != 1) {
                printf("Failed to write 1 byte - %s\n", smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = fnum;
+       io.lockx.in.file.fnum = fnum;
        io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 0;
@@ -405,7 +405,7 @@ static BOOL test_pidhigh(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
                printf("Failed to read 1 byte - %s\n", smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -415,7 +415,7 @@ static BOOL test_pidhigh(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        if (smbcli_read(cli->tree, fnum, &c, 0, 1) == 1) {
                printf("pid is incorrect handled for read with lock!\n");
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -423,7 +423,7 @@ static BOOL test_pidhigh(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        if (smbcli_read(cli->tree, fnum, &c, 0, 1) != 1) {
                printf("High pid is used on this server!\n");
-               ret = False;
+               ret = false;
        } else {
                printf("High pid is not used on this server (correct)\n");
        }
@@ -439,33 +439,39 @@ done:
 /*
   test locking&X async operation
 */
-static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_async(struct torture_context *tctx, 
+                                          struct smbcli_state *cli)
 {
+       struct smbcli_session *session;
+       struct smb_composite_sesssetup setup;
+       struct smbcli_tree *tree;
+       union smb_tcon tcon;
+       const char *host, *share;
        union smb_lock io;
        struct smb_lock_entry lock[2];
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
        const char *fname = BASEDIR "\\test.txt";
        time_t t;
        struct smbcli_request *req;
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Testing LOCKING_ANDX_CANCEL_LOCK\n");
        io.generic.level = RAW_LOCK_LOCKX;
-       
+
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = fnum;
+       io.lockx.in.file.fnum = fnum;
        io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 0;
@@ -486,7 +492,7 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        req = smb_raw_lock_send(cli->tree, &io);
        if (req == NULL) {
                printf("Failed to setup timed lock (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -495,14 +501,14 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.lockx.in.timeout = 0;
        io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
        status = smb_raw_lock(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+       CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
 
        /* cancel with the wrong bits set */
        lock[0].offset = 100;
        io.lockx.in.timeout = 0;
        io.lockx.in.mode = LOCKING_ANDX_CANCEL_LOCK;
        status = smb_raw_lock(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+       CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
 
        /* cancel the right range */
        lock[0].offset = 100;
@@ -517,7 +523,7 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        if (time(NULL) > t+2) {
                printf("lock cancel was not immediate (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -533,7 +539,7 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        req = smb_raw_lock_send(cli->tree, &io);
        if (req == NULL) {
                printf("Failed to setup timed lock (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -542,16 +548,17 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_lock(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
+       t = time(NULL);
        status = smbcli_request_simple_recv(req);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        if (time(NULL) > t+2) {
-               printf("lock cancel by unlock was not immediate (%s)\n", __location__);
-               ret = False;
+               printf("lock cancel by unlock was not immediate (%s) - took %d secs\n", 
+                      __location__, (int)(time(NULL)-t));
+               ret = false;
                goto done;
        }
 
-
        printf("testing cancel by close\n");
        io.lockx.in.ulock_cnt = 0;
        io.lockx.in.lock_cnt = 1;
@@ -560,28 +567,684 @@ static BOOL test_async(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_lock(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
 
+       t = time(NULL);
        io.lockx.in.timeout = 10000;
        req = smb_raw_lock_send(cli->tree, &io);
        if (req == NULL) {
                printf("Failed to setup timed lock (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
-       smbcli_close(cli->tree, fnum);
+       status = smbcli_close(cli->tree, fnum);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
        status = smbcli_request_simple_recv(req);
        CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
 
        if (time(NULL) > t+2) {
-               printf("lock cancel by unlock was not immediate (%s)\n", __location__);
-               ret = False;
+               printf("lock cancel by close was not immediate (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       printf("create a new sessions\n");
+       session = smbcli_session_init(cli->transport, tctx, false);
+       setup.in.sesskey = cli->transport->negotiate.sesskey;
+       setup.in.capabilities = cli->transport->negotiate.capabilities;
+       setup.in.workgroup = lp_workgroup(tctx->lp_ctx);
+       setup.in.credentials = cmdline_credentials;
+       status = smb_composite_sesssetup(session, &setup);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       session->vuid = setup.out.vuid;
+
+       printf("create new tree context\n");
+       share = torture_setting_string(tctx, "share", NULL);
+       host  = torture_setting_string(tctx, "host", NULL);
+       tree = smbcli_tree_init(session, tctx, false);
+       tcon.generic.level = RAW_TCON_TCONX;
+       tcon.tconx.in.flags = 0;
+       tcon.tconx.in.password = data_blob(NULL, 0);
+       tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
+       tcon.tconx.in.device = "A:";
+       status = smb_raw_tcon(tree, tctx, &tcon);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       tree->tid = tcon.tconx.out.tid;
+
+       printf("testing cancel by exit\n");
+       fname = BASEDIR "\\test_exit.txt";
+       fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       io.lockx.in.timeout = 10000;
+       t = time(NULL);
+       req = smb_raw_lock_send(tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       status = smb_raw_exit(session);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smbcli_request_simple_recv(req);
+       CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+       if (time(NULL) > t+2) {
+               printf("lock cancel by exit was not immediate (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       printf("testing cancel by ulogoff\n");
+       fname = BASEDIR "\\test_ulogoff.txt";
+       fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       io.lockx.in.timeout = 10000;
+       t = time(NULL);
+       req = smb_raw_lock_send(tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       status = smb_raw_ulogoff(session);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smbcli_request_simple_recv(req);
+       if (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status)) {
+               printf("lock not canceled by ulogoff - %s (ignored because of vfs_vifs fails it)\n",
+                       nt_errstr(status));
+               smb_tree_disconnect(tree);
+               smb_raw_exit(session);
+               goto done;
+       }
+       CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+       if (time(NULL) > t+2) {
+               printf("lock cancel by ulogoff was not immediate (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       printf("testing cancel by tdis\n");
+       tree->session = cli->session;
+
+       fname = BASEDIR "\\test_tdis.txt";
+       fnum = smbcli_open(tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = cli->session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smb_raw_lock(tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       io.lockx.in.timeout = 10000;
+       t = time(NULL);
+       req = smb_raw_lock_send(tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       status = smb_tree_disconnect(tree);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smbcli_request_simple_recv(req);
+       CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
+
+       if (time(NULL) > t+2) {
+               printf("lock cancel by tdis was not immediate (%s)\n", __location__);
+               ret = false;
                goto done;
        }
-       
 
 done:
+       smb_raw_exit(cli->session);
+       smbcli_deltree(cli->tree, BASEDIR);
+       return ret;
+}
+
+/*
+  test NT_STATUS_LOCK_NOT_GRANTED vs. NT_STATUS_FILE_LOCK_CONFLICT
+*/
+static bool test_errorcode(struct torture_context *tctx, 
+                                                  struct smbcli_state *cli)
+{
+       union smb_lock io;
+       union smb_open op;
+       struct smb_lock_entry lock[2];
+       NTSTATUS status;
+       bool ret = true;
+       int fnum, fnum2;
+       const char *fname;
+       struct smbcli_request *req;
+       time_t start;
+       int t;
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       printf("Testing LOCK_NOT_GRANTED vs. FILE_LOCK_CONFLICT\n");
+
+       printf("testing with timeout = 0\n");
+       fname = BASEDIR "\\test0.txt";
+       t = 0;
+
+       /*
+        * the first run is with t = 0,
+        * the second with t > 0 (=1)
+        */
+next_run:
+       /* 
+        * use the DENY_DOS mode, that creates two fnum's of one low-level file handle,
+        * this demonstrates that the cache is per fnum
+        */
+       op.openx.level = RAW_OPEN_OPENX;
+       op.openx.in.fname = fname;
+       op.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+       op.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_DOS;
+       op.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
+       op.openx.in.search_attrs = 0;
+       op.openx.in.file_attrs = 0;
+       op.openx.in.write_time = 0;
+       op.openx.in.size = 0;
+       op.openx.in.timeout = 0;
+
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = op.openx.out.file.fnum;
+
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum2 = op.openx.out.file.fnum;
+
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = t;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = cli->session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * demonstrate that the first conflicting lock on each handle give LOCK_NOT_GRANTED
+        * this also demonstrates that the error code cache is per file handle
+        * (LOCK_NOT_GRANTED is only be used when timeout is 0!)
+        */
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+       /* demonstrate that each following conflict gives FILE_LOCK_CONFLICT */
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* demonstrate that the smbpid doesn't matter */
+       lock[0].pid++;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+       lock[0].pid--;
+
+       /* 
+        * demonstrate the a successful lock with count = 0 and the same offset,
+        * doesn't reset the error cache
+        */
+       lock[0].offset = 100;
+       lock[0].count = 0;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* 
+        * demonstrate the a successful lock with count = 0 and outside the locked range,
+        * doesn't reset the error cache
+        */
+       lock[0].offset = 110;
+       lock[0].count = 0;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 99;
+       lock[0].count = 0;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* demonstrate that a changing count doesn't reset the error cache */
+       lock[0].offset = 100;
+       lock[0].count = 5;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 100;
+       lock[0].count = 15;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* 
+        * demonstrate the a lock with count = 0 and inside the locked range,
+        * fails and resets the error cache
+        */
+       lock[0].offset = 101;
+       lock[0].count = 0;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* demonstrate the a changing offset, resets the error cache */
+       lock[0].offset = 105;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 95;
+       lock[0].count = 9;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* 
+        * demonstrate the a successful lock in a different range, 
+        * doesn't reset the cache, the failing lock on the 2nd handle
+        * resets the resets the cache
+        */
+       lock[0].offset = 120;
+       lock[0].count = 15;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.file.fnum = fnum;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       io.lockx.in.file.fnum = fnum2;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, (t?NT_STATUS_FILE_LOCK_CONFLICT:NT_STATUS_LOCK_NOT_GRANTED));
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       /* end of the loop */
+       if (t == 0) {
+               smb_raw_exit(cli->session);
+               printf("testing with timeout > 0 (=1)\n");
+               fname = BASEDIR "\\test1.txt";
+               t = 1;
+               goto next_run;
+       }
+
+       /*
+        * the following 3 test sections demonstrate that
+        * the cache is only set when the error is reported
+        * to the client (after the timeout went by)
+        */
+       smb_raw_exit(cli->session);
+       printf("testing a conflict while a lock is pending\n");
+       fname = BASEDIR "\\test2.txt";
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = cli->session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       start = time(NULL);
+       io.lockx.in.timeout = 1000;
+       req = smb_raw_lock_send(cli->tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       io.lockx.in.timeout = 0;
+       lock[0].offset = 105;
+       lock[0].count = 10;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       status = smbcli_request_simple_recv(req);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       if (time(NULL) < start+1) {
+               printf("lock comes back to early (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       smbcli_close(cli->tree, fnum);
+       fname = BASEDIR "\\test3.txt";
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = cli->session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       start = time(NULL);
+       io.lockx.in.timeout = 1000;
+       req = smb_raw_lock_send(cli->tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       io.lockx.in.timeout = 0;
+       lock[0].offset = 105;
+       lock[0].count = 10;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       status = smbcli_request_simple_recv(req);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       if (time(NULL) < start+1) {
+               printf("lock comes back to early (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
        smbcli_close(cli->tree, fnum);
+       fname = BASEDIR "\\test4.txt";
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum == -1) {
+               printf("Failed to reopen %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
+               goto done;
+       }
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.file.fnum = fnum;
+       io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       lock[0].pid = cli->session->pid;
+       lock[0].offset = 100;
+       lock[0].count = 10;
+       io.lockx.in.locks = &lock[0];
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       start = time(NULL);
+       io.lockx.in.timeout = 1000;
+       req = smb_raw_lock_send(cli->tree, &io);
+       if (req == NULL) {
+               printf("Failed to setup timed lock (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+       io.lockx.in.timeout = 0;
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
+
+       status = smbcli_request_simple_recv(req);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       status = smb_raw_lock(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+
+       if (time(NULL) < start+1) {
+               printf("lock comes back to early (%s)\n", __location__);
+               ret = false;
+               goto done;
+       }
+
+done:
        smb_raw_exit(cli->session);
        smbcli_deltree(cli->tree, BASEDIR);
        return ret;
@@ -591,18 +1254,19 @@ done:
 /*
   test LOCKING_ANDX_CHANGE_LOCKTYPE
 */
-static BOOL test_changetype(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_changetype(struct torture_context *tctx, 
+                                                       struct smbcli_state *cli)
 {
        union smb_lock io;
        struct smb_lock_entry lock[2];
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
-       char c = 0;
+       uint8_t c = 0;
        const char *fname = BASEDIR "\\test.txt";
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
        printf("Testing LOCKING_ANDX_CHANGE_LOCKTYPE\n");
@@ -611,12 +1275,12 @@ static BOOL test_changetype(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               ret = false;
                goto done;
        }
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = fnum;
+       io.lockx.in.file.fnum = fnum;
        io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 0;
@@ -630,18 +1294,18 @@ static BOOL test_changetype(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
                printf("allowed write on read locked region (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
        /* windows server don't seem to support this */
        io.lockx.in.mode = LOCKING_ANDX_CHANGE_LOCKTYPE;
        status = smb_raw_lock(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL);
+       CHECK_STATUS(status, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
 
        if (smbcli_write(cli->tree, fnum, 0, &c, 100, 1) == 1) {
                printf("allowed write after lock change (%s)\n", __location__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -656,25 +1320,16 @@ done:
 /* 
    basic testing of lock calls
 */
-BOOL torture_raw_lock(void)
+struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx)
 {
-       struct smbcli_state *cli;
-       BOOL ret = True;
-       TALLOC_CTX *mem_ctx;
-
-       if (!torture_open_connection(&cli)) {
-               return False;
-       }
-
-       mem_ctx = talloc_init("torture_raw_lock");
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "LOCK");
 
-       ret &= test_lockx(cli, mem_ctx);
-       ret &= test_lock(cli, mem_ctx);
-       ret &= test_pidhigh(cli, mem_ctx);
-       ret &= test_async(cli, mem_ctx);
-       ret &= test_changetype(cli, mem_ctx);
+       torture_suite_add_1smb_test(suite, "lockx", test_lockx);
+       torture_suite_add_1smb_test(suite, "lock", test_lock);
+       torture_suite_add_1smb_test(suite, "pidhigh", test_pidhigh);
+       torture_suite_add_1smb_test(suite, "async", test_async);
+       torture_suite_add_1smb_test(suite, "errorcode", test_errorcode);
+       torture_suite_add_1smb_test(suite, "changetype", test_changetype);
 
-       torture_close_connection(cli);
-       talloc_destroy(mem_ctx);
-       return ret;
+       return suite;
 }