tools/ctdb: Pass memory context for returning nodes in parse_nodestring
[Samba/wip.git] / ctdb / libctdb / test / ctdb-test.c
blobc1dc4b8bab555aa76e015371378d251e2beda13f
1 /*
2 test driver for libctdb
4 Copyright (C) Rusty Russell 2010
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <poll.h>
23 #include <talloc.h>
24 #include <tdb.h>
26 /* We replace the following functions, for finer control. */
27 #define poll(fds, nfds, timeout) ctdb_test_poll((fds), (nfds), (timeout), __location__)
28 #define malloc(size) ctdb_test_malloc((size), __location__)
29 #define free(ptr) ctdb_test_free((ptr), __location__)
30 #define realloc(ptr, size) ctdb_test_realloc((ptr), (size), __location__)
31 #define read(fd, buf, count) ctdb_test_read((fd), (buf), (count), __location__)
32 #define write(fd, buf, count) ctdb_test_write((fd), (buf), (count), __location__)
33 #define socket(domain, type, protocol) ctdb_test_socket((domain), (type), (protocol), __location__)
34 #define connect(sockfd, addr, addrlen) ctdb_test_connect((sockfd), (addr), (addrlen), __location__)
36 #define tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, log_ctx, hash_fn) ctdb_test_tdb_open_ex((name), (hash_size), (tdb_flags), (open_flags), (mode), (log_ctx), (hash_fn), __location__)
37 #define tdb_fetch(tdb, key) ctdb_test_tdb_fetch((tdb), (key))
39 /* Implement these if they're ever used. */
40 #define calloc ctdb_test_calloc
41 #define select ctdb_test_select
42 #define epoll_wait ctdb_test_epoll_wait
43 #define epoll_ctl ctdb_test_epoll_ctl
44 #define tdb_open ctdb_test_tdb_open
46 static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout, const char *location);
47 static void *ctdb_test_malloc(size_t size, const char *location);
48 static void ctdb_test_free(void *ptr, const char *location);
49 static void *ctdb_test_realloc(void *ptr, size_t size, const char *location);
50 static ssize_t ctdb_test_read(int fd, void *buf, size_t count, const char *location);
51 static ssize_t ctdb_test_write(int fd, const void *buf, size_t count, const char *location);
52 static int ctdb_test_socket(int domain, int type, int protocol, const char *location);
53 static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
54 socklen_t addrlen, const char *location);
55 static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
56 int hash_size, int tdb_flags,
57 int open_flags, mode_t mode,
58 const struct tdb_logging_context *log_ctx,
59 tdb_hash_func hash_fn, const char *location);
60 static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
62 #include "../sync.c"
63 #include "../control.c"
64 #include "../ctdb.c"
65 #include "../io_elem.c"
66 #include "../local_tdb.c"
67 #include "../logging.c"
68 #include "../messages.c"
70 #undef poll
71 #undef malloc
72 #undef realloc
73 #undef read
74 #undef write
75 #undef socket
76 #undef connect
77 #undef tdb_open_ex
78 #undef calloc
79 #undef select
80 #undef epoll_wait
81 #undef epoll_ctl
82 #undef tdb_open
83 #undef tdb_fetch
85 #include "ctdb-test.h"
86 #include "utils.h"
87 #include "tui.h"
88 #include "log.h"
89 #include "failtest.h"
90 #include "expect.h"
91 #include <err.h>
93 /* Talloc contexts */
94 void *allocations;
95 void *working;
97 static void run_inits(void)
99 /* Linker magic creates these to delineate section. */
100 extern initcall_t __start_init_call[], __stop_init_call[];
101 initcall_t *p;
103 for (p = __start_init_call; p < __stop_init_call; p++)
104 (*p)();
107 static void print_license(void)
109 printf("ctdb-test, Copyright (C) 2010 Jeremy Kerr, Rusty Russell\n"
110 "ctdb-test comes with ABSOLUTELY NO WARRANTY; see COPYING.\n"
111 "This is free software, and you are welcome to redistribute\n"
112 "it under certain conditions; see COPYING for details.\n");
115 /*** XML Argument:
116 <section id="a:echo">
117 <title><option>--echo</option>, <option>-x</option></title>
118 <subtitle>Echo commands as they are executed</subtitle>
119 <para>ctdb-test will echo each command before it is executed. Useful when
120 commands are read from a file</para>
121 </section>
123 static void cmdline_echo(struct option *opt)
125 tui_echo_commands = 1;
127 cmdline_opt("echo", 0, 'x', cmdline_echo);
129 /*** XML Argument:
130 <section id="a:quiet">
131 <title><option>--quiet</option>, <option>-q</option></title>
132 <subtitle>Run quietly</subtitle>
133 <para>Causes ctdb-test to reduce its output to the minimum possible - no prompt
134 is displayed, and most warning messages are suppressed
135 </para>
136 </section>
138 static void cmdline_quiet(struct option *opt)
140 tui_quiet = 1;
142 cmdline_opt("quiet", 0, 'q', cmdline_quiet);
144 /*** XML Argument:
145 <section id="a:exit">
146 <title><option>--exit</option>, <option>-e</option></title>
147 <subtitle>Exit on error</subtitle>
148 <para>If <option>--exit</option> is specified, ctdb-test will exit (with a
149 non-zero error code) on the first script error it encounters (eg an
150 expect command does not match). This is the default when invoked as a
151 non-interactive script.</para>
152 </section>
154 static void cmdline_abort_on_fail(struct option *opt)
156 tui_abort_on_fail = 1;
158 cmdline_opt("exit", 0, 'e', cmdline_abort_on_fail);
160 /*** XML Argument:
161 <section id="a:help">
162 <title><option>--help</option></title>
163 <subtitle>Print usage information</subtitle>
164 <para>Causes ctdb-test to print its command line arguments and then exit</para>
165 </section>
167 static void cmdline_help(struct option *opt)
169 print_license();
170 print_usage();
171 exit(EXIT_SUCCESS);
173 cmdline_opt("help", 0, 'h', cmdline_help);
175 extern struct cmdline_option __start_cmdline[], __stop_cmdline[];
177 static struct cmdline_option *get_cmdline_option(int opt)
179 struct cmdline_option *copt;
181 /* if opt is < '0', we have been passed a long option, which is
182 * indexed directly */
183 if (opt < '0')
184 return __start_cmdline + opt;
186 /* otherwise search for the short option in the .val member */
187 for (copt = __start_cmdline; copt < __stop_cmdline; copt++)
188 if (copt->opt.val == opt)
189 return copt;
191 return NULL;
194 static struct option *get_cmdline_options(void)
196 struct cmdline_option *copts;
197 struct option *opts;
198 unsigned int x, n_opts;
200 n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
201 sizeof(struct cmdline_option);
203 opts = talloc_zero_array(NULL, struct option, n_opts + 1);
204 copts = __start_cmdline;
206 for (x = 0; x < n_opts; x++) {
207 unsigned int y;
209 if (copts[x].opt.has_arg > 2)
210 errx(1, "Bad argument `%s'", copts[x].opt.name);
212 for (y = 0; y < x; y++)
213 if ((copts[x].opt.val && copts[x].opt.val
214 == opts[y].val)
215 || streq(copts[x].opt.name,
216 opts[y].name))
217 errx(1, "Conflicting arguments %s = %s\n",
218 copts[x].opt.name, opts[y].name);
220 opts[x] = copts[x].opt;
221 opts[x].val = x;
224 return opts;
227 static char *get_cmdline_optstr(void)
229 struct cmdline_option *copts;
230 unsigned int x, n_opts;
231 char *optstr, tmpstr[3], *colonstr = "::";
233 n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
234 sizeof(struct cmdline_option);
236 optstr = talloc_size(NULL, 3 * n_opts * sizeof(*optstr) + 1);
237 *optstr = '\0';
239 copts = __start_cmdline;
241 for (x = 0; x < n_opts; x++) {
242 if (!copts[x].opt.val)
243 continue;
244 snprintf(tmpstr, 4, "%c%s", copts[x].opt.val,
245 colonstr + 2 - copts[x].opt.has_arg);
246 strcat(optstr, tmpstr);
248 return optstr;
251 static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout,
252 const char *location)
254 if (should_i_fail("poll", location)) {
255 errno = EINVAL;
256 return -1;
258 return poll(fds, nfds, timeout);
261 static void *ctdb_test_malloc(size_t size, const char *location)
263 if (should_i_fail("malloc", location)) {
264 errno = ENOMEM;
265 return NULL;
267 return talloc_named_const(allocations, size, location);
270 static void ctdb_test_free(void *ptr, const char *location)
272 talloc_free(ptr);
275 static void *ctdb_test_realloc(void *ptr, size_t size, const char *location)
277 if (should_i_fail("realloc", location)) {
278 errno = ENOMEM;
279 return NULL;
281 ptr = _talloc_realloc(allocations, ptr, size, location);
282 if (ptr)
283 talloc_set_name(ptr, "%s (reallocated to %u at %s)",
284 talloc_get_name(ptr), size, location);
285 return ptr;
288 static ssize_t ctdb_test_read(int fd, void *buf, size_t count,
289 const char *location)
291 if (should_i_fail("read", location)) {
292 errno = EBADF;
293 return -1;
295 /* FIXME: We only let parent read and write.
296 * We should have child do short read, at least until whole packet is
297 * read. Then we terminate child. */
298 if (!am_parent()) {
299 log_line(LOG_DEBUG, "Child reading fd");
300 return 0;
302 return read(fd, buf, count);
305 static ssize_t ctdb_test_write(int fd, const void *buf, size_t count,
306 const char *location)
308 if (should_i_fail("write", location)) {
309 errno = EBADF;
310 return -1;
312 /* FIXME: We only let parent read and write.
313 * We should have child do short write, at least until whole packet is
314 * written, then terminate child. Check that all children and parent
315 * write the same data. */
316 if (!am_parent()) {
317 log_line(LOG_DEBUG, "Child writing fd");
318 return 0;
320 return write(fd, buf, count);
323 static int ctdb_test_socket(int domain, int type, int protocol,
324 const char *location)
326 if (should_i_fail("socket", location)) {
327 errno = EINVAL;
328 return -1;
330 return socket(domain, type, protocol);
333 static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
334 socklen_t addrlen, const char *location)
336 if (should_i_fail("connect", location)) {
337 errno = EINVAL;
338 return -1;
340 return connect(sockfd, addr, addrlen);
343 static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
344 int hash_size, int tdb_flags,
345 int open_flags, mode_t mode,
346 const struct tdb_logging_context *log_ctx,
347 tdb_hash_func hash_fn,
348 const char *location)
350 if (should_i_fail("tdb_open_ex", location)) {
351 errno = ENOENT;
352 return NULL;
354 return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode,
355 log_ctx, hash_fn);
358 /* We don't need to fail this, but as library expects to be able to free()
359 dptr, we need to make sure it's talloced (see ctdb_test_free) */
360 static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
362 TDB_DATA ret = tdb_fetch(tdb, key);
363 if (ret.dptr) {
364 ret.dptr = talloc_memdup(allocations, ret.dptr, ret.dsize);
365 if (!ret.dptr) {
366 err(1, "Could not memdup %zu bytes", ret.dsize);
369 return ret;
372 void check_allocations(void)
374 talloc_free(working);
376 if (talloc_total_blocks(allocations) != 1) {
377 log_line(LOG_ALWAYS, "Resource leak:");
378 talloc_report_full(allocations, stdout);
379 exit(1);
383 /* This version adds one byte (for nul term) */
384 void *grab_fd(int fd, size_t *size)
386 size_t max = 16384;
387 int ret;
388 void *buffer = talloc_array(NULL, char, max+1);
390 *size = 0;
391 while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
392 *size += ret;
393 if (*size == max)
394 buffer = talloc_realloc(NULL, buffer, char, max *= 2 + 1);
396 if (ret < 0) {
397 talloc_free(buffer);
398 buffer = NULL;
400 return buffer;
403 int main(int argc, char *argv[])
405 int input_fd, c;
406 const char *optstr;
407 struct option *options;
409 allocations = talloc_named_const(NULL, 1, "ctdb-test");
410 working = talloc_named_const(NULL, 1, "ctdb-test-working");
412 options = get_cmdline_options();
413 optstr = get_cmdline_optstr();
415 while ((c = getopt_long(argc, argv, optstr, options, NULL)) != EOF) {
416 struct cmdline_option *copt = get_cmdline_option(c);
417 if (!copt)
418 errx(1, "Unknown argument");
420 copt->parse(&copt->opt);
423 if (optind == argc) {
424 log_line(LOG_DEBUG, "Disabling failtest due to stdin.");
425 failtest = false;
426 input_fd = STDIN_FILENO;
427 } else if (optind + 1 != argc)
428 errx(1, "Need a single argument: input filename");
429 else {
430 input_fd = open(argv[optind], O_RDONLY);
431 if (input_fd < 0)
432 err(1, "Opening %s", argv[optind]);
433 tui_abort_on_fail = true;
436 run_inits();
437 if (!tui_quiet)
438 print_license();
440 log_line(LOG_VERBOSE, "initialisation done");
442 tui_run(input_fd);
444 /* Everyone loves a good error haiku! */
445 if (expects_remaining())
446 errx(1, "Expectations still / "
447 "unfulfilled remaining. / "
448 "Testing blossoms fail.");
449 check_allocations();
450 check_databases();
451 dump_failinfo();
453 return EXIT_SUCCESS;