4 Copyright (C) Andrew Tridgell 2004
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
29 * Description: utility to test ldb
31 * Author: Andrew Tridgell
35 #include "system/filesys.h"
36 #include "system/time.h"
38 #include "tools/cmdline.h"
40 static struct timespec tp1
,tp2
;
41 static struct ldb_cmdline
*options
;
43 static void _start_timer(void)
45 if (clock_gettime(CUSTOM_CLOCK_MONOTONIC
, &tp1
) != 0) {
46 clock_gettime(CLOCK_REALTIME
, &tp1
);
50 static double _end_timer(void)
52 if (clock_gettime(CUSTOM_CLOCK_MONOTONIC
, &tp2
) != 0) {
53 clock_gettime(CLOCK_REALTIME
, &tp2
);
55 return((tp2
.tv_sec
- tp1
.tv_sec
) +
56 (tp2
.tv_nsec
- tp1
.tv_nsec
)*1.0e-9);
59 static void add_records(struct ldb_context
*ldb
,
60 struct ldb_dn
*basedn
,
63 struct ldb_message msg
;
67 if (ldb_lock(ldb
, "transaction") != 0) {
68 printf("transaction lock failed\n");
69 exit(LDB_ERR_OPERATIONS_ERROR
);
72 for (i
=0;i
<count
;i
++) {
73 struct ldb_message_element el
[6];
74 struct ldb_val vals
[6][1];
76 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
78 name
= talloc_asprintf(tmp_ctx
, "Test%d", i
);
80 msg
.dn
= ldb_dn_copy(tmp_ctx
, basedn
);
81 ldb_dn_add_child_fmt(msg
.dn
, "cn=%s", name
);
86 el
[0].name
= talloc_strdup(tmp_ctx
, "cn");
88 el
[0].values
= vals
[0];
89 vals
[0][0].data
= (uint8_t *)name
;
90 vals
[0][0].length
= strlen(name
);
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
);
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
);
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
);
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
);
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
);
127 ldb_delete(ldb
, msg
.dn
);
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
);
134 printf("adding uid %s\r", name
);
137 talloc_free(tmp_ctx
);
140 if (ldb_unlock(ldb
, "transaction") != 0) {
141 printf("transaction unlock failed\n");
142 exit(LDB_ERR_OPERATIONS_ERROR
);
148 static void modify_records(struct ldb_context
*ldb
,
149 struct ldb_dn
*basedn
,
152 struct ldb_message msg
;
155 for (i
=0;i
<count
;i
++) {
156 struct ldb_message_element el
[3];
157 struct ldb_val vals
[3];
159 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
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
);
165 msg
.num_elements
= 3;
168 el
[0].flags
= LDB_FLAG_MOD_DELETE
;
169 el
[0].name
= talloc_strdup(tmp_ctx
, "mail");
170 el
[0].num_values
= 0;
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
);
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
);
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
);
191 printf("Modifying uid %s\r", name
);
194 talloc_free(tmp_ctx
);
201 static void delete_records(struct ldb_context
*ldb
,
202 struct ldb_dn
*basedn
,
207 for (i
=0;i
<count
;i
++) {
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
);
213 printf("Deleting uid Test%d\r", i
);
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
);
226 static void search_uid(struct ldb_context
*ldb
, struct ldb_dn
*basedn
,
227 unsigned int nrecords
, unsigned int nsearches
)
231 for (i
=0;i
<nsearches
;i
++) {
232 int uid
= (i
* 700 + 17) % (nrecords
* 2);
234 struct ldb_result
*res
= NULL
;
237 expr
= talloc_asprintf(ldb
, "(uid=TEST%d)", uid
);
238 ret
= ldb_search(ldb
, ldb
, &res
, basedn
, LDB_SCOPE_SUBTREE
, NULL
, "%s", expr
);
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
);
245 if (uid
>= nrecords
&& res
->count
> 0) {
246 printf("Found %s !? - %d\n", expr
, ret
);
247 exit(LDB_ERR_OPERATIONS_ERROR
);
250 printf("Testing uid %d/%d - %d \r", i
, uid
, res
->count
);
260 static void start_test(struct ldb_context
*ldb
, unsigned int nrecords
,
261 unsigned int nsearches
)
263 struct ldb_dn
*basedn
;
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
);
271 printf("Adding %d records\n", nrecords
);
272 add_records(ldb
, basedn
, nrecords
);
274 printf("Starting search on uid\n");
276 search_uid(ldb
, basedn
, nrecords
, nsearches
);
277 printf("uid search took %.2f seconds\n", _end_timer());
279 printf("Modifying records\n");
280 modify_records(ldb
, basedn
, nrecords
);
282 printf("Deleting records\n");
283 delete_records(ldb
, basedn
, nrecords
);
288 2) Store an @indexlist record
290 3) Store a record that contains fields that should be index according
293 4) disconnection from database
295 5) connect to same database
297 6) search for record added in step 3 using a search key that should
300 static void start_test_index(struct ldb_context
**ldb
)
302 struct ldb_message
*msg
;
303 struct ldb_result
*res
= NULL
;
304 struct ldb_dn
*indexlist
;
305 struct ldb_dn
*basedn
;
307 unsigned int flags
= 0;
308 const char *specials
;
310 specials
= getenv("LDB_SPECIALS");
311 if (specials
&& atoi(specials
) == 0) {
312 printf("LDB_SPECIALS disabled - skipping index test\n");
316 if (options
->nosync
) {
317 flags
|= LDB_FLG_NOSYNC
;
320 printf("Starting index test\n");
322 indexlist
= ldb_dn_new(*ldb
, *ldb
, "@INDEXLIST");
324 ldb_delete(*ldb
, indexlist
);
326 msg
= ldb_msg_new(NULL
);
329 ldb_msg_add_string(msg
, "@IDXATTR", strdup("uid"));
331 if (ldb_add(*ldb
, msg
) != 0) {
332 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg
->dn
), ldb_errstring(*ldb
));
333 exit(LDB_ERR_OPERATIONS_ERROR
);
336 basedn
= ldb_dn_new(*ldb
, *ldb
, options
->basedn
);
338 memset(msg
, 0, sizeof(*msg
));
339 msg
->dn
= ldb_dn_copy(msg
, basedn
);
340 ldb_dn_add_child_fmt(msg
->dn
, "cn=test");
341 ldb_msg_add_string(msg
, "cn", strdup("test"));
342 ldb_msg_add_string(msg
, "sn", strdup("test"));
343 ldb_msg_add_string(msg
, "uid", strdup("test"));
344 ldb_msg_add_string(msg
, "objectClass", strdup("OpenLDAPperson"));
346 if (ldb_add(*ldb
, msg
) != LDB_SUCCESS
) {
347 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg
->dn
), ldb_errstring(*ldb
));
348 exit(LDB_ERR_OPERATIONS_ERROR
);
351 if (talloc_free(*ldb
) != 0) {
352 printf("failed to free/close ldb database");
353 exit(LDB_ERR_OPERATIONS_ERROR
);
356 (*ldb
) = ldb_init(options
, NULL
);
358 ret
= ldb_connect(*ldb
, options
->url
, flags
, NULL
);
359 if (ret
!= LDB_SUCCESS
) {
360 printf("failed to connect to %s\n", options
->url
);
361 exit(LDB_ERR_OPERATIONS_ERROR
);
364 basedn
= ldb_dn_new(*ldb
, *ldb
, options
->basedn
);
366 ldb_dn_add_child_fmt(msg
->dn
, "cn=test");
368 ret
= ldb_search(*ldb
, *ldb
, &res
, basedn
, LDB_SCOPE_SUBTREE
, NULL
, "uid=test");
369 if (ret
!= LDB_SUCCESS
) {
370 printf("Search with (uid=test) filter failed!\n");
371 exit(LDB_ERR_OPERATIONS_ERROR
);
373 if(res
->count
!= 1) {
374 printf("Should have found 1 record - found %d\n", res
->count
);
375 exit(LDB_ERR_OPERATIONS_ERROR
);
378 indexlist
= ldb_dn_new(*ldb
, *ldb
, "@INDEXLIST");
380 if (ldb_delete(*ldb
, msg
->dn
) != 0 ||
381 ldb_delete(*ldb
, indexlist
) != 0) {
382 printf("cleanup failed - %s\n", ldb_errstring(*ldb
));
383 exit(LDB_ERR_OPERATIONS_ERROR
);
386 printf("Finished index test\n");
390 static void usage(struct ldb_context
*ldb
)
392 printf("Usage: ldbtest <options>\n");
393 printf("Options:\n");
394 printf(" -H ldb_url choose the database (or $LDB_URL)\n");
395 printf(" --num-records nrecords database size to use\n");
396 printf(" --num-searches nsearches number of searches to do\n");
398 printf("tests ldb API\n\n");
399 exit(LDB_ERR_OPERATIONS_ERROR
);
402 int main(int argc
, const char **argv
)
404 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
405 struct ldb_context
*ldb
;
407 ldb
= ldb_init(mem_ctx
, NULL
);
409 return LDB_ERR_OPERATIONS_ERROR
;
412 options
= ldb_cmdline_process(ldb
, argc
, argv
, usage
);
414 talloc_steal(mem_ctx
, options
);
416 if (options
->basedn
== NULL
) {
417 options
->basedn
= "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST";
422 printf("Testing with num-records=%d and num-searches=%d\n",
423 options
->num_records
, options
->num_searches
);
426 (unsigned int) options
->num_records
,
427 (unsigned int) options
->num_searches
);
429 start_test_index(&ldb
);
431 talloc_free(mem_ctx
);