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
37 #include "ldb_includes.h"
41 #include "tools/cmdline.h"
43 static struct timeval tp1
,tp2
;
44 static struct ldb_cmdline
*options
;
46 static void _start_timer(void)
48 gettimeofday(&tp1
,NULL
);
51 static double _end_timer(void)
53 gettimeofday(&tp2
,NULL
);
54 return((tp2
.tv_sec
- tp1
.tv_sec
) +
55 (tp2
.tv_usec
- tp1
.tv_usec
)*1.0e-6);
58 static void add_records(struct ldb_context
*ldb
,
59 struct ldb_dn
*basedn
,
62 struct ldb_message msg
;
66 if (ldb_lock(ldb
, "transaction") != 0) {
67 printf("transaction lock failed\n");
71 for (i
=0;i
<count
;i
++) {
72 struct ldb_message_element el
[6];
73 struct ldb_val vals
[6][1];
75 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
77 name
= talloc_asprintf(tmp_ctx
, "Test%d", i
);
79 msg
.dn
= ldb_dn_copy(tmp_ctx
, basedn
);
80 ldb_dn_add_child_fmt(msg
.dn
, "cn=%s", name
);
85 el
[0].name
= talloc_strdup(tmp_ctx
, "cn");
87 el
[0].values
= vals
[0];
88 vals
[0][0].data
= (uint8_t *)name
;
89 vals
[0][0].length
= strlen(name
);
94 el
[1].values
= vals
[1];
95 vals
[1][0].data
= (uint8_t *)talloc_asprintf(tmp_ctx
, "The title of %s", name
);
96 vals
[1][0].length
= strlen((char *)vals
[1][0].data
);
99 el
[2].name
= talloc_strdup(tmp_ctx
, "uid");
100 el
[2].num_values
= 1;
101 el
[2].values
= vals
[2];
102 vals
[2][0].data
= (uint8_t *)ldb_casefold(ldb
, tmp_ctx
, name
, strlen(name
));
103 vals
[2][0].length
= strlen((char *)vals
[2][0].data
);
106 el
[3].name
= talloc_strdup(tmp_ctx
, "mail");
107 el
[3].num_values
= 1;
108 el
[3].values
= vals
[3];
109 vals
[3][0].data
= (uint8_t *)talloc_asprintf(tmp_ctx
, "%s@example.com", name
);
110 vals
[3][0].length
= strlen((char *)vals
[3][0].data
);
113 el
[4].name
= talloc_strdup(tmp_ctx
, "objectClass");
114 el
[4].num_values
= 1;
115 el
[4].values
= vals
[4];
116 vals
[4][0].data
= (uint8_t *)talloc_strdup(tmp_ctx
, "OpenLDAPperson");
117 vals
[4][0].length
= strlen((char *)vals
[4][0].data
);
120 el
[5].name
= talloc_strdup(tmp_ctx
, "sn");
121 el
[5].num_values
= 1;
122 el
[5].values
= vals
[5];
123 vals
[5][0].data
= (uint8_t *)name
;
124 vals
[5][0].length
= strlen((char *)vals
[5][0].data
);
126 ldb_delete(ldb
, msg
.dn
);
128 if (ldb_add(ldb
, &msg
) != 0) {
129 printf("Add of %s failed - %s\n", name
, ldb_errstring(ldb
));
133 printf("adding uid %s\r", name
);
136 talloc_free(tmp_ctx
);
139 if (ldb_unlock(ldb
, "transaction") != 0) {
140 printf("transaction unlock failed\n");
147 static void modify_records(struct ldb_context
*ldb
,
148 struct ldb_dn
*basedn
,
151 struct ldb_message msg
;
154 for (i
=0;i
<count
;i
++) {
155 struct ldb_message_element el
[3];
156 struct ldb_val vals
[3];
158 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
160 name
= talloc_asprintf(tmp_ctx
, "Test%d", i
);
161 msg
.dn
= ldb_dn_copy(tmp_ctx
, basedn
);
162 ldb_dn_add_child_fmt(msg
.dn
, "cn=%s", name
);
164 msg
.num_elements
= 3;
167 el
[0].flags
= LDB_FLAG_MOD_DELETE
;
168 el
[0].name
= talloc_strdup(tmp_ctx
, "mail");
169 el
[0].num_values
= 0;
171 el
[1].flags
= LDB_FLAG_MOD_ADD
;
172 el
[1].name
= talloc_strdup(tmp_ctx
, "mail");
173 el
[1].num_values
= 1;
174 el
[1].values
= &vals
[1];
175 vals
[1].data
= (uint8_t *)talloc_asprintf(tmp_ctx
, "%s@other.example.com", name
);
176 vals
[1].length
= strlen((char *)vals
[1].data
);
178 el
[2].flags
= LDB_FLAG_MOD_REPLACE
;
179 el
[2].name
= talloc_strdup(tmp_ctx
, "mail");
180 el
[2].num_values
= 1;
181 el
[2].values
= &vals
[2];
182 vals
[2].data
= (uint8_t *)talloc_asprintf(tmp_ctx
, "%s@other2.example.com", name
);
183 vals
[2].length
= strlen((char *)vals
[2].data
);
185 if (ldb_modify(ldb
, &msg
) != 0) {
186 printf("Modify of %s failed - %s\n", name
, ldb_errstring(ldb
));
190 printf("Modifying uid %s\r", name
);
193 talloc_free(tmp_ctx
);
200 static void delete_records(struct ldb_context
*ldb
,
201 struct ldb_dn
*basedn
,
206 for (i
=0;i
<count
;i
++) {
208 char *name
= talloc_asprintf(ldb
, "Test%d", i
);
209 dn
= ldb_dn_copy(name
, basedn
);
210 ldb_dn_add_child_fmt(dn
, "cn=%s", name
);
212 printf("Deleting uid Test%d\r", i
);
215 if (ldb_delete(ldb
, dn
) != 0) {
216 printf("Delete of %s failed - %s\n", ldb_dn_get_linearized(dn
), ldb_errstring(ldb
));
225 static void search_uid(struct ldb_context
*ldb
, struct ldb_dn
*basedn
,
226 unsigned int nrecords
, unsigned int nsearches
)
230 for (i
=0;i
<nsearches
;i
++) {
231 int uid
= (i
* 700 + 17) % (nrecords
* 2);
233 struct ldb_result
*res
= NULL
;
236 expr
= talloc_asprintf(ldb
, "(uid=TEST%d)", uid
);
237 ret
= ldb_search(ldb
, ldb
, &res
, basedn
, LDB_SCOPE_SUBTREE
, NULL
, "%s", expr
);
239 if (ret
!= LDB_SUCCESS
|| (uid
< nrecords
&& res
->count
!= 1)) {
240 printf("Failed to find %s - %s\n", expr
, ldb_errstring(ldb
));
244 if (uid
>= nrecords
&& res
->count
> 0) {
245 printf("Found %s !? - %d\n", expr
, ret
);
249 printf("Testing uid %d/%d - %d \r", i
, uid
, res
->count
);
259 static void start_test(struct ldb_context
*ldb
, unsigned int nrecords
,
260 unsigned int nsearches
)
262 struct ldb_dn
*basedn
;
264 basedn
= ldb_dn_new(ldb
, ldb
, options
->basedn
);
265 if ( ! ldb_dn_validate(basedn
)) {
266 printf("Invalid base DN\n");
270 printf("Adding %d records\n", nrecords
);
271 add_records(ldb
, basedn
, nrecords
);
273 printf("Starting search on uid\n");
275 search_uid(ldb
, basedn
, nrecords
, nsearches
);
276 printf("uid search took %.2f seconds\n", _end_timer());
278 printf("Modifying records\n");
279 modify_records(ldb
, basedn
, nrecords
);
281 printf("Deleting records\n");
282 delete_records(ldb
, basedn
, nrecords
);
287 2) Store an @indexlist record
289 3) Store a record that contains fields that should be index according
292 4) disconnection from database
294 5) connect to same database
296 6) search for record added in step 3 using a search key that should
299 static void start_test_index(struct ldb_context
**ldb
)
301 struct ldb_message
*msg
;
302 struct ldb_result
*res
= NULL
;
303 struct ldb_dn
*indexlist
;
304 struct ldb_dn
*basedn
;
307 const char *specials
;
309 specials
= getenv("LDB_SPECIALS");
310 if (specials
&& atoi(specials
) == 0) {
311 printf("LDB_SPECIALS disabled - skipping index test\n");
315 if (options
->nosync
) {
316 flags
|= LDB_FLG_NOSYNC
;
319 printf("Starting index test\n");
321 indexlist
= ldb_dn_new(*ldb
, *ldb
, "@INDEXLIST");
323 ldb_delete(*ldb
, indexlist
);
325 msg
= ldb_msg_new(NULL
);
328 ldb_msg_add_string(msg
, "@IDXATTR", strdup("uid"));
330 if (ldb_add(*ldb
, msg
) != 0) {
331 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg
->dn
), ldb_errstring(*ldb
));
335 basedn
= ldb_dn_new(*ldb
, *ldb
, options
->basedn
);
337 memset(msg
, 0, sizeof(*msg
));
338 msg
->dn
= ldb_dn_copy(msg
, basedn
);
339 ldb_dn_add_child_fmt(msg
->dn
, "cn=test");
340 ldb_msg_add_string(msg
, "cn", strdup("test"));
341 ldb_msg_add_string(msg
, "sn", strdup("test"));
342 ldb_msg_add_string(msg
, "uid", strdup("test"));
343 ldb_msg_add_string(msg
, "objectClass", strdup("OpenLDAPperson"));
345 if (ldb_add(*ldb
, msg
) != 0) {
346 printf("Add of %s failed - %s\n", ldb_dn_get_linearized(msg
->dn
), ldb_errstring(*ldb
));
350 if (talloc_free(*ldb
) != 0) {
351 printf("failed to free/close ldb database");
355 (*ldb
) = ldb_init(options
, NULL
);
357 ret
= ldb_connect(*ldb
, options
->url
, flags
, NULL
);
359 printf("failed to connect to %s\n", options
->url
);
363 basedn
= ldb_dn_new(*ldb
, *ldb
, options
->basedn
);
365 ldb_dn_add_child_fmt(msg
->dn
, "cn=test");
367 ret
= ldb_search(*ldb
, *ldb
, &res
, basedn
, LDB_SCOPE_SUBTREE
, NULL
, "uid=test");
368 if (ret
!= LDB_SUCCESS
) {
369 printf("Search with (uid=test) filter failed!\n");
372 if(res
->count
!= 1) {
373 printf("Should have found 1 record - found %d\n", res
->count
);
377 indexlist
= ldb_dn_new(*ldb
, *ldb
, "@INDEXLIST");
379 if (ldb_delete(*ldb
, msg
->dn
) != 0 ||
380 ldb_delete(*ldb
, indexlist
) != 0) {
381 printf("cleanup failed - %s\n", ldb_errstring(*ldb
));
385 printf("Finished index test\n");
389 static void usage(void)
391 printf("Usage: ldbtest <options>\n");
392 printf("Options:\n");
393 printf(" -H ldb_url choose the database (or $LDB_URL)\n");
394 printf(" --num-records nrecords database size to use\n");
395 printf(" --num-searches nsearches number of searches to do\n");
397 printf("tests ldb API\n\n");
401 int main(int argc
, const char **argv
)
403 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
404 struct ldb_context
*ldb
;
406 ldb
= ldb_init(mem_ctx
, NULL
);
408 options
= ldb_cmdline_process(ldb
, argc
, argv
, usage
);
410 talloc_steal(mem_ctx
, options
);
412 if (options
->basedn
== NULL
) {
413 options
->basedn
= "ou=Ldb Test,ou=People,o=University of Michigan,c=TEST";
418 printf("Testing with num-records=%d and num-searches=%d\n",
419 options
->num_records
, options
->num_searches
);
422 (unsigned int) options
->num_records
,
423 (unsigned int) options
->num_searches
);
425 start_test_index(&ldb
);
427 talloc_free(mem_ctx
);