ccan/ntdb: demote to junkcode.
[ccan] / junkcode / rusty@rustcorp.com.au-ntdb / test / api-fork-test.c
1 /* Test forking while holding lock.
2  *
3  * There are only five ways to do this currently:
4  * (1) grab a ntdb_chainlock, then fork.
5  * (2) grab a ntdb_lockall, then fork.
6  * (3) grab a ntdb_lockall_read, then fork.
7  * (4) start a transaction, then fork.
8  * (5) fork from inside a ntdb_parse() callback.
9  *
10  * Note that we don't hold a lock across ntdb_traverse callbacks, so
11  * that doesn't matter.
12  */
13 #include "config.h"
14 #include "../ntdb.h"
15 #include "../private.h"
16 #include "tap-interface.h"
17 #include "logging.h"
18 #include "helpapi-external-agent.h"
19
20 static bool am_child = false;
21
22 static enum NTDB_ERROR fork_in_parse(NTDB_DATA key, NTDB_DATA data,
23                                     struct ntdb_context *ntdb)
24 {
25         int status;
26
27         if (fork() == 0) {
28                 am_child = true;
29
30                 /* We expect this to fail. */
31                 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
32                         exit(1);
33
34                 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
35                         exit(1);
36
37                 if (tap_log_messages != 2)
38                         exit(2);
39
40                 return NTDB_SUCCESS;
41         }
42         wait(&status);
43         ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
44         return NTDB_SUCCESS;
45 }
46
47 int main(int argc, char *argv[])
48 {
49         unsigned int i;
50         struct ntdb_context *ntdb;
51         int flags[] = { NTDB_DEFAULT, NTDB_NOMMAP,
52                         NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT };
53         NTDB_DATA key = ntdb_mkdata("key", 3);
54         NTDB_DATA data = ntdb_mkdata("data", 4);
55
56         plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
57         for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
58                 int status;
59
60                 tap_log_messages = 0;
61
62                 ntdb = ntdb_open("run-fork-test.ntdb",
63                                  flags[i]|MAYBE_NOSYNC,
64                                  O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
65                 if (!ok1(ntdb))
66                         continue;
67
68                 /* Put a record in here. */
69                 ok1(ntdb_store(ntdb, key, data, NTDB_REPLACE) == NTDB_SUCCESS);
70
71                 ok1(ntdb_chainlock(ntdb, key) == NTDB_SUCCESS);
72                 if (fork() == 0) {
73                         /* We expect this to fail. */
74                         if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
75                                 return 1;
76
77                         if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
78                                 return 1;
79
80                         if (tap_log_messages != 2)
81                                 return 2;
82
83                         /* Child can do this without any complaints. */
84                         ntdb_chainunlock(ntdb, key);
85                         if (tap_log_messages != 2)
86                                 return 3;
87                         ntdb_close(ntdb);
88                         if (tap_log_messages != 2)
89                                 return 4;
90                         return 0;
91                 }
92                 wait(&status);
93                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
94                 ntdb_chainunlock(ntdb, key);
95
96                 ok1(ntdb_lockall(ntdb) == NTDB_SUCCESS);
97                 if (fork() == 0) {
98                         /* We expect this to fail. */
99                         if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
100                                 return 1;
101
102                         if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
103                                 return 1;
104
105                         if (tap_log_messages != 2)
106                                 return 2;
107
108                         /* Child can do this without any complaints. */
109                         ntdb_unlockall(ntdb);
110                         if (tap_log_messages != 2)
111                                 return 3;
112                         ntdb_close(ntdb);
113                         if (tap_log_messages != 2)
114                                 return 4;
115                         return 0;
116                 }
117                 wait(&status);
118                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
119                 ntdb_unlockall(ntdb);
120
121                 ok1(ntdb_lockall_read(ntdb) == NTDB_SUCCESS);
122                 if (fork() == 0) {
123                         /* We expect this to fail. */
124                         /* This would always fail anyway... */
125                         if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
126                                 return 1;
127
128                         if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
129                                 return 1;
130
131                         if (tap_log_messages != 2)
132                                 return 2;
133
134                         /* Child can do this without any complaints. */
135                         ntdb_unlockall_read(ntdb);
136                         if (tap_log_messages != 2)
137                                 return 3;
138                         ntdb_close(ntdb);
139                         if (tap_log_messages != 2)
140                                 return 4;
141                         return 0;
142                 }
143                 wait(&status);
144                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
145                 ntdb_unlockall_read(ntdb);
146
147                 ok1(ntdb_transaction_start(ntdb) == NTDB_SUCCESS);
148                 /* If transactions is empty, noop "commit" succeeds. */
149                 ok1(ntdb_delete(ntdb, key) == NTDB_SUCCESS);
150                 if (fork() == 0) {
151                         int last_log_messages;
152
153                         /* We expect this to fail. */
154                         if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
155                                 return 1;
156
157                         if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
158                                 return 1;
159
160                         if (tap_log_messages != 2)
161                                 return 2;
162
163                         if (ntdb_transaction_prepare_commit(ntdb)
164                             != NTDB_ERR_LOCK)
165                                 return 3;
166                         if (tap_log_messages == 2)
167                                 return 4;
168
169                         last_log_messages = tap_log_messages;
170                         /* Child can do this without any complaints. */
171                         ntdb_transaction_cancel(ntdb);
172                         if (tap_log_messages != last_log_messages)
173                                 return 4;
174                         ntdb_close(ntdb);
175                         if (tap_log_messages != last_log_messages)
176                                 return 4;
177                         return 0;
178                 }
179                 wait(&status);
180                 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
181                 ntdb_transaction_cancel(ntdb);
182
183                 ok1(ntdb_parse_record(ntdb, key, fork_in_parse, ntdb)
184                     == NTDB_SUCCESS);
185                 ntdb_close(ntdb);
186                 if (am_child) {
187                         /* Child can return from parse without complaints. */
188                         if (tap_log_messages != 2)
189                                 exit(3);
190                         exit(0);
191                 }
192                 ok1(tap_log_messages == 0);
193         }
194         return exit_status();
195 }