Code

dbi_test: Add some more connection tests.
[sysdb.git] / t / unit / utils / dbi_test.c
1 /*
2  * SysDB - t/unit/utils/dbi_test.c
3  * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "testutils.h"
33 #include "utils/dbi.h"
35 #include <check.h>
36 #include <dbi/dbi.h>
38 #define TEST_MAGIC ((void *)0x1337)
40 /*
41  * private data-types
42  */
43 typedef union {
44         long long   integer;
45         double      decimal;
46         const char *string;
47         time_t      datetime;
48         struct {
49                 size_t length;
50                 const unsigned char *datum;
51         } binary;
52 } mock_data_t;
54 typedef struct {
55         const char *name;
56         unsigned long long nrows;
57         unsigned long long current_row;
58         unsigned int    nfields;
59         unsigned short *field_types;
60         char          **field_names;
61 } mock_query_t;
63 /*
64  * private variables
65  */
67 static sdb_dbi_client_t *client;
69 /*
70  * mock queries
71  */
73 /* field definitions */
74 static unsigned short field_types[] = {
75         DBI_TYPE_INTEGER,
76         DBI_TYPE_DECIMAL,
77         DBI_TYPE_STRING,
78         DBI_TYPE_DATETIME,
79         DBI_TYPE_BINARY,
80 };
81 static char *field_names[] = {
82         "field0",
83         "field1",
84         "field2",
85         "field3",
86         "field4",
87 };
89 #define DATUM(p) ((const unsigned char *)(p))
90 static mock_data_t golden_data[][5] = {
91         {
92                 { .integer  = 1234   },
93                 { .decimal  = 1.234  },
94                 { .string   = "abcd" },
95                 { .datetime = 0      },
96                 { .binary   = { 1, DATUM("a") } },
97         },
98         {
99                 { .integer  = 2345   },
100                 { .decimal  = 23.45  },
101                 { .string   = "bcde" },
102                 { .datetime = 1      },
103                 { .binary   = { 4, DATUM("bcde") } },
104         },
105         {
106                 { .integer  = 3456   },
107                 { .decimal  = 345.6  },
108                 { .string   = "cd"   },
109                 { .datetime = 2      },
110                 { .binary   = { 0, DATUM(NULL) } },
111         },
112         {
113                 { .integer  = 4567   },
114                 { .decimal  = 4567   },
115                 { .string   = "d"    },
116                 { .datetime = 3      },
117                 { .binary   = { 13, DATUM("defghijklmnop") } },
118         },
119         {
120                 { .integer  = 5678   },
121                 { .decimal  = 56.78  },
122                 { .string   = "efgh" },
123                 { .datetime = 4      },
124                 { .binary   = { 5, DATUM("efghi") } },
125         },
126 };
128 /* query definitions */
129 static mock_query_t mock_queries[] = {
130         { "mockquery0", 5, 1, 0, NULL, NULL },
131         { "mockquery1", 0, 0, 1, field_types, field_names },
132         { "mockquery2", 1, 1, 1, field_types, field_names },
133         { "mockquery3", 2, 1, 1, field_types, field_names },
134         { "mockquery4", 5, 1, 1, field_types, field_names },
135         { "mockquery5", 5, 1, 2, field_types, field_names },
136         { "mockquery6", 5, 1, 3, field_types, field_names },
137         { "mockquery7", 5, 1, 4, field_types, field_names },
138         { "mockquery8", 5, 1, 5, field_types, field_names },
139 };
141 static mock_query_t *current_query = NULL;
143 /*
144  * mocked functions
145  */
147 /* dbi_driver, dbi_conn, dbi_result are void pointers */
149 #if LIBDBI_VERSION < 900
150 typedef void *dbi_inst;
152 int
153 dbi_initialize_r(const char *driverdir, dbi_inst *pInst);
154 void
155 dbi_shutdown_r(dbi_inst inst);
156 dbi_driver
157 dbi_driver_open_r(const char *name, dbi_inst inst);
158 dbi_driver
159 dbi_driver_list_r(dbi_driver curr, dbi_inst inst);
160 #endif
162 const dbi_inst INST = (void *)0x4711;
164 int
165 dbi_initialize_r(const char __attribute__((unused)) *driverdir, dbi_inst *pInst)
167         *pInst = INST;
168         return 0;
169 } /* dbi_initialize_r */
171 void
172 dbi_shutdown_r(dbi_inst inst)
174         fail_unless(inst == INST,
175                         "dbi_shutdown_r() called with unexpected inst=%p; expected %p",
176                         inst, INST);
177 } /* dbi_shutdown_r */
179 dbi_driver
180 dbi_driver_open_r(const char *name, dbi_inst inst)
182         fail_unless(inst == INST,
183                         "dbi_driver_open_r() called with unexpected inst=%p; expected %p",
184                         inst, INST);
186         if (strcmp(name, "mockdriver"))
187                 return NULL;
188         return (dbi_driver)"mockdriver";
189 } /* dbi_driver_open */
191 dbi_driver
192 dbi_driver_list_r(dbi_driver curr, dbi_inst inst)
194         fail_unless(inst == INST,
195                         "dbi_driver_list_r() called with unexpected inst=%p; expected %p",
196                         inst, INST);
198         if (!curr)
199                 return "mockdriver";
200         return NULL;
201 } /* dbi_driver_list */
203 #if LIBDBI_VERSION < 900
204 int
205 dbi_initialize(const char *driverdir)
207         return dbi_initialize_r(driverdir, NULL);
208 } /* dbi_initialize */
210 /* for some weird reason, gcc and clang complain about a missing prototype for
211  * dbi_shutdown; however, the function is declared in dbi/dbi.h */
212 void
213 dbi_shutdown(void);
214 void
215 dbi_shutdown(void)
217         dbi_shutdown_r(NULL);
218 } /* dbi_shutdown */
220 dbi_driver
221 dbi_driver_open(const char *name)
223         return dbi_driver_open_r(name, NULL);
224 } /* dbi_driver_open */
226 dbi_driver
227 dbi_driver_list(dbi_driver curr)
229         return dbi_driver_list_r(curr, NULL);
230 } /* dbi_driver_list */
231 #endif
233 const char *
234 dbi_driver_get_name(dbi_driver driver)
236         return (const char *)driver;
237 } /* dbi_driver_get_name */
239 int
240 dbi_conn_set_option(dbi_conn __attribute__((unused)) conn,
241                 const char __attribute__((unused)) *key,
242                 const char __attribute__((unused)) *value)
244         return 0;
245 } /* dbi_conn_set_option */
247 const char *
248 dbi_conn_get_option_list(dbi_conn __attribute__((unused)) conn,
249                 const char __attribute__((unused)) *key)
251         return NULL;
252 } /* dbi_conn_get_option_list */
254 dbi_conn
255 dbi_conn_open(dbi_driver driver)
257         if (strcmp((const char *)driver, "mockdriver"))
258                 return NULL;
259         return (dbi_conn)"mockconnection";
260 } /* dbi_conn_open */
262 static unsigned long long dbi_conn_connect_called = 0;
263 int
264 dbi_conn_connect(dbi_conn conn)
266         ++dbi_conn_connect_called;
267         if (strcmp((const char *)conn, "mockconnection"))
268                 return DBI_ERROR_NOCONN;
269         return 0;
270 } /* dbi_conn_connect */
272 int
273 dbi_conn_ping(dbi_conn conn)
275         if (strcmp((const char *)conn, "mockconnection"))
276                 return 0;
277         return 1;
278 } /* dbi_conn_connect */
280 void
281 dbi_conn_close(dbi_conn __attribute__((unused)) conn)
283         return;
284 } /* dbi_conn_close */
286 int
287 dbi_conn_error(dbi_conn conn, const char **errmsg)
289         if ((! conn) || (strcmp((const char *)conn, "mockconnection")))
290                 return DBI_ERROR_BADOBJECT;
291         if (errmsg)
292                 *errmsg = "mockerror";
293         return DBI_ERROR_UNSUPPORTED;
294 } /* dbi_conn_error */
296 static unsigned long long dbi_conn_query_called = 0;
297 dbi_result
298 dbi_conn_query(dbi_conn conn, const char __attribute__((unused)) *statement)
300         size_t i;
302         ++dbi_conn_query_called;
303         if (strcmp((const char *)conn, "mockconnection"))
304                 return NULL;
306         for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) {
307                 if (!strcmp(mock_queries[i].name, statement)) {
308                         current_query = &mock_queries[i];
309                         return (dbi_result)current_query;
310                 }
311         }
312         return NULL;
313 } /* dbi_conn_query */
315 unsigned long long
316 dbi_result_get_numrows(dbi_result res)
318         mock_query_t *q = res;
319         if (! q)
320                 return DBI_ROW_ERROR;
321         return q->nrows;
322 } /* dbi_result_get_numrows */
324 unsigned int
325 dbi_result_get_numfields(dbi_result res)
327         mock_query_t *q = res;
328         if (! q)
329                 return DBI_FIELD_ERROR;
330         return q->nfields;
331 } /* dbi_result_get_numfields */
333 unsigned short
334 dbi_result_get_field_type_idx(dbi_result res, unsigned int i)
336         mock_query_t *q = res;
337         if ((! q) || (i > q->nfields))
338                 return DBI_TYPE_ERROR;
339         return q->field_types[i - 1];
340 } /* dbi_result_get_field_type_idx */
342 const char *
343 dbi_result_get_field_name(dbi_result res, unsigned int i)
345         mock_query_t *q = res;
346         if ((! q) || (i > q->nfields))
347                 return NULL;
348         return q->field_names[i - 1];
349 } /* dbi_result_get_field_name */
351 int
352 dbi_result_seek_row(dbi_result res, unsigned long long n)
354         mock_query_t *q = res;
355         if ((! q) || (n > q->nrows))
356                 return 0;
358         q->current_row = n;
359         return 1;
360 } /* dbi_result_seek_row */
362 static mock_data_t
363 get_golden_data(dbi_result res, unsigned int i) {
364         mock_query_t *q = res;
365         fail_unless(q != NULL, "dbi_result_get_*_idx() called with "
366                         "NULL result data; expected valid result object");
368         /* this information is managed by seek_row and, thus,
369          * should never be invalid */
370         fail_unless(q->current_row && q->current_row <= q->nrows,
371                         "INTERNAL ERROR: current row out of range");
373         fail_unless(i && i <= q->nfields,
374                         "dbi_result_get_*_idx() called with index out of range; "
375                         "got: %u; expected [1, %u]", i, q->nfields);
376         return golden_data[q->current_row - 1][i - 1];
377 } /* get_golden_data */
379 long long
380 dbi_result_get_longlong_idx(dbi_result res, unsigned int i)
382         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_INTEGER,
383                         "dbi_result_get_longlong_idx() called for non-integer "
384                         "column type %u", current_query->field_types[i - 1]);
385         return get_golden_data(res, i).integer;
386 } /* dbi_result_get_longlong_idx */
388 double
389 dbi_result_get_double_idx(dbi_result res, unsigned int i)
391         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DECIMAL,
392                         "dbi_result_get_double_idx() called for non-decimal "
393                         "column type %u", current_query->field_types[i - 1]);
394         return get_golden_data(res, i).decimal;
395 } /* dbi_result_get_double_idx */
397 const char *
398 dbi_result_get_string_idx(dbi_result res, unsigned int i)
400         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING,
401                         "dbi_result_get_string_idx() called for non-string "
402                         "column type %u", current_query->field_types[i - 1]);
403         return get_golden_data(res, i).string;
404 } /* dbi_result_get_string_idx */
406 char *
407 dbi_result_get_string_copy_idx(dbi_result res, unsigned int i)
409         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING,
410                         "dbi_result_get_string_copy_idx() called for non-string "
411                         "column type %u", current_query->field_types[i - 1]);
412         if (! get_golden_data(res, i).string)
413                 return NULL;
414         return strdup(get_golden_data(res, i).string);
415 } /* dbi_result_get_string_copy_idx */
417 time_t
418 dbi_result_get_datetime_idx(dbi_result res, unsigned int i)
420         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_DATETIME,
421                         "dbi_result_get_datetime_idx() called for non-datetime "
422                         "column type %u", current_query->field_types[i - 1]);
423         return get_golden_data(res, i).datetime;
424 } /* dbi_result_get_datetime_idx */
426 size_t
427 dbi_result_get_field_length_idx(dbi_result res, unsigned int i)
429         /* this will check if the parameters are valid */
430         get_golden_data(res, i);
432         switch (current_query->field_types[i - 1]) {
433                 case DBI_TYPE_INTEGER:
434                         return sizeof(long long);
435                         break;
436                 case DBI_TYPE_DECIMAL:
437                         return sizeof(double);
438                         break;
439                 case DBI_TYPE_STRING:
440                         return strlen(get_golden_data(res, i).string) + 1;
441                         break;
442                 case DBI_TYPE_DATETIME:
443                         return sizeof(time_t);
444                         break;
445                 case DBI_TYPE_BINARY:
446                         return get_golden_data(res, i).binary.length;
447                         break;
448         }
450         fail("INTERNAL ERROR: dbi_result_get_field_length_idx() "
451                         "called for unexpected field type %u",
452                         current_query->field_types[i - 1]);
453         return 0;
454 } /* dbi_result_get_field_length_idx */
456 const unsigned char *
457 dbi_result_get_binary_idx(dbi_result res, unsigned int i)
459         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY,
460                         "dbi_result_get_binary_idx() called for non-binary "
461                         "column type %u", current_query->field_types[i - 1]);
462         return get_golden_data(res, i).binary.datum;
463 } /* dbi_result_get_binary_idx */
465 unsigned char *
466 dbi_result_get_binary_copy_idx(dbi_result res, unsigned int i)
468         const char *data;
469         fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY,
470                         "dbi_result_get_binary_copy_idx() called for non-binary "
471                         "column type %u", current_query->field_types[i - 1]);
472         data = (const char *)get_golden_data(res, i).binary.datum;
473         if (! data)
474                 return NULL;
475         return (unsigned char *)strdup(data);
476 } /* dbi_result_get_binary_copy_idx */
478 static unsigned long long dbi_result_free_called = 0;
479 int
480 dbi_result_free(dbi_result res)
482         mock_query_t *q = res;
484         ++dbi_result_free_called;
485         if (! q)
486                 return -1;
488         current_query = NULL;
489         return 0;
490 } /* dbi_result_free */
492 /*
493  * private helper functions
494  */
496 static void
497 setup(void)
499         client = sdb_dbi_client_create("mockdriver", "mockdatabase");
500         fail_unless(client != NULL,
501                         "sdb_dbi_client_create() = NULL; expected client object");
503         dbi_conn_connect_called = 0;
504 } /* setup */
506 static void
507 connect(void)
509         int check = sdb_dbi_client_connect(client);
510         fail_unless(check == 0,
511                         "sdb_dbi_client_connect() = %i; expected: 0", check);
512 } /* connect */
514 static void
515 teardown(void)
517         sdb_dbi_client_destroy(client);
518         client = NULL;
519 } /* teardown */
521 static unsigned long long query_callback_called = 0;
522 static int
523 query_callback(sdb_dbi_client_t *c,
524                 size_t n, sdb_data_t *data, sdb_object_t *user_data)
526         size_t i;
528         ++query_callback_called;
530         fail_unless(c == client,
531                         "query callback received unexpected client = %p; "
532                         "expected: %p", c, client);
533         fail_unless(n == current_query->nfields,
534                         "query callback received n = %i; expected: %i",
535                         n, current_query->nfields);
536         fail_unless(data != NULL,
537                         "query callback received data = NULL; expected: valid data");
538         fail_unless(user_data == TEST_MAGIC,
539                         "query callback received user_data = %p; expected: %p",
540                         user_data, TEST_MAGIC);
542         for (i = 0; i < n; ++i) {
543                 int expected_type = DBI_TYPE_TO_SDB(current_query->field_types[i]);
544                 mock_data_t expected_data;
546                 fail_unless((int)data[i].type == expected_type,
547                                 "query callback received unexpected type %i for "
548                                 "column %zu; expected: %i", data[i].type, i,
549                                 expected_type);
551                 expected_data = golden_data[current_query->current_row - 1][i];
552                 switch (expected_type) {
553                         case SDB_TYPE_INTEGER:
554                                 fail_unless(data[i].data.integer == expected_data.integer,
555                                                 "query callback received unexpected data %lli "
556                                                 "for column %zu; expected: %lli",
557                                                 data[i].data.integer, i, expected_data.integer);
558                                 break;
559                         case SDB_TYPE_DECIMAL:
560                                 fail_unless(data[i].data.decimal == expected_data.decimal,
561                                                 "query callback received unexpected data %g "
562                                                 "for column %zu; expected: %g",
563                                                 data[i].data.decimal, i, expected_data.decimal);
564                                 break;
565                         case SDB_TYPE_STRING:
566                                 fail_unless(!strcmp(data[i].data.string, expected_data.string),
567                                                 "query callback received unexpected data %s "
568                                                 "for column %zu; expected: %s",
569                                                 data[i].data.string, i, expected_data.string);
570                                 break;
571                         case SDB_TYPE_DATETIME:
572                                 fail_unless(data[i].data.datetime
573                                                         == SECS_TO_SDB_TIME(expected_data.datetime),
574                                                 "query callback received unexpected data "PRIsdbTIME
575                                                 " for column %zu; expected: "PRIsdbTIME,
576                                                 data[i].data.integer, i,
577                                                 SECS_TO_SDB_TIME(expected_data.integer));
578                                 break;
579                         case SDB_TYPE_BINARY:
580                                 fail_unless(data[i].data.binary.length ==
581                                                         expected_data.binary.length,
582                                                 "query callback received unexpected "
583                                                 "binary data length %zu for column %zu; "
584                                                 "expected: %lli", data[i].data.binary.length, i,
585                                                 expected_data.binary.length);
586                                 fail_unless(!memcmp(data[i].data.binary.datum,
587                                                         expected_data.binary.datum,
588                                                         expected_data.binary.length),
589                                                 "query callback received unexpected binary data %p "
590                                                 "for column %zu; expected: %p",
591                                                 data[i].data.binary.datum, i,
592                                                 expected_data.binary.datum);
593                                 break;
594                         default:
595                                 fail("INTERNAL ERROR: query callback received "
596                                                 "unknown type %i for column %zu",
597                                                 expected_type, i);
598                 }
599         }
600         return 0;
601 } /* query_callback */
603 /*
604  * tests
605  */
607 START_TEST(test_sdb_dbi_client_connect)
609         sdb_dbi_options_t *opts;
610         int check;
612         check = sdb_dbi_client_connect(client);
613         fail_unless(check == 0,
614                         "sdb_dbi_client_connect() = %i; expected: 0", check);
615         fail_unless(dbi_conn_connect_called == 1,
616                         "sdb_dbi_client_create() called dbi_conn_connect %i times; "
617                         "expected: 1", dbi_conn_connect_called);
619         /* calling it again shall reconnect */
620         check = sdb_dbi_client_connect(client);
621         fail_unless(check == 0,
622                         "repeated sdb_dbi_client_connect() = %i; expected: 0", check);
623         fail_unless(dbi_conn_connect_called == 2,
624                         "repeated sdb_dbi_client_create() called dbi_conn_connect %i times; "
625                         "expected: 2", dbi_conn_connect_called);
627         opts = sdb_dbi_options_create();
628         fail_unless(opts != NULL,
629                         "sdb_dbi_options_create() returned NULL; expected <opts>");
630         check = sdb_dbi_options_add(opts, "a", "1");
631         fail_unless(check == 0,
632                         "sdb_dbi_options_add('a', '1') = %d; expected: 0", check);
633         check = sdb_dbi_options_add(opts, "b", "2");
634         fail_unless(check == 0,
635                         "sdb_dbi_options_add('b', '2') = %d; expected: 0", check);
637         check = sdb_dbi_client_set_options(client, opts);
638         fail_unless(check == 0,
639                         "sdb_dbi_client_set_options() = %d; expected: 0", check);
640         /* reconnect with options */
641         check = sdb_dbi_client_connect(client);
642         fail_unless(check == 0,
643                         "repeated, with options sdb_dbi_client_connect() = %i; expected: 0",
644                         check);
645         fail_unless(dbi_conn_connect_called == 3,
646                         "repeated, with options sdb_dbi_client_create() called "
647                         "dbi_conn_connect %i times; expected: 3", dbi_conn_connect_called);
649         /* The client takes ownership of the options, so no need to destroy it. */
651 END_TEST
653 START_TEST(test_sdb_dbi_client_check_conn)
655         int check = sdb_dbi_client_check_conn(client);
656         fail_unless(check == 0,
657                         "sdb_dbi_client_check_conn() = %i; expected: 0", check);
659         /* the first call will actually connect to the database */
660         fail_unless(dbi_conn_connect_called == 1,
661                         "sdb_dbi_client_check_conn() called dbi_conn_connect %i times; "
662                         "expected: 1", dbi_conn_connect_called);
664         dbi_conn_connect_called = 0;
665         check = sdb_dbi_client_check_conn(client);
666         fail_unless(check == 0,
667                         "sdb_dbi_client_check_conn() = %i; expected: 0", check);
669         /* should not reconnect */
670         fail_unless(dbi_conn_connect_called == 0,
671                         "sdb_dbi_client_check_conn() called dbi_conn_connect %i time(s); "
672                         "expected: 0", dbi_conn_connect_called);
674 END_TEST
676 START_TEST(test_sdb_dbi_exec_query)
678         size_t i;
680         int check = sdb_dbi_exec_query(client, "mockquery0", query_callback,
681                         /* user_data = */ TEST_MAGIC, /* n = */ 0);
682         /* not connected yet */
683         fail_unless(check < 0,
684                         "sdb_dbi_exec_query() = %i; expected: < 0", check);
686         connect();
688         for (i = 0; i < SDB_STATIC_ARRAY_LEN(mock_queries); ++i) {
689                 mock_query_t *q = &mock_queries[i];
691                 unsigned long long expected_callback_calls = 0;
693                 dbi_conn_query_called = 0;
694                 query_callback_called = 0;
695                 dbi_result_free_called = 0;
697                 /* sdb_dbi_exec_query will only use as many type arguments are needed,
698                  * so we can safely pass in the maximum number of arguments required
699                  * on each call */
700                 check = sdb_dbi_exec_query(client, q->name, query_callback,
701                                 /* user_data = */ TEST_MAGIC, /* n = */ (int)q->nfields,
702                                 SDB_TYPE_INTEGER, SDB_TYPE_DECIMAL, SDB_TYPE_STRING,
703                                 SDB_TYPE_DATETIME, SDB_TYPE_BINARY);
704                 fail_unless(check == 0,
705                                 "sdb_dbi_exec_query() = %i; expected: 0", check);
707                 fail_unless(dbi_conn_query_called == 1,
708                                 "sdb_dbi_exec_query() called dbi_conn_query %i times; "
709                                 "expected: 1", dbi_conn_query_called);
711                 if (q->nfields)
712                         expected_callback_calls = q->nrows;
714                 fail_unless(query_callback_called == expected_callback_calls,
715                                 "sdb_dbi_exec_query() did not call the registered callback "
716                                 "for each result row; got %i call%s; expected: 0",
717                                 query_callback_called,
718                                 (query_callback_called == 1) ? "" : "s");
720                 fail_unless(dbi_result_free_called == 1,
721                                 "sdb_dbi_exec_query() did not free the query result object");
722         }
724 END_TEST
726 TEST_MAIN("utils::dbi")
728         TCase *tc = tcase_create("core");
729         tcase_add_checked_fixture(tc, setup, teardown);
730         tcase_add_test(tc, test_sdb_dbi_client_connect);
731         tcase_add_test(tc, test_sdb_dbi_client_check_conn);
732         tcase_add_test(tc, test_sdb_dbi_exec_query);
733         ADD_TCASE(tc);
735 TEST_MAIN_END
737 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */