torture: add local fsrvp state tests
authorDavid Disseldorp <ddiss@samba.org>
Tue, 11 Sep 2012 09:59:45 +0000 (11:59 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:20 +0000 (18:15 +0200)
Test the storage and retrieval of FSRVP server state.

source4/torture/local/fsrvp_state.c [new file with mode: 0644]
source4/torture/local/local.c
source4/torture/local/wscript_build

diff --git a/source4/torture/local/fsrvp_state.c b/source4/torture/local/fsrvp_state.c
new file mode 100644 (file)
index 0000000..6233fb3
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   test suite for FSRVP RPC server state
+
+   Copyright (C) David Disseldorp 2012
+
+   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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "includes.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/param/param.h"
+#include "lib/util/dlinklist.h"
+#include "libcli/resolve/resolve.h"
+#include "librpc/gen_ndr/ndr_fsrvp.h"
+#include "librpc/gen_ndr/ndr_fsrvp_c.h"
+#include "source3/rpc_server/fss/srv_fss_private.h"
+#include "torture/torture.h"
+#include "torture/local/proto.h"
+
+char *lock_path(const char *name);
+static bool test_fsrvp_state_empty(struct torture_context *tctx)
+{
+       NTSTATUS status;
+       struct fss_global fss_global;
+       struct stat sbuf;
+       char *db_path = lock_path(FSS_DB_NAME);
+
+       memset(&fss_global, 0, sizeof(fss_global));
+       fss_global.mem_ctx = talloc_new(NULL);
+
+       status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
+                                fss_global.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to store empty fss state");
+
+       torture_assert_int_equal(tctx, stat(db_path, &sbuf), 0,
+                       "failed to stat fss state tdb");
+       talloc_free(fss_global.mem_ctx);
+
+       memset(&fss_global, 0, sizeof(fss_global));
+       fss_global.mem_ctx = talloc_new(NULL);
+
+       status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
+                                   &fss_global.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to retrieve empty fss state");
+       torture_assert_int_equal(tctx, fss_global.sc_sets_count, 0,
+                                "sc_sets_count set when it should be zero");
+       talloc_free(fss_global.mem_ctx);
+       talloc_free(db_path);
+
+       return true;
+}
+
+static bool test_fsrvp_state_sc_set(struct torture_context *tctx,
+                                   TALLOC_CTX *mem_ctx,
+                                   struct fss_sc_set **sc_set_out)
+{
+       struct fss_sc_set *sc_set;
+
+       sc_set = talloc_zero(mem_ctx, struct fss_sc_set);
+       sc_set->id = GUID_random();
+       sc_set->id_str = GUID_string(sc_set, &sc_set->id);
+       sc_set->state = FSS_SC_COMMITED;
+       sc_set->context = FSRVP_CTX_FILE_SHARE_BACKUP;
+       *sc_set_out = sc_set;
+
+       return true;
+}
+
+static bool test_fsrvp_state_sc(struct torture_context *tctx,
+                               TALLOC_CTX *mem_ctx,
+                               struct fss_sc **sc_out)
+{
+       struct fss_sc *sc;
+
+       sc = talloc_zero(mem_ctx, struct fss_sc);
+       sc->id = GUID_random();
+       sc->id_str = GUID_string(sc, &sc->id);
+       sc->volume_name = talloc_strdup(sc, "/this/is/a/path");
+       /* keep snap path NULL, i.e. not yet commited */
+       sc->create_ts = time(NULL);
+       *sc_out = sc;
+
+       return true;
+}
+
+static bool test_fsrvp_state_smap(struct torture_context *tctx,
+                               TALLOC_CTX *mem_ctx,
+                               const char *base_share_name,
+                               const char *sc_share_name,
+                               struct fss_sc_smap **smap_out)
+{
+       struct fss_sc_smap *smap;
+
+       smap = talloc_zero(mem_ctx, struct fss_sc_smap);
+       smap->snum = 42;
+       smap->share_name = talloc_strdup(mem_ctx, base_share_name);
+       smap->sc_share_name = talloc_strdup(mem_ctx, sc_share_name);
+       smap->sc_share_comment = talloc_strdup(mem_ctx, "test sc share comment");
+       smap->is_exposed = false;
+       *smap_out = smap;
+
+       return true;
+}
+
+static bool test_fsrvp_state_smap_compare(struct torture_context *tctx,
+                                         struct fss_sc_smap *smap_1,
+                                         struct fss_sc_smap *smap_2)
+{
+       /* already confirmed by caller */
+       torture_assert_str_equal(tctx, smap_1->sc_share_name,
+                                smap_2->sc_share_name,
+                                "smap sc share name strings differ");
+
+       torture_assert_int_equal(tctx, smap_1->snum, smap_2->snum,
+                                "smaps snums differ");
+
+       torture_assert_str_equal(tctx, smap_1->share_name,
+                                smap_2->share_name,
+                                "smap share name strings differ");
+
+       torture_assert_str_equal(tctx, smap_1->sc_share_comment,
+                                smap_2->sc_share_comment,
+                                "smap sc share comment strings differ");
+
+       torture_assert(tctx, (smap_1->is_exposed == smap_2->is_exposed),
+                      "smap exposure settings differ");
+
+       return true;
+}
+
+static bool test_fsrvp_state_sc_compare(struct torture_context *tctx,
+                                       struct fss_sc *sc_1,
+                                       struct fss_sc *sc_2)
+{
+       struct fss_sc_smap *smap_1;
+       struct fss_sc_smap *smap_2;
+       bool ok;
+
+       /* should have already been confirmed by the caller */
+       torture_assert(tctx, GUID_equal(&sc_1->id, &sc_2->id),
+                      "sc guids differ");
+
+       torture_assert_str_equal(tctx, sc_1->volume_name, sc_2->volume_name,
+                                "sc volume_name strings differ");
+
+       /* may be null, assert_str_eq handles null ptrs safely */
+       torture_assert_str_equal(tctx, sc_1->sc_path, sc_2->sc_path,
+                                "sc path strings differ");
+
+       torture_assert(tctx, difftime(sc_1->create_ts, sc_2->create_ts) == 0,
+                      "sc create timestamps differ");
+
+       torture_assert_int_equal(tctx, sc_1->smaps_count, sc_2->smaps_count,
+                                "sc smaps counts differ");
+
+       for (smap_1 = sc_1->smaps; smap_1; smap_1 = smap_1->next) {
+               bool matched = false;
+               for (smap_2 = sc_2->smaps; smap_2; smap_2 = smap_2->next) {
+                       if (strcmp(smap_1->sc_share_name,
+                                  smap_2->sc_share_name) == 0) {
+                               matched = true;
+                               ok = test_fsrvp_state_smap_compare(tctx,
+                                                                  smap_1,
+                                                                  smap_2);
+                               torture_assert(tctx, ok, "");
+                               break;
+                       }
+               }
+               torture_assert(tctx, matched, "no match for smap");
+       }
+
+       return true;
+}
+
+static bool test_fsrvp_state_sc_set_compare(struct torture_context *tctx,
+                                           struct fss_sc_set *sc_set_1,
+                                           struct fss_sc_set *sc_set_2)
+{
+       struct fss_sc *sc_1;
+       struct fss_sc *sc_2;
+       bool ok;
+
+       /* should have already been confirmed by the caller */
+       torture_assert(tctx, GUID_equal(&sc_set_1->id, &sc_set_2->id),
+                      "sc_set guids differ");
+
+       torture_assert_str_equal(tctx, sc_set_1->id_str, sc_set_2->id_str,
+                                "sc_set guid strings differ");
+
+       torture_assert_int_equal(tctx, sc_set_1->state, sc_set_2->state,
+                                "sc_set state enums differ");
+
+       torture_assert_int_equal(tctx, sc_set_1->context, sc_set_2->context,
+                                "sc_set contexts differ");
+
+       torture_assert_int_equal(tctx, sc_set_1->scs_count, sc_set_2->scs_count,
+                                "sc_set sc counts differ");
+
+       for (sc_1 = sc_set_1->scs; sc_1; sc_1 = sc_1->next) {
+               bool matched = false;
+               for (sc_2 = sc_set_2->scs; sc_2; sc_2 = sc_2->next) {
+                       if (GUID_equal(&sc_1->id, &sc_2->id)) {
+                               matched = true;
+                               ok = test_fsrvp_state_sc_compare(tctx, sc_1,
+                                                                      sc_2);
+                               torture_assert(tctx, ok, "");
+                               break;
+                       }
+               }
+               torture_assert(tctx, matched, "no match for sc");
+       }
+       return true;
+}
+
+static bool test_fsrvp_state_compare(struct torture_context *tctx,
+                                    struct fss_global *fss_1,
+                                    struct fss_global *fss_2)
+{
+       struct fss_sc_set *sc_set_1;
+       struct fss_sc_set *sc_set_2;
+       bool ok;
+
+       torture_assert_int_equal(tctx, fss_1->sc_sets_count,
+                                fss_2->sc_sets_count,
+                                "sc_sets_count differ");
+
+       for (sc_set_1 = fss_1->sc_sets; sc_set_1; sc_set_1 = sc_set_1->next) {
+               bool matched = false;
+               for (sc_set_2 = fss_2->sc_sets;
+                    sc_set_2;
+                    sc_set_2 = sc_set_2->next) {
+                       if (GUID_equal(&sc_set_1->id, &sc_set_2->id)) {
+                               matched = true;
+                               ok = test_fsrvp_state_sc_set_compare(tctx,
+                                                                    sc_set_1,
+                                                                    sc_set_2);
+                               torture_assert(tctx, ok, "");
+                               break;
+                       }
+               }
+               torture_assert(tctx, matched, "no match for sc_set");
+       }
+
+       return true;
+}
+
+/*
+ * test a simple heirarchy of:
+ *
+ *       |
+ *     sc_set
+ *       |
+ *      sc
+ *        \
+ *       smap
+ */
+static bool test_fsrvp_state_single(struct torture_context *tctx)
+{
+       NTSTATUS status;
+       bool ok;
+       struct fss_global fss_gs;
+       struct fss_global fss_gr;
+       struct fss_sc_set *sc_set;
+       struct fss_sc *sc;
+       struct fss_sc_smap *smap;
+
+       memset(&fss_gs, 0, sizeof(fss_gs));
+       fss_gs.mem_ctx = talloc_new(NULL);
+
+       ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set);
+       torture_assert(tctx, ok, "failed to create sc set");
+
+       /* use parent as mem ctx */
+       ok = test_fsrvp_state_sc(tctx, sc_set, &sc);
+       torture_assert(tctx, ok, "failed to create sc");
+
+       ok = test_fsrvp_state_smap(tctx, sc, "base_share", "sc_share", &smap);
+       torture_assert(tctx, ok, "failed to create smap");
+
+       DLIST_ADD_END(fss_gs.sc_sets, sc_set, struct fss_sc_set *);
+       fss_gs.sc_sets_count++;
+       DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
+       sc_set->scs_count++;
+       sc->sc_set = sc_set;
+       DLIST_ADD_END(sc->smaps, smap, struct fss_sc_smap *);
+       sc->smaps_count++;
+
+       status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
+                                fss_gs.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to store fss state");
+
+       memset(&fss_gr, 0, sizeof(fss_gr));
+       fss_gr.mem_ctx = talloc_new(NULL);
+
+       status = fss_state_retrieve(fss_gr.mem_ctx, &fss_gr.sc_sets,
+                                   &fss_gr.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to retrieve fss state");
+
+       ok = test_fsrvp_state_compare(tctx, &fss_gs, &fss_gr);
+       torture_assert(tctx, ok,
+                      "stored and retrieved state comparison failed");
+
+       talloc_free(fss_gs.mem_ctx);
+       talloc_free(fss_gr.mem_ctx);
+
+       return true;
+}
+
+/*
+ * test a complex heirarchy of:
+ *
+ *              /\
+ *             /  \
+ *     sc_set_a    sc_set_b
+ *     /     \
+ * sc_aa      sc_ab
+ * |          |   \
+ * smap_aaa   |    \
+ *            |     \
+ *       smap_aba   smap_abb
+ */
+static bool test_fsrvp_state_multi(struct torture_context *tctx)
+{
+       NTSTATUS status;
+       bool ok;
+       struct fss_global fss_gs;
+       struct fss_global fss_gr;
+       struct fss_sc_set *sc_set_a;
+       struct fss_sc_set *sc_set_b;
+       struct fss_sc *sc_aa;
+       struct fss_sc *sc_ab;
+       struct fss_sc_smap *smap_aaa;
+       struct fss_sc_smap *smap_aba;
+       struct fss_sc_smap *smap_abb;
+
+       memset(&fss_gs, 0, sizeof(fss_gs));
+       fss_gs.mem_ctx = talloc_new(NULL);
+
+       ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set_a);
+       torture_assert(tctx, ok, "failed to create sc set");
+
+       ok = test_fsrvp_state_sc_set(tctx, fss_gs.mem_ctx, &sc_set_b);
+       torture_assert(tctx, ok, "failed to create sc set");
+
+       /* use parent as mem ctx */
+       ok = test_fsrvp_state_sc(tctx, sc_set_a, &sc_aa);
+       torture_assert(tctx, ok, "failed to create sc");
+
+       ok = test_fsrvp_state_sc(tctx, sc_set_a, &sc_ab);
+       torture_assert(tctx, ok, "failed to create sc");
+
+       ok = test_fsrvp_state_smap(tctx, sc_ab, "share_aa", "sc_share_aaa",
+                                  &smap_aaa);
+       torture_assert(tctx, ok, "failed to create smap");
+
+       ok = test_fsrvp_state_smap(tctx, sc_ab, "share_ab", "sc_share_aba",
+                                  &smap_aba);
+       torture_assert(tctx, ok, "failed to create smap");
+
+       ok = test_fsrvp_state_smap(tctx, sc_ab, "share_ab", "sc_share_abb",
+                                  &smap_abb);
+       torture_assert(tctx, ok, "failed to create smap");
+
+       DLIST_ADD_END(fss_gs.sc_sets, sc_set_a, struct fss_sc_set *);
+       fss_gs.sc_sets_count++;
+       DLIST_ADD_END(fss_gs.sc_sets, sc_set_b, struct fss_sc_set *);
+       fss_gs.sc_sets_count++;
+
+       DLIST_ADD_END(sc_set_a->scs, sc_aa, struct fss_sc *);
+       sc_set_a->scs_count++;
+       sc_aa->sc_set = sc_set_a;
+       DLIST_ADD_END(sc_set_a->scs, sc_ab, struct fss_sc *);
+       sc_set_a->scs_count++;
+       sc_ab->sc_set = sc_set_a;
+
+       DLIST_ADD_END(sc_aa->smaps, smap_aaa, struct fss_sc_smap *);
+       sc_aa->smaps_count++;
+       DLIST_ADD_END(sc_ab->smaps, smap_aba, struct fss_sc_smap *);
+       sc_ab->smaps_count++;
+       DLIST_ADD_END(sc_ab->smaps, smap_abb, struct fss_sc_smap *);
+       sc_ab->smaps_count++;
+
+       status = fss_state_store(fss_gs.mem_ctx, fss_gs.sc_sets,
+                                fss_gs.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to store fss state");
+
+       memset(&fss_gr, 0, sizeof(fss_gr));
+       fss_gr.mem_ctx = talloc_new(NULL);
+       status = fss_state_retrieve(fss_gr.mem_ctx, &fss_gr.sc_sets,
+                                   &fss_gr.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to retrieve fss state");
+
+       ok = test_fsrvp_state_compare(tctx, &fss_gs, &fss_gr);
+       torture_assert(tctx, ok,
+                      "stored and retrieved state comparison failed");
+
+       talloc_free(fss_gs.mem_ctx);
+       talloc_free(fss_gr.mem_ctx);
+
+       return true;
+}
+
+static bool test_fsrvp_state_none(struct torture_context *tctx)
+{
+       NTSTATUS status;
+       struct fss_global fss_global;
+       char *db_path = lock_path(FSS_DB_NAME);
+
+       /* ensure start with an empty db */
+       unlink(db_path);
+
+       memset(&fss_global, 0, sizeof(fss_global));
+       fss_global.mem_ctx = talloc_new(NULL);
+
+       status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
+                                   &fss_global.sc_sets_count);
+       torture_assert_ntstatus_ok(tctx, status,
+                                  "failed to retrieve fss state");
+       torture_assert_int_equal(tctx, fss_global.sc_sets_count, 0,
+                                "sc_sets_count set when it should be zero");
+       talloc_free(fss_global.mem_ctx);
+       talloc_free(db_path);
+
+       return true;
+}
+
+struct torture_suite *torture_local_fsrvp(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx,
+                                                          "fsrvp_state");
+
+       /* dbwrap uses talloc_tos(), hence we need a stackframe :( */
+       talloc_stackframe();
+
+       torture_suite_add_simple_test(suite,
+                                     "state_empty",
+                                     test_fsrvp_state_empty);
+
+       torture_suite_add_simple_test(suite,
+                                     "state_single",
+                                     test_fsrvp_state_single);
+
+       torture_suite_add_simple_test(suite,
+                                     "state_multi",
+                                     test_fsrvp_state_multi);
+
+       /* keep this last so that the tdb is cleaned up */
+       torture_suite_add_simple_test(suite,
+                                     "state_none",
+                                     test_fsrvp_state_none);
+
+       return suite;
+}
index c0b3305462a80b4d58c596ee509969ac7c895fc0..4b2ce41d2f8029ad4264fdcd66b3dd256a3148ae 100644 (file)
@@ -22,6 +22,7 @@
 #include "torture/local/proto.h"
 #include "torture/ndr/proto.h"
 #include "torture/auth/proto.h"
+#include "torture/rpc/proto.h"
 #include "../lib/crypto/test_proto.h"
 #include "lib/registry/tests/proto.h"
 #include "lib/replace/replace-test.h"
@@ -74,6 +75,7 @@
        torture_dsdb_dn,
        torture_dsdb_syntax,
        torture_registry,
+       torture_local_fsrvp,
        NULL
 };
 
index c5d897a1237a151d1eeb448f7115aca250ae01c6..da0869a3392dc16d5016766baa0005e63f344262 100644 (file)
@@ -16,7 +16,8 @@ TORTURE_LOCAL_SOURCE = '''../../../lib/util/charset/tests/iconv.c
        ../../param/tests/loadparm.c ../../../auth/credentials/tests/simple.c local.c
        dbspeed.c torture.c ../ldb/ldb.c ../../dsdb/common/tests/dsdb_dn.c
        ../../dsdb/schema/tests/schema_syntax.c
-       ../../../lib/util/tests/anonymous_shared.c'''
+       ../../../lib/util/tests/anonymous_shared.c
+       fsrvp_state.c ../../../source3/rpc_server/fss/srv_fss_state.c'''
 
 TORTURE_LOCAL_DEPS = 'RPC_NDR_ECHO TDR LIBCLI_SMB MESSAGING iconv POPT_CREDENTIALS TORTURE_AUTH TORTURE_UTIL TORTURE_NDR TORTURE_LIBCRYPTO share torture_registry PROVISION ldb samdb replace-test'