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