2 Unix SMB/CIFS implementation.
4 DRSUAPI schemaInfo unit tests
6 Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
24 #include "torture/smbtorture.h"
25 #include "dsdb/samdb/samdb.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
28 #include "lib/ldb/include/ldb_module.h"
29 #include "torture/rpc/drsuapi.h"
30 #include "librpc/ndr/libndr.h"
31 #include "param/param.h"
35 * schemaInfo to init ldb context with
37 * GUID: 00000000-0000-0000-0000-000000000000
39 #define SCHEMA_INFO_INIT_STR "FF0000000000000000000000000000000000000000"
42 * Default schema_info string to be used for testing
44 * GUID: 071c82fd-45c7-4351-a3db-51f75a630a7f
46 #define SCHEMA_INFO_DEFAULT_STR "FF00000001FD821C07C7455143A3DB51F75A630A7F"
49 * Schema info data to test with
51 struct schemainfo_data {
53 struct dsdb_schema_info schi;
59 * Schema info test data in human-readable format (... kind of)
62 const char *schema_info_str;
67 } _schemainfo_test_data[] = {
69 .schema_info_str = "FF0000000000000000000000000000000000000000",
71 .guid_str = "00000000-0000-0000-0000-000000000000",
72 .werr_expected = WERR_OK,
73 .test_both_ways = true
76 .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F",
78 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
79 .werr_expected = WERR_OK,
80 .test_both_ways = true
83 .schema_info_str = "FFFFFFFFFFFD821C07C7455143A3DB51F75A630A7F",
84 .revision = 0xFFFFFFFF,
85 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
86 .werr_expected = WERR_OK,
87 .test_both_ways = true
90 .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F00",
92 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
93 .werr_expected = WERR_INVALID_PARAMETER,
94 .test_both_ways = false
97 .schema_info_str = "AA00000001FD821C07C7455143A3DB51F75A630A7F",
99 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
100 .werr_expected = WERR_INVALID_PARAMETER,
101 .test_both_ways = false
106 * Private data to be shared among all test in Test case
108 struct drsut_schemainfo_data {
109 struct ldb_context *ldb;
110 struct ldb_module *ldb_module;
111 struct dsdb_schema *schema;
113 /* Initial schemaInfo set in ldb to test with */
114 struct dsdb_schema_info *schema_info;
116 uint32_t test_data_count;
117 struct schemainfo_data *test_data;
121 * torture macro to assert for equal dsdb_schema_info's
123 #define torture_assert_schema_info_equal(torture_ctx,got,expected,cmt)\
124 do { const struct dsdb_schema_info *__got = (got), *__expected = (expected); \
125 if (__got->revision != __expected->revision) { \
126 torture_result(torture_ctx, TORTURE_FAIL, \
127 __location__": "#got".revision %d did not match "#expected".revision %d: %s", \
128 (int)__got->revision, (int)__expected->revision, cmt); \
131 if (!GUID_equal(&__got->invocation_id, &__expected->invocation_id)) { \
132 torture_result(torture_ctx, TORTURE_FAIL, \
133 __location__": "#got".invocation_id did not match "#expected".invocation_id: %s", cmt); \
139 * forward declaration for internal functions
141 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
142 struct ldb_context *ldb,
143 const char *schema_info_str,
148 * Creates dsdb_schema_info object based on NDR data
149 * passed as hex string
151 static bool _drsut_schemainfo_new(struct torture_context *tctx,
152 const char *schema_info_str, struct dsdb_schema_info **_si)
157 blob = strhex_to_data_blob(tctx, schema_info_str);
159 torture_comment(tctx, "Not enough memory!\n");
163 werr = dsdb_schema_info_from_blob(&blob, tctx, _si);
164 if (!W_ERROR_IS_OK(werr)) {
165 torture_comment(tctx,
166 "Failed to create dsdb_schema_info object for %s: %s",
172 data_blob_free(&blob);
178 * Creates dsdb_schema_info object based on predefined data
179 * Function is public as it is intended to be used by other
180 * tests (e.g. prefixMap tests)
182 bool drsut_schemainfo_new(struct torture_context *tctx, struct dsdb_schema_info **_si)
184 return _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, _si);
189 * Tests dsdb_schema_info_new() and dsdb_schema_info_blob_new()
191 static bool test_dsdb_schema_info_new(struct torture_context *tctx,
192 struct drsut_schemainfo_data *priv)
196 DATA_BLOB ndr_blob_expected;
197 struct dsdb_schema_info *schi;
200 mem_ctx = talloc_new(priv);
201 torture_assert(tctx, mem_ctx, "Not enough memory!");
202 ndr_blob_expected = strhex_to_data_blob(mem_ctx, SCHEMA_INFO_INIT_STR);
203 torture_assert(tctx, ndr_blob_expected.data, "Not enough memory!");
205 werr = dsdb_schema_info_new(mem_ctx, &schi);
206 torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_new() failed");
207 torture_assert_int_equal(tctx, schi->revision, 0,
208 "dsdb_schema_info_new() creates schemaInfo with invalid revision");
209 torture_assert(tctx, GUID_all_zero(&schi->invocation_id),
210 "dsdb_schema_info_new() creates schemaInfo with not ZERO GUID");
212 werr = dsdb_schema_info_blob_new(mem_ctx, &ndr_blob);
213 torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_blob_new() failed");
214 torture_assert_data_blob_equal(tctx, ndr_blob, ndr_blob_expected,
215 "dsdb_schema_info_blob_new() returned invalid blob");
217 talloc_free(mem_ctx);
222 * Tests dsdb_schema_info_from_blob()
224 static bool test_dsdb_schema_info_from_blob(struct torture_context *tctx,
225 struct drsut_schemainfo_data *priv)
230 struct dsdb_schema_info *schema_info;
233 mem_ctx = talloc_new(priv);
234 torture_assert(tctx, mem_ctx, "Not enough memory!");
236 for (i = 0; i < priv->test_data_count; i++) {
237 struct schemainfo_data *data = &priv->test_data[i];
239 msg = talloc_asprintf(tctx, "dsdb_schema_info_from_blob() [%d]-[%s]",
240 i, _schemainfo_test_data[i].schema_info_str);
242 werr = dsdb_schema_info_from_blob(&data->ndr_blob, mem_ctx, &schema_info);
243 torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
245 /* test returned data */
246 if (W_ERROR_IS_OK(werr)) {
247 torture_assert_schema_info_equal(tctx,
248 schema_info, &data->schi,
249 "after dsdb_schema_info_from_blob() call");
253 talloc_free(mem_ctx);
259 * Tests dsdb_blob_from_schema_info()
261 static bool test_dsdb_blob_from_schema_info(struct torture_context *tctx,
262 struct drsut_schemainfo_data *priv)
270 mem_ctx = talloc_new(priv);
271 torture_assert(tctx, mem_ctx, "Not enough memory!");
273 for (i = 0; i < priv->test_data_count; i++) {
274 struct schemainfo_data *data = &priv->test_data[i];
276 /* not all test are valid reverse type of conversion */
277 if (!data->test_both_ways) {
281 msg = talloc_asprintf(tctx, "dsdb_blob_from_schema_info() [%d]-[%s]",
282 i, _schemainfo_test_data[i].schema_info_str);
284 werr = dsdb_blob_from_schema_info(&data->schi, mem_ctx, &ndr_blob);
285 torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
287 /* test returned data */
288 if (W_ERROR_IS_OK(werr)) {
289 torture_assert_data_blob_equal(tctx,
290 ndr_blob, data->ndr_blob,
291 "dsdb_blob_from_schema_info()");
295 talloc_free(mem_ctx);
301 * Tests dsdb_module_schema_info_blob_read()
302 * and dsdb_module_schema_info_blob_write()
304 static bool test_dsdb_module_schema_info_blob_rw(struct torture_context *tctx,
305 struct drsut_schemainfo_data *priv)
308 DATA_BLOB blob_write;
311 /* reset schmeInfo to know value */
313 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
314 "_drsut_ldb_schema_info_reset() failed");
316 /* write tests' default schemaInfo */
317 blob_write = strhex_to_data_blob(priv, SCHEMA_INFO_DEFAULT_STR);
318 torture_assert(tctx, blob_write.data, "Not enough memory!");
320 werr = dsdb_module_schema_info_blob_write(priv->ldb_module,
321 DSDB_FLAG_TOP_MODULE,
323 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_write() failed");
325 werr = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
327 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_read() failed");
329 /* check if we get what we wrote */
330 torture_assert_data_blob_equal(tctx, blob_read, blob_write,
331 "Write/Read of schemeInfo blob failed");
337 * Tests dsdb_schema_update_schema_info()
339 static bool test_dsdb_module_schema_info_update(struct torture_context *tctx,
340 struct drsut_schemainfo_data *priv)
344 struct dsdb_schema_info *schema_info;
346 /* reset schmeInfo to know value */
348 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
349 "_drsut_ldb_schema_info_reset() failed");
351 werr = dsdb_module_schema_info_update(priv->ldb_module,
353 DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM);
354 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_update() failed");
356 /* get updated schemaInfo */
357 werr = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
359 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_read() failed");
361 werr = dsdb_schema_info_from_blob(&blob, priv, &schema_info);
362 torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob() failed");
364 /* check against default schema_info */
365 torture_assert_schema_info_equal(tctx, schema_info, priv->schema_info,
366 "schemaInfo attribute no updated correctly");
373 * Reset schemaInfo record to know value
375 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
376 struct ldb_context *ldb,
377 const char *schema_info_str,
383 struct ldb_message *msg;
384 TALLOC_CTX *mem_ctx = talloc_new(tctx);
386 blob = strhex_to_data_blob(mem_ctx, schema_info_str);
387 torture_assert_goto(tctx, blob.data, bret, DONE, "Not enough memory!");
389 msg = ldb_msg_new(mem_ctx);
390 torture_assert_goto(tctx, msg, bret, DONE, "Not enough memory!");
392 msg->dn = ldb_get_schema_basedn(ldb);
393 ldb_err = ldb_msg_add_value(msg, "schemaInfo", &blob, NULL);
394 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
395 "ldb_msg_add_value() failed");
398 ldb_err = ldb_add(ldb, msg);
400 ldb_err = dsdb_replace(ldb, msg, DSDB_MODIFY_PERMISSIVE);
402 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
403 "dsdb_replace() failed");
406 talloc_free(mem_ctx);
411 * Prepare temporary LDB and opens it
413 static bool _drsut_ldb_setup(struct torture_context *tctx, struct drsut_schemainfo_data *priv)
418 char *tempdir = NULL;
422 mem_ctx = talloc_new(priv);
423 torture_assert(tctx, mem_ctx, "Not enough memory!");
425 status = torture_temp_dir(tctx, "drs_", &tempdir);
426 torture_assert_ntstatus_ok_goto(tctx, status, bret, DONE, "creating temp dir");
428 ldb_url = talloc_asprintf(priv, "%s/drs_schemainfo.ldb", tempdir);
429 torture_assert_goto(tctx, ldb_url, bret, DONE, "Not enough memory!");
432 priv->ldb = ldb_wrap_connect(priv, tctx->ev, tctx->lp_ctx,
433 ldb_url, NULL, NULL, 0);
434 torture_assert_goto(tctx, priv->ldb, bret, DONE, "ldb_wrap_connect() failed");
436 /* set some schemaNamingContext */
437 ldb_err = ldb_set_opaque(priv->ldb,
438 "schemaNamingContext",
439 ldb_dn_new(priv->ldb, priv->ldb, "CN=Schema,CN=Config"));
440 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
441 "ldb_set_opaque() failed");
443 /* add schemaInfo attribute so tested layer could work properly */
444 torture_assert_goto(tctx,
445 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, true),
447 "_drsut_ldb_schema_info_reset() failed");
450 talloc_free(tempdir);
451 talloc_free(mem_ctx);
456 * Setup/Teardown for test case
458 static bool torture_drs_unit_schemainfo_setup(struct torture_context *tctx,
459 struct drsut_schemainfo_data **_priv)
466 struct drsut_schemainfo_data *priv;
468 priv = talloc_zero(tctx, struct drsut_schemainfo_data);
469 torture_assert(tctx, priv, "Not enough memory!");
471 /* returned allocated pointer here
472 * teardown() will be called even in case of failure,
473 * so we'll get a changes to clean up */
476 /* create initial schemaInfo */
478 _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema_info),
479 "Failed to create schema_info test object");
481 /* create data to test with */
482 priv->test_data_count = ARRAY_SIZE(_schemainfo_test_data);
483 priv->test_data = talloc_array(tctx, struct schemainfo_data, priv->test_data_count);
485 for (i = 0; i < ARRAY_SIZE(_schemainfo_test_data); i++) {
486 struct schemainfo_data *data = &priv->test_data[i];
488 ndr_blob = strhex_to_data_blob(priv,
489 _schemainfo_test_data[i].schema_info_str);
490 torture_assert(tctx, ndr_blob.data, "Not enough memory!");
492 status = GUID_from_string(_schemainfo_test_data[i].guid_str, &guid);
493 torture_assert_ntstatus_ok(tctx, status,
494 talloc_asprintf(tctx,
495 "GUID_from_string() failed for %s",
496 _schemainfo_test_data[i].guid_str));
498 data->ndr_blob = ndr_blob;
499 data->schi.invocation_id = guid;
500 data->schi.revision = _schemainfo_test_data[i].revision;
501 data->werr_expected = _schemainfo_test_data[i].werr_expected;
502 data->test_both_ways = _schemainfo_test_data[i].test_both_ways;
506 /* create temporary LDB and populate with data */
507 if (!_drsut_ldb_setup(tctx, priv)) {
511 /* create ldb_module mockup object */
512 priv->ldb_module = ldb_module_new(priv, priv->ldb, "schemaInfo_test_module", NULL);
513 torture_assert(tctx, priv->ldb_module, "Not enough memory!");
515 /* create schema mockup object */
516 priv->schema = dsdb_new_schema(priv);
518 /* pre-cache invocationId for samdb_ntds_invocation_id()
519 * to work with our mock ldb */
520 ldb_err = ldb_set_opaque(priv->ldb, "cache.invocation_id",
521 &priv->schema_info->invocation_id);
522 torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "ldb_set_opaque() failed");
524 /* Perform all tests in transactions so that
525 * underlying modify calls not to fail */
526 ldb_err = ldb_transaction_start(priv->ldb);
527 torture_assert_int_equal(tctx,
530 "ldb_transaction_start() failed");
535 static bool torture_drs_unit_schemainfo_teardown(struct torture_context *tctx,
536 struct drsut_schemainfo_data *priv)
540 /* commit pending transaction so we will
541 * be able to check what LDB state is */
542 ldb_err = ldb_transaction_commit(priv->ldb);
543 if (ldb_err != LDB_SUCCESS) {
544 torture_comment(tctx, "ldb_transaction_commit() - %s (%s)",
545 ldb_strerror(ldb_err),
546 ldb_errstring(priv->ldb));
555 * Test case initialization for
556 * DRS-UNIT.schemaInfo
558 struct torture_tcase * torture_drs_unit_schemainfo(struct torture_suite *suite)
560 typedef bool (*pfn_setup)(struct torture_context *, void **);
561 typedef bool (*pfn_teardown)(struct torture_context *, void *);
562 typedef bool (*pfn_run)(struct torture_context *, void *);
564 struct torture_tcase * tc = torture_suite_add_tcase(suite, "schemaInfo");
566 torture_tcase_set_fixture(tc,
567 (pfn_setup)torture_drs_unit_schemainfo_setup,
568 (pfn_teardown)torture_drs_unit_schemainfo_teardown);
570 tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::schemaInfo implementation");
572 torture_tcase_add_simple_test(tc, "dsdb_schema_info_new",
573 (pfn_run)test_dsdb_schema_info_new);
574 torture_tcase_add_simple_test(tc, "dsdb_schema_info_from_blob",
575 (pfn_run)test_dsdb_schema_info_from_blob);
576 torture_tcase_add_simple_test(tc, "dsdb_blob_from_schema_info",
577 (pfn_run)test_dsdb_blob_from_schema_info);
578 torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_blob read|write",
579 (pfn_run)test_dsdb_module_schema_info_blob_rw);
580 torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_update",
581 (pfn_run)test_dsdb_module_schema_info_update);