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