1/* 2 ldb database library 3 4 Copyright (C) Andrew Tridgell 2004 5 6 ** NOTE! The following LGPL license applies to the ldb 7 ** library. This does NOT imply that all of Samba is released 8 ** under the LGPL 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 3 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, see <http://www.gnu.org/licenses/>. 22*/ 23 24/* 25 * Name: ldb 26 * 27 * Component: ldbtest 28 * 29 * Description: utility to test ldb 30 * 31 * Author: Andrew Tridgell 32 */ 33 34#include "ldb_includes.h" 35#include "ldb.h" 36#include "tools/cmdline.h" 37 38static struct timeval tp1,tp2; 39static struct ldb_cmdline *options; 40 41static void _start_timer(void) 42{ 43 gettimeofday(&tp1,NULL); 44} 45 46static double _end_timer(void) 47{ 48 gettimeofday(&tp2,NULL); 49 return((tp2.tv_sec - tp1.tv_sec) + 50 (tp2.tv_usec - tp1.tv_usec)*1.0e-6); 51} 52 53static void add_records(struct ldb_context *ldb, 54 struct ldb_dn *basedn, 55 int count) 56{ 57 struct ldb_message msg; 58 int i; 59 60#if 0 61 if (ldb_lock(ldb, "transaction") != 0) { 62 printf("transaction lock failed\n"); 63 exit(1); 64 } 65#endif 66 for (i=0;i<count;i++) { 67 struct ldb_message_element el[6]; 68 struct ldb_val vals[6][1]; 69 char *name; 70 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 71 72 name = talloc_asprintf(tmp_ctx, "Test%d", i); 73 74 msg.dn = ldb_dn_copy(tmp_ctx, basedn); 75 ldb_dn_add_child_fmt(msg.dn, "cn=%s", name); 76 msg.num_elements = 6; 77 msg.elements = el; 78 79 el[0].flags = 0; 80 el[0].name = talloc_strdup(tmp_ctx, "cn"); 81 el[0].num_values = 1; 82 el[0].values = vals[0]; 83 vals[0][0].data = (uint8_t *)name; 84 vals[0][0].length = strlen(name); 85 86 el[1].flags = 0; 87 el[1].name = "title"; 88 el[1].num_values = 1; 89 el[1].values = vals[1]; 90 vals[1][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "The title of %s", name); 91 vals[1][0].length = strlen((char *)vals[1][0].data); 92 93 el[2].flags = 0; 94 el[2].name = talloc_strdup(tmp_ctx, "uid"); 95 el[2].num_values = 1; 96 el[2].values = vals[2]; 97 vals[2][0].data = (uint8_t *)ldb_casefold(ldb, tmp_ctx, name, strlen(name)); 98 vals[2][0].length = strlen((char *)vals[2][0].data); 99 100 el[3].flags = 0; 101 el[3].name = talloc_strdup(tmp_ctx, "mail"); 102 el[3].num_values = 1; 103 el[3].values = vals[3]; 104 vals[3][0].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@example.com", name); 105 vals[3][0].length = strlen((char *)vals[3][0].data); 106 107 el[4].flags = 0; 108 el[4].name = talloc_strdup(tmp_ctx, "objectClass"); 109 el[4].num_values = 1; 110 el[4].values = vals[4]; 111 vals[4][0].data = (uint8_t *)talloc_strdup(tmp_ctx, "OpenLDAPperson"); 112 vals[4][0].length = strlen((char *)vals[4][0].data); 113 114 el[5].flags = 0; 115 el[5].name = talloc_strdup(tmp_ctx, "sn"); 116 el[5].num_values = 1; 117 el[5].values = vals[5]; 118 vals[5][0].data = (uint8_t *)name; 119 vals[5][0].length = strlen((char *)vals[5][0].data); 120 121 ldb_delete(ldb, msg.dn); 122 123 if (ldb_add(ldb, &msg) != 0) { 124 printf("Add of %s failed - %s\n", name, ldb_errstring(ldb)); 125 exit(1); 126 } 127 128 printf("adding uid %s\r", name); 129 fflush(stdout); 130 131 talloc_free(tmp_ctx); 132 } 133#if 0 134 if (ldb_unlock(ldb, "transaction") != 0) { 135 printf("transaction unlock failed\n"); 136 exit(1); 137 } 138#endif 139 printf("\n"); 140} 141 142static void modify_records(struct ldb_context *ldb, 143 struct ldb_dn *basedn, 144 int count) 145{ 146 struct ldb_message msg; 147 int i; 148 149 for (i=0;i<count;i++) { 150 struct ldb_message_element el[3]; 151 struct ldb_val vals[3]; 152 char *name; 153 TALLOC_CTX *tmp_ctx = talloc_new(ldb); 154 155 name = talloc_asprintf(tmp_ctx, "Test%d", i); 156 msg.dn = ldb_dn_copy(tmp_ctx, basedn); 157 ldb_dn_add_child_fmt(msg.dn, "cn=%s", name); 158 159 msg.num_elements = 3; 160 msg.elements = el; 161 162 el[0].flags = LDB_FLAG_MOD_DELETE; 163 el[0].name = talloc_strdup(tmp_ctx, "mail"); 164 el[0].num_values = 0; 165 166 el[1].flags = LDB_FLAG_MOD_ADD; 167 el[1].name = talloc_strdup(tmp_ctx, "mail"); 168 el[1].num_values = 1; 169 el[1].values = &vals[1]; 170 vals[1].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other.example.com", name); 171 vals[1].length = strlen((char *)vals[1].data); 172 173 el[2].flags = LDB_FLAG_MOD_REPLACE; 174 el[2].name = talloc_strdup(tmp_ctx, "mail"); 175 el[2].num_values = 1; 176 el[2].values = &vals[2]; 177 vals[2].data = (uint8_t *)talloc_asprintf(tmp_ctx, "%s@other2.example.com", name); 178 vals[2].length = strlen((char *)vals[2].data); 179 180 if (ldb_modify(ldb, &msg) != 0) { 181 printf("Modify of %s failed - %s\n", name, ldb_errstring(ldb)); 182 exit(1); 183 } 184 185 printf("Modifying uid %s\r", name); 186 fflush(stdout); 187 188 talloc_free(tmp_ctx); 189 } 190 191 printf("\n"); 192} 193 194 195static void delete_records(struct ldb_context *ldb, 196 struct ldb_dn *basedn, 197 int count) 198{ 199 int i; 200 201 for (i=0;i<count;i++) { 202 struct ldb_dn *dn; 203 char *name = talloc_asprintf(ldb, "Test%d", i); 204 dn = ldb_dn_copy(name, basedn); 205 ldb_dn_add_child_fmt(dn, "cn=%s", name); 206 207 printf("Deleting uid Test%d\r", i); 208 fflush(stdout); 209 210 if (ldb_delete(ldb, dn) != 0) { 211 printf("Delete of %s failed - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)); 212 exit(1); 213 } 214 talloc_free(name); 215 } 216 217 printf("\n"); 218} 219 220static void search_uid(struct ldb_context *ldb, struct ldb_dn *basedn, int nrecords, int nsearches) 221{ 222 int i; 223 224 for (i=0;i<nsearches;i++) { 225 int uid = (i * 700 + 17) % (nrecords * 2); 226 char *expr; 227 struct ldb_result *res = NULL; 228 int ret; 229 230 expr = talloc_asprintf(ldb, "(uid=TEST%d)", uid); 231 ret = ldb_search(ldb, ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "%s", expr); 232 233 if (ret != LDB_SUCCESS || (uid < nrecords && res->count != 1)) { 234 printf("Failed to find %s - %s\n", expr, ldb_errstring(ldb)); 235 exit(1); 236 } 237 238 if (uid >= nrecords && res->count > 0) { 239 printf("Found %s !? - %d\n", expr, ret); 240 exit(1); 241 } 242 243 printf("testing uid %d/%d - %d \r", i, uid, res->count); 244 fflush(stdout); 245 246 talloc_free(res); 247 talloc_free(expr); 248 } 249 250 printf("\n"); 251} 252 253static void start_test(struct ldb_context *ldb, int nrecords, int nsearches) 254{ 255 struct ldb_dn *basedn; 256 257 basedn = ldb_dn_new(ldb, ldb, options->basedn); 258 if ( ! ldb_dn_validate(basedn)) { 259 printf("Invalid base DN\n"); 260 exit(1); 261 } 262 263 printf("Adding %d records\n", nrecords); 264 add_records(ldb, basedn, nrecords); 265 266 printf("Starting search on uid\n"); 267 _start_timer(); 268 search_uid(ldb, basedn, nrecords, nsearches); 269 printf("uid search took %.2f seconds\n", _end_timer()); 270 271 printf("Modifying records\n"); 272 modify_records(ldb, basedn, nrecords); 273 274 printf("Deleting records\n"); 275 delete_records(ldb, basedn, nrecords); 276} 277 278 279/* 280 2) Store an @indexlist record 281 282 3) Store a record that contains fields that should be index according 283to @index 284 285 4) disconnection from database 286 287 5) connect to same database 288 289 6) search for record added in step 3 using a search key that should 290be indexed 291*/ 292static void start_test_index(struct ldb_context **ldb) 293{ 294 struct ldb_message *msg; 295 struct ldb_result *res = NULL; 296 struct ldb_dn *indexlist; 297 struct ldb_dn *basedn; 298 int ret; 299 int flags = 0; 300 const char *specials; 301 302 specials = getenv("LDB_SPECIALS"); 303 if (specials && atoi(specials) == 0) { 304 printf("LDB_SPECIALS disabled - skipping index test\n"); 305 return; 306 } 307 308 if (options->nosync) { 309 flags |= LDB_FLG_NOSYNC; 310 } 311 312 printf("Starting index test\n"); 313 314 indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); 315 316 ldb_delete(*ldb, indexlist); 317 318 msg = ldb_msg_new(NULL); 319 320 msg->dn = indexlist; 321 ldb_msg_add_string(msg, "@IDXATTR", strdup("uid")); 322 323 if (ldb_add(*ldb, msg) != 0) { 324 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); 325 exit(1); 326 } 327 328 basedn = ldb_dn_new(*ldb, *ldb, options->basedn); 329 330 memset(msg, 0, sizeof(*msg)); 331 msg->dn = ldb_dn_copy(msg, basedn); 332 ldb_dn_add_child_fmt(msg->dn, "cn=test"); 333 ldb_msg_add_string(msg, "cn", strdup("test")); 334 ldb_msg_add_string(msg, "sn", strdup("test")); 335 ldb_msg_add_string(msg, "uid", strdup("test")); 336 ldb_msg_add_string(msg, "objectClass", strdup("OpenLDAPperson")); 337 338 if (ldb_add(*ldb, msg) != 0) { 339 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(*ldb)); 340 exit(1); 341 } 342 343 if (talloc_free(*ldb) != 0) { 344 printf("failed to free/close ldb database"); 345 exit(1); 346 } 347 348 (*ldb) = ldb_init(options, NULL); 349 350 ret = ldb_connect(*ldb, options->url, flags, NULL); 351 if (ret != 0) { 352 printf("failed to connect to %s\n", options->url); 353 exit(1); 354 } 355 356 basedn = ldb_dn_new(*ldb, *ldb, options->basedn); 357 358 ret = ldb_search(*ldb, *ldb, &res, basedn, LDB_SCOPE_SUBTREE, NULL, "uid=test"); 359 if (ret != LDB_SUCCESS) { 360 printf("Search with (uid=test) filter failed!\n"); 361 exit(1); 362 } 363 if(res->count != 1) { 364 printf("Should have found 1 record - found %d\n", res->count); 365 exit(1); 366 } 367 368 indexlist = ldb_dn_new(*ldb, *ldb, "@INDEXLIST"); 369 370 if (ldb_delete(*ldb, msg->dn) != 0 || 371 ldb_delete(*ldb, indexlist) != 0) { 372 printf("cleanup failed - %s\n", ldb_errstring(*ldb)); 373 exit(1); 374 } 375 376 printf("Finished index test\n"); 377} 378 379 380static void usage(void) 381{ 382 printf("Usage: ldbtest <options>\n"); 383 printf("Options:\n"); 384 printf(" -H ldb_url choose the database (or $LDB_URL)\n"); 385 printf(" --num-records nrecords database size to use\n"); 386 printf(" --num-searches nsearches number of searches to do\n"); 387 printf("\n"); 388 printf("tests ldb API\n\n"); 389 exit(1); 390} 391 392int main(int argc, const char **argv) 393{ 394 TALLOC_CTX *mem_ctx = talloc_new(NULL); 395 struct ldb_context *ldb; 396 397 ldb = ldb_init(mem_ctx, NULL); 398 399 options = ldb_cmdline_process(ldb, argc, argv, usage); 400 401 talloc_steal(mem_ctx, options); 402 403 if (options->basedn == NULL) { 404 options->basedn = "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST"; 405 } 406 407 srandom(1); 408 409 printf("Testing with num-records=%d and num-searches=%d\n", 410 options->num_records, options->num_searches); 411 412 start_test(ldb, options->num_records, options->num_searches); 413 414 start_test_index(&ldb); 415 416 talloc_free(mem_ctx); 417 418 return 0; 419} 420