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/>.
20 #include <sys/types.h>
21 #include <sys/socket.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
);
63 #include "../control.c"
65 #include "../io_elem.c"
66 #include "../local_tdb.c"
67 #include "../logging.c"
68 #include "../messages.c"
85 #include "ctdb-test.h"
97 static void run_inits(void)
99 /* Linker magic creates these to delineate section. */
100 extern initcall_t __start_init_call
[], __stop_init_call
[];
103 for (p
= __start_init_call
; p
< __stop_init_call
; 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");
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>
123 static void cmdline_echo(struct option
*opt
)
125 tui_echo_commands
= 1;
127 cmdline_opt("echo", 0, 'x', cmdline_echo
);
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
138 static void cmdline_quiet(struct option
*opt
)
142 cmdline_opt("quiet", 0, 'q', cmdline_quiet
);
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>
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
);
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>
167 static void cmdline_help(struct option
*opt
)
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 */
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
)
194 static struct option
*get_cmdline_options(void)
196 struct cmdline_option
*copts
;
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
++) {
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
215 || streq(copts
[x
].opt
.name
,
217 errx(1, "Conflicting arguments %s = %s\n",
218 copts
[x
].opt
.name
, opts
[y
].name
);
220 opts
[x
] = copts
[x
].opt
;
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);
239 copts
= __start_cmdline
;
241 for (x
= 0; x
< n_opts
; x
++) {
242 if (!copts
[x
].opt
.val
)
244 snprintf(tmpstr
, 4, "%c%s", copts
[x
].opt
.val
,
245 colonstr
+ 2 - copts
[x
].opt
.has_arg
);
246 strcat(optstr
, tmpstr
);
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
)) {
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
)) {
267 return talloc_named_const(allocations
, size
, location
);
270 static void ctdb_test_free(void *ptr
, const char *location
)
275 static void *ctdb_test_realloc(void *ptr
, size_t size
, const char *location
)
277 if (should_i_fail("realloc", location
)) {
281 ptr
= _talloc_realloc(allocations
, ptr
, size
, location
);
283 talloc_set_name(ptr
, "%s (reallocated to %u at %s)",
284 talloc_get_name(ptr
), size
, location
);
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
)) {
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. */
299 log_line(LOG_DEBUG
, "Child reading fd");
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
)) {
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. */
317 log_line(LOG_DEBUG
, "Child writing fd");
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
)) {
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
)) {
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
)) {
354 return tdb_open_ex(name
, hash_size
, tdb_flags
, open_flags
, mode
,
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
);
364 ret
.dptr
= talloc_memdup(allocations
, ret
.dptr
, ret
.dsize
);
366 err(1, "Could not memdup %zu bytes", ret
.dsize
);
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
);
383 /* This version adds one byte (for nul term) */
384 void *grab_fd(int fd
, size_t *size
)
388 void *buffer
= talloc_array(NULL
, char, max
+1);
391 while ((ret
= read(fd
, buffer
+ *size
, max
- *size
)) > 0) {
394 buffer
= talloc_realloc(NULL
, buffer
, char, max
*= 2 + 1);
403 int main(int argc
, char *argv
[])
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
);
418 errx(1, "Unknown argument");
420 copt
->parse(&copt
->opt
);
423 if (optind
== argc
) {
424 log_line(LOG_DEBUG
, "Disabling failtest due to stdin.");
426 input_fd
= STDIN_FILENO
;
427 } else if (optind
+ 1 != argc
)
428 errx(1, "Need a single argument: input filename");
430 input_fd
= open(argv
[optind
], O_RDONLY
);
432 err(1, "Opening %s", argv
[optind
]);
433 tui_abort_on_fail
= true;
440 log_line(LOG_VERBOSE
, "initialisation done");
444 /* Everyone loves a good error haiku! */
445 if (expects_remaining())
446 errx(1, "Expectations still / "
447 "unfulfilled remaining. / "
448 "Testing blossoms fail.");