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"
27 #include "lib/ldb_wrap.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: 071c82fd-45c7-4351-a3db-51f75a630a7f
39 #define SCHEMA_INFO_INIT_STR "FF0000000100000000000000000000000000000000"
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 = "FF00000001FD821C07C7455143A3DB51F75A630A7F",
71 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
72 .werr_expected = WERR_OK,
73 .test_both_ways = true
76 .schema_info_str = "FFFFFFFFFFFD821C07C7455143A3DB51F75A630A7F",
77 .revision = 0xFFFFFFFF,
78 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
79 .werr_expected = WERR_OK,
80 .test_both_ways = true
83 /* removed until kamen can take a look - revision 0 is sent by
84 * w2k8r2, and we need to accept it, possibly only when the
85 * other fields are zero */
87 .schema_info_str = "FF00000000FD821C07C7455143A3DB51F75A630A7F",
89 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
90 .werr_expected = WERR_INVALID_PARAMETER,
91 .test_both_ways = true
95 .schema_info_str = "FF00000001FD821C07C7455143A3DB51F75A630A7F00",
97 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
98 .werr_expected = WERR_INVALID_PARAMETER,
99 .test_both_ways = false
102 .schema_info_str = "AA00000001FD821C07C7455143A3DB51F75A630A7F",
104 .guid_str = "071c82fd-45c7-4351-a3db-51f75a630a7f",
105 .werr_expected = WERR_INVALID_PARAMETER,
106 .test_both_ways = false
111 * Private data to be shared among all test in Test case
113 struct drsut_schemainfo_data {
114 struct ldb_context *ldb;
115 struct ldb_module *ldb_module;
116 struct dsdb_schema *schema;
118 /* Initial schemaInfo set in ldb to test with */
119 struct dsdb_schema_info *schema_info;
121 uint32_t test_data_count;
122 struct schemainfo_data *test_data;
126 * torture macro to assert for equal dsdb_schema_info's
128 #define torture_assert_schema_info_equal(torture_ctx,got,expected,cmt)\
129 do { const struct dsdb_schema_info *__got = (got), *__expected = (expected); \
130 if (__got->revision != __expected->revision) { \
131 torture_result(torture_ctx, TORTURE_FAIL, \
132 __location__": "#got".revision %d did not match "#expected".revision %d: %s", \
133 (int)__got->revision, (int)__expected->revision, cmt); \
136 if (!GUID_equal(&__got->invocation_id, &__expected->invocation_id)) { \
137 torture_result(torture_ctx, TORTURE_FAIL, \
138 __location__": "#got".invocation_id did not match "#expected".invocation_id: %s", cmt); \
144 * forward declaration for internal functions
146 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
147 struct ldb_context *ldb,
148 const char *schema_info_str,
153 * Creates dsdb_schema_info object based on NDR data
154 * passed as hex string
156 static bool _drsut_schemainfo_new(struct torture_context *tctx,
157 const char *schema_info_str, struct dsdb_schema_info **_si)
162 blob = strhex_to_data_blob(tctx, schema_info_str);
164 torture_comment(tctx, "Not enough memory!\n");
168 werr = dsdb_schema_info_from_blob(&blob, tctx, _si);
169 if (!W_ERROR_IS_OK(werr)) {
170 torture_comment(tctx,
171 "Failed to create dsdb_schema_info object for %s: %s",
177 data_blob_free(&blob);
183 * Creates dsdb_schema_info object based on predefined data
184 * Function is public as it is intended to be used by other
185 * tests (e.g. prefixMap tests)
187 bool drsut_schemainfo_new(struct torture_context *tctx, struct dsdb_schema_info **_si)
189 return _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, _si);
194 * Tests dsdb_schema_info_from_blob()
196 static bool test_dsdb_schema_info_from_blob(struct torture_context *tctx,
197 struct drsut_schemainfo_data *priv)
202 struct dsdb_schema_info *schema_info;
205 mem_ctx = talloc_new(priv);
206 torture_assert(tctx, mem_ctx, "Not enough memory!");
208 for (i = 0; i < priv->test_data_count; i++) {
209 struct schemainfo_data *data = &priv->test_data[i];
211 msg = talloc_asprintf(tctx, "dsdb_schema_info_from_blob() [%d]-[%s]",
212 i, _schemainfo_test_data[i].schema_info_str);
214 werr = dsdb_schema_info_from_blob(&data->ndr_blob, mem_ctx, &schema_info);
215 torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
217 /* test returned data */
218 if (W_ERROR_IS_OK(werr)) {
219 torture_assert_schema_info_equal(tctx,
220 schema_info, &data->schi,
221 "after dsdb_schema_info_from_blob() call");
225 talloc_free(mem_ctx);
231 * Tests dsdb_blob_from_schema_info()
233 static bool test_dsdb_blob_from_schema_info(struct torture_context *tctx,
234 struct drsut_schemainfo_data *priv)
242 mem_ctx = talloc_new(priv);
243 torture_assert(tctx, mem_ctx, "Not enough memory!");
245 for (i = 0; i < priv->test_data_count; i++) {
246 struct schemainfo_data *data = &priv->test_data[i];
248 /* not all test are valid reverse type of conversion */
249 if (!data->test_both_ways) {
253 msg = talloc_asprintf(tctx, "dsdb_blob_from_schema_info() [%d]-[%s]",
254 i, _schemainfo_test_data[i].schema_info_str);
256 werr = dsdb_blob_from_schema_info(&data->schi, mem_ctx, &ndr_blob);
257 torture_assert_werr_equal(tctx, werr, data->werr_expected, msg);
259 /* test returned data */
260 if (W_ERROR_IS_OK(werr)) {
261 torture_assert_data_blob_equal(tctx,
262 ndr_blob, data->ndr_blob,
263 "dsdb_blob_from_schema_info()");
267 talloc_free(mem_ctx);
273 * Tests dsdb_module_schema_info_blob_read()
274 * and dsdb_module_schema_info_blob_write()
276 static bool test_dsdb_module_schema_info_blob_rw(struct torture_context *tctx,
277 struct drsut_schemainfo_data *priv)
280 DATA_BLOB blob_write;
283 /* reset schmeInfo to know value */
285 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
286 "_drsut_ldb_schema_info_reset() failed");
288 /* write tests' default schemaInfo */
289 blob_write = strhex_to_data_blob(priv, SCHEMA_INFO_DEFAULT_STR);
290 torture_assert(tctx, blob_write.data, "Not enough memory!");
292 werr = dsdb_module_schema_info_blob_write(priv->ldb_module,
293 DSDB_FLAG_TOP_MODULE,
295 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_write() failed");
297 werr = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
299 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_read() failed");
301 /* check if we get what we wrote */
302 torture_assert_data_blob_equal(tctx, blob_read, blob_write,
303 "Write/Read of schemeInfo blob failed");
309 * Tests dsdb_schema_update_schema_info()
311 static bool test_dsdb_module_schema_info_update(struct torture_context *tctx,
312 struct drsut_schemainfo_data *priv)
316 struct dsdb_schema_info *schema_info;
318 /* reset schmeInfo to know value */
320 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, false),
321 "_drsut_ldb_schema_info_reset() failed");
323 werr = dsdb_module_schema_info_update(priv->ldb_module,
325 DSDB_FLAG_TOP_MODULE | DSDB_FLAG_AS_SYSTEM);
326 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_update() failed");
328 /* get updated schemaInfo */
329 werr = dsdb_module_schema_info_blob_read(priv->ldb_module, DSDB_FLAG_TOP_MODULE,
331 torture_assert_werr_ok(tctx, werr, "dsdb_module_schema_info_blob_read() failed");
333 werr = dsdb_schema_info_from_blob(&blob, priv, &schema_info);
334 torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_from_blob() failed");
336 /* decrement revision to be able to compare
337 * against default schemaInfo later */
338 schema_info->revision--;
340 /* check against default schema_info */
341 torture_assert_schema_info_equal(tctx, schema_info, priv->schema_info,
342 "schemaInfo attribute no updated correctly");
348 * Tests dsdb_schema_info_create()
350 static bool test_dsdb_schema_info_create(struct torture_context *tctx,
351 struct drsut_schemainfo_data *priv)
354 struct dsdb_schema_info *schema_info = NULL;
356 werr = dsdb_schema_info_create(priv->ldb, true, priv, &schema_info);
357 torture_assert_werr_ok(tctx, werr, "dsdb_schema_info_create() failed");
359 torture_assert(tctx, schema_info, "schema_info is NULL after dsdb_schema_info_create()");
360 torture_assert_int_equal(tctx, schema_info->revision, 1, "Invalid schemaInfo revision");
362 GUID_equal(&schema_info->invocation_id, &priv->schema_info->invocation_id),
363 "Invalid invocationId returned");
365 talloc_free(schema_info);
372 * Reset schemaInfo record to know value
374 static bool _drsut_ldb_schema_info_reset(struct torture_context *tctx,
375 struct ldb_context *ldb,
376 const char *schema_info_str,
382 struct ldb_message *msg;
383 TALLOC_CTX *mem_ctx = talloc_new(tctx);
385 blob = strhex_to_data_blob(mem_ctx, schema_info_str);
386 torture_assert_goto(tctx, blob.data, bret, DONE, "Not enough memory!");
388 msg = ldb_msg_new(mem_ctx);
389 torture_assert_goto(tctx, msg, bret, DONE, "Not enough memory!");
391 msg->dn = ldb_get_schema_basedn(ldb);
392 ldb_err = ldb_msg_add_value(msg, "schemaInfo", &blob, NULL);
393 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
394 "ldb_msg_add_value() failed");
397 ldb_err = ldb_add(ldb, msg);
399 ldb_err = dsdb_replace(ldb, msg, DSDB_MODIFY_PERMISSIVE);
401 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
402 "dsdb_replace() failed");
405 talloc_free(mem_ctx);
410 * Prepare temporary LDB and opens it
412 static bool _drsut_ldb_setup(struct torture_context *tctx, struct drsut_schemainfo_data *priv)
417 char *tempdir = NULL;
421 mem_ctx = talloc_new(priv);
422 torture_assert(tctx, mem_ctx, "Not enough memory!");
424 status = torture_temp_dir(tctx, "drs_", &tempdir);
425 torture_assert_ntstatus_ok_goto(tctx, status, bret, DONE, "creating temp dir");
427 ldb_url = talloc_asprintf(priv, "%s/drs_schemainfo.ldb", tempdir);
428 torture_assert_goto(tctx, ldb_url, bret, DONE, "Not enough memory!");
431 priv->ldb = ldb_wrap_connect(priv, tctx->ev, tctx->lp_ctx,
432 ldb_url, NULL, NULL, 0);
433 torture_assert_goto(tctx, priv->ldb, bret, DONE, "ldb_wrap_connect() failed");
435 /* set some schemaNamingContext */
436 ldb_err = ldb_set_opaque(priv->ldb,
437 "schemaNamingContext",
438 ldb_dn_new(priv->ldb, priv->ldb, "CN=Schema,CN=Config"));
439 torture_assert_int_equal_goto(tctx, ldb_err, LDB_SUCCESS, bret, DONE,
440 "ldb_set_opaque() failed");
442 /* add schemaInfo attribute so tested layer could work properly */
443 torture_assert_goto(tctx,
444 _drsut_ldb_schema_info_reset(tctx, priv->ldb, SCHEMA_INFO_INIT_STR, true),
446 "_drsut_ldb_schema_info_reset() failed");
449 talloc_free(tempdir);
450 talloc_free(mem_ctx);
455 * Setup/Teardown for test case
457 static bool torture_drs_unit_schemainfo_setup(struct torture_context *tctx,
458 struct drsut_schemainfo_data **_priv)
465 struct drsut_schemainfo_data *priv;
467 priv = talloc_zero(tctx, struct drsut_schemainfo_data);
468 torture_assert(tctx, priv, "Not enough memory!");
470 /* returned allocated pointer here
471 * teardown() will be called even in case of failure,
472 * so we'll get a changes to clean up */
475 /* create initial schemaInfo */
477 _drsut_schemainfo_new(tctx, SCHEMA_INFO_DEFAULT_STR, &priv->schema_info),
478 "Failed to create schema_info test object");
480 /* create data to test with */
481 priv->test_data_count = ARRAY_SIZE(_schemainfo_test_data);
482 priv->test_data = talloc_array(tctx, struct schemainfo_data, priv->test_data_count);
484 for (i = 0; i < ARRAY_SIZE(_schemainfo_test_data); i++) {
485 struct schemainfo_data *data = &priv->test_data[i];
487 ndr_blob = strhex_to_data_blob(priv,
488 _schemainfo_test_data[i].schema_info_str);
489 torture_assert(tctx, ndr_blob.data, "Not enough memory!");
491 status = GUID_from_string(_schemainfo_test_data[i].guid_str, &guid);
492 torture_assert_ntstatus_ok(tctx, status,
493 talloc_asprintf(tctx,
494 "GUID_from_string() failed for %s",
495 _schemainfo_test_data[i].guid_str));
497 data->ndr_blob = ndr_blob;
498 data->schi.invocation_id = guid;
499 data->schi.revision = _schemainfo_test_data[i].revision;
500 data->werr_expected = _schemainfo_test_data[i].werr_expected;
501 data->test_both_ways = _schemainfo_test_data[i].test_both_ways;
505 /* create temporary LDB and populate with data */
506 if (!_drsut_ldb_setup(tctx, priv)) {
510 /* create ldb_module mockup object */
511 priv->ldb_module = ldb_module_new(priv, priv->ldb, "schemaInfo_test_module", NULL);
512 torture_assert(tctx, priv->ldb_module, "Not enough memory!");
514 /* create schema mockup object */
515 priv->schema = dsdb_new_schema(priv, lp_iconv_convenience(tctx->lp_ctx));
517 /* pre-cache invocationId for samdb_ntds_invocation_id()
518 * to work with our mock ldb */
519 ldb_err = ldb_set_opaque(priv->ldb, "cache.invocation_id",
520 &priv->schema_info->invocation_id);
521 torture_assert_int_equal(tctx, ldb_err, LDB_SUCCESS, "ldb_set_opaque() failed");
523 /* Perform all tests in transactions so that
524 * underlying modify calls not to fail */
525 ldb_err = ldb_transaction_start(priv->ldb);
526 torture_assert_int_equal(tctx,
529 "ldb_transaction_start() failed");
534 static bool torture_drs_unit_schemainfo_teardown(struct torture_context *tctx,
535 struct drsut_schemainfo_data *priv)
539 /* commit pending transaction so we will
540 * be able to check what LDB state is */
541 ldb_err = ldb_transaction_commit(priv->ldb);
542 if (ldb_err != LDB_SUCCESS) {
543 torture_comment(tctx, "ldb_transaction_commit() - %s (%s)",
544 ldb_strerror(ldb_err),
545 ldb_errstring(priv->ldb));
554 * Test case initialization for
555 * DRS-UNIT.schemaInfo
557 struct torture_tcase * torture_drs_unit_schemainfo(struct torture_suite *suite)
559 typedef bool (*pfn_setup)(struct torture_context *, void **);
560 typedef bool (*pfn_teardown)(struct torture_context *, void *);
561 typedef bool (*pfn_run)(struct torture_context *, void *);
563 struct torture_tcase * tc = torture_suite_add_tcase(suite, "schemaInfo");
565 torture_tcase_set_fixture(tc,
566 (pfn_setup)torture_drs_unit_schemainfo_setup,
567 (pfn_teardown)torture_drs_unit_schemainfo_teardown);
569 tc->description = talloc_strdup(tc, "Unit tests for DRSUAPI::schemaInfo implementation");
571 torture_tcase_add_simple_test(tc, "dsdb_schema_info_from_blob",
572 (pfn_run)test_dsdb_schema_info_from_blob);
573 torture_tcase_add_simple_test(tc, "dsdb_blob_from_schema_info",
574 (pfn_run)test_dsdb_blob_from_schema_info);
575 torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_blob read|write",
576 (pfn_run)test_dsdb_module_schema_info_blob_rw);
577 torture_tcase_add_simple_test(tc, "dsdb_schema_info_create",
578 (pfn_run)test_dsdb_schema_info_create);
579 torture_tcase_add_simple_test(tc, "dsdb_module_schema_info_update",
580 (pfn_run)test_dsdb_module_schema_info_update);