VERSION: Bump version number up to 4.1.3...
[Samba.git] / lib / ntdb / test / api-fork-test.c
blob6298a4af01874f28c2216057a180c1451555a3cf
1 /* Test forking while holding lock.
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.
10 * Note that we don't hold a lock across ntdb_traverse callbacks, so
11 * that doesn't matter.
13 #include "config.h"
14 #include "ntdb.h"
15 #include "tap-interface.h"
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include "logging.h"
25 static bool am_child = false;
27 static enum NTDB_ERROR fork_in_parse(NTDB_DATA key, NTDB_DATA data,
28 struct ntdb_context *ntdb)
30 int status;
32 if (fork() == 0) {
33 am_child = true;
35 /* We expect this to fail. */
36 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
37 exit(1);
39 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
40 exit(1);
42 if (tap_log_messages != 2)
43 exit(2);
45 return NTDB_SUCCESS;
47 wait(&status);
48 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
49 return NTDB_SUCCESS;
52 int main(int argc, char *argv[])
54 unsigned int i;
55 struct ntdb_context *ntdb;
56 int flags[] = { NTDB_DEFAULT, NTDB_NOMMAP,
57 NTDB_CONVERT, NTDB_NOMMAP|NTDB_CONVERT };
58 NTDB_DATA key = ntdb_mkdata("key", 3);
59 NTDB_DATA data = ntdb_mkdata("data", 4);
61 plan_tests(sizeof(flags) / sizeof(flags[0]) * 14);
62 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
63 int status;
65 tap_log_messages = 0;
67 ntdb = ntdb_open("run-fork-test.ntdb",
68 flags[i]|MAYBE_NOSYNC,
69 O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
70 if (!ok1(ntdb))
71 continue;
73 /* Put a record in here. */
74 ok1(ntdb_store(ntdb, key, data, NTDB_REPLACE) == NTDB_SUCCESS);
76 ok1(ntdb_chainlock(ntdb, key) == NTDB_SUCCESS);
77 if (fork() == 0) {
78 /* We expect this to fail. */
79 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
80 return 1;
82 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
83 return 1;
85 if (tap_log_messages != 2)
86 return 2;
88 /* Child can do this without any complaints. */
89 ntdb_chainunlock(ntdb, key);
90 if (tap_log_messages != 2)
91 return 3;
92 ntdb_close(ntdb);
93 if (tap_log_messages != 2)
94 return 4;
95 return 0;
97 wait(&status);
98 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
99 ntdb_chainunlock(ntdb, key);
101 ok1(ntdb_lockall(ntdb) == NTDB_SUCCESS);
102 if (fork() == 0) {
103 /* We expect this to fail. */
104 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
105 return 1;
107 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
108 return 1;
110 if (tap_log_messages != 2)
111 return 2;
113 /* Child can do this without any complaints. */
114 ntdb_unlockall(ntdb);
115 if (tap_log_messages != 2)
116 return 3;
117 ntdb_close(ntdb);
118 if (tap_log_messages != 2)
119 return 4;
120 return 0;
122 wait(&status);
123 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
124 ntdb_unlockall(ntdb);
126 ok1(ntdb_lockall_read(ntdb) == NTDB_SUCCESS);
127 if (fork() == 0) {
128 /* We expect this to fail. */
129 /* This would always fail anyway... */
130 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
131 return 1;
133 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
134 return 1;
136 if (tap_log_messages != 2)
137 return 2;
139 /* Child can do this without any complaints. */
140 ntdb_unlockall_read(ntdb);
141 if (tap_log_messages != 2)
142 return 3;
143 ntdb_close(ntdb);
144 if (tap_log_messages != 2)
145 return 4;
146 return 0;
148 wait(&status);
149 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
150 ntdb_unlockall_read(ntdb);
152 ok1(ntdb_transaction_start(ntdb) == NTDB_SUCCESS);
153 /* If transactions is empty, noop "commit" succeeds. */
154 ok1(ntdb_delete(ntdb, key) == NTDB_SUCCESS);
155 if (fork() == 0) {
156 int last_log_messages;
158 /* We expect this to fail. */
159 if (ntdb_store(ntdb, key, data, NTDB_REPLACE) != NTDB_ERR_LOCK)
160 return 1;
162 if (ntdb_fetch(ntdb, key, &data) != NTDB_ERR_LOCK)
163 return 1;
165 if (tap_log_messages != 2)
166 return 2;
168 if (ntdb_transaction_prepare_commit(ntdb)
169 != NTDB_ERR_LOCK)
170 return 3;
171 if (tap_log_messages == 2)
172 return 4;
174 last_log_messages = tap_log_messages;
175 /* Child can do this without any complaints. */
176 ntdb_transaction_cancel(ntdb);
177 if (tap_log_messages != last_log_messages)
178 return 4;
179 ntdb_close(ntdb);
180 if (tap_log_messages != last_log_messages)
181 return 4;
182 return 0;
184 wait(&status);
185 ok1(WIFEXITED(status) && WEXITSTATUS(status) == 0);
186 ntdb_transaction_cancel(ntdb);
188 ok1(ntdb_parse_record(ntdb, key, fork_in_parse, ntdb)
189 == NTDB_SUCCESS);
190 ntdb_close(ntdb);
191 if (am_child) {
192 /* Child can return from parse without complaints. */
193 if (tap_log_messages != 2)
194 exit(3);
195 exit(0);
197 ok1(tap_log_messages == 0);
199 return exit_status();