failtest: hook can return FAIL_PROBE
[ccan] / ccan / failtest / failtest.h
1 #ifndef CCAN_FAILTEST_H
2 #define CCAN_FAILTEST_H
3 #include <sys/types.h>
4 #include <stdbool.h>
5 #include <fcntl.h>
6 #include <ccan/compiler/compiler.h>
7
8 /**
9  * failtest_init - initialize the failtest module
10  * @argc: the number of commandline arguments
11  * @argv: the commandline argument array
12  *
13  * This initializes the module, and in particular if argv[1] is "--failpath="
14  * then it ensures that failures follow that pattern.  This allows easy
15  * debugging of complex failure paths.
16  */
17 void failtest_init(int argc, char *argv[]);
18
19 /**
20  * failtest_exit - clean up and exit the test
21  * @status: the status (usually exit_status() from ccan/tap).
22  *
23  * This cleans up and changes to files made in this child, and exits the test.
24  * It also calls your failtest_default_hook, if any.
25  *
26  * A child which does not exit via failtest_exit() will cause the overall test
27  * to fail.
28  */
29 void NORETURN failtest_exit(int status);
30
31 /**
32  * enum failtest_call_type - discriminator for failtest_call.u
33  */
34 enum failtest_call_type {
35         FAILTEST_MALLOC,
36         FAILTEST_CALLOC,
37         FAILTEST_REALLOC,
38         FAILTEST_OPEN,
39         FAILTEST_CLOSE,
40         FAILTEST_PIPE,
41         FAILTEST_READ,
42         FAILTEST_WRITE,
43         FAILTEST_FCNTL,
44 };
45
46 struct calloc_call {
47         void *ret;
48         size_t nmemb;
49         size_t size;
50 };
51
52 struct malloc_call {
53         void *ret;
54         size_t size;
55 };
56
57 struct realloc_call {
58         void *ret;
59         void *ptr;
60         size_t size;
61 };
62
63 struct open_call {
64         int ret;
65         const char *pathname;
66         int flags;
67         mode_t mode;
68 };
69
70 struct close_call {
71         int fd;
72 };
73
74 struct pipe_call {
75         int ret;
76         int fds[2];
77         bool closed[2];
78 };
79
80 struct read_call {
81         ssize_t ret;
82         off_t off;
83         int fd;
84         void *buf;
85         size_t count;
86 };
87
88 struct write_call {
89         ssize_t ret;
90         int fd;
91         const void *buf;
92         size_t count;
93         off_t off;
94 };
95
96 struct fcntl_call {
97         int ret;
98         int fd;
99         int cmd;
100         union {
101                 struct flock fl;
102                 long l;
103                 int i;
104         } arg;
105 };
106
107 /**
108  * struct failtest_call - description of a call redirected to failtest module
109  * @type: the call type
110  * @file: the filename of the caller
111  * @line: the line number of the caller
112  * @fail: did this call fail
113  * @error: the errno (if any)
114  * @u: the union of call data
115  *
116  * This structure is used to represent the ordered history of calls.
117  *
118  * See Also:
119  *      failtest_hook, failtest_exit_check
120  */
121 struct failtest_call {
122         enum failtest_call_type type;
123         /* Where we were called from. */
124         const char *file;
125         unsigned int line;
126         /* Did we fail? */
127         bool fail;
128         /* What we set errno to. */
129         int error;
130         /* How do we clean this up? */
131         void (*cleanup)(void *u);
132         /* The actual call data. */
133         union {
134                 struct calloc_call calloc;
135                 struct malloc_call malloc;
136                 struct realloc_call realloc;
137                 struct open_call open;
138                 struct close_call close;
139                 struct pipe_call pipe;
140                 struct read_call read;
141                 struct write_call write;
142                 struct fcntl_call fcntl;
143         } u;
144 };
145
146 enum failtest_result {
147         /* Yes try failing this call. */
148         FAIL_OK,
149         /* No, don't try failing this call. */
150         FAIL_DONT_FAIL,
151         /* Try failing this call but don't go too far down that path. */
152         FAIL_PROBE,
153 };
154
155 /**
156  * failtest_hook - whether a certain call should fail or not.
157  * @history: the ordered history of all failtest calls.
158  * @num: the number of elements in @history (greater than 0)
159  *
160  * The default value of this hook is failtest_default_hook(), which returns
161  * FAIL_OK (ie. yes, fail the call).
162  *
163  * You can override it, and avoid failing certain calls.  The parameters
164  * of the call (but not the return value(s)) will be filled in for the last
165  * call.
166  *
167  * Example:
168  *      static enum failtest_result dont_fail_alloc(struct failtest_call *hist,
169  *                                                  unsigned num)
170  *      {
171  *              if (hist[num-1].type == FAILTEST_MALLOC
172  *                      || hist[num-1].type == FAILTEST_CALLOC
173  *                      || hist[num-1].type == FAILTEST_REALLOC)
174  *                      return FAIL_DONT_FAIL;
175  *              return FAIL_OK;
176  *      }
177  *      ...
178  *              failtest_hook = dont_fail_alloc;
179  */
180 extern enum failtest_result
181 (*failtest_hook)(struct failtest_call *history, unsigned num);
182
183 /**
184  * failtest_exit_check - hook for additional checks on a failed child.
185  * @history: the ordered history of all failtest calls.
186  * @num: the number of elements in @history (greater than 0)
187  *
188  * Your program might have additional checks to do on failure, such as
189  * check that a file is not corrupted, or than an error message has been
190  * logged.
191  *
192  * If this returns false, the path to this failure will be printed and the
193  * overall test will fail.
194  */
195 extern bool (*failtest_exit_check)(struct failtest_call *history,
196                                    unsigned num);
197
198 /**
199  * failtest_timeout_ms - how long to wait before killing child.
200  *
201  * Default is 20,000 (20 seconds).
202  */
203 extern unsigned int failtest_timeout_ms;
204 #endif /* CCAN_FAILTEST_H */