2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
28 #include "testutils.h"
29 #include "glib-util.h"
32 extern amflock_impl_t *amflock_impls[];
34 #define TEST_FILENAME "./amflocktest.file"
36 /* Test all amflock implementations available for basic
42 amflock_impl_t **imp = amflock_impls;
43 char *resource = "rez";
47 /* set lnlock's lock directory to the current directory */
48 extern char *_lnlock_dir;
52 tu_dbg("Testing amflock-%s\n", (*imp)->impl_name);
54 for (lock_ro = 0; lock_ro < 2; lock_ro++) { /* false (0) or true (1) */
55 if (unlink(TEST_FILENAME) == -1 && errno != ENOENT) {
60 if ((fd = open(TEST_FILENAME, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) {
66 if ((*imp)->amroflock_impl(fd, resource) != 0) {
71 if ((*imp)->amflock_impl(fd, resource) != 0) {
77 if ((*imp)->amfunlock_impl(fd, resource) != 0) {
82 close(fd); /* ignore error */
83 unlink(TEST_FILENAME); /* ignore error */
86 fprintf(stderr, " PASS amflock-%s\n", (*imp)->impl_name);
95 * Test lock and write_and_unlock
98 inc_counter(file_lock *lock)
104 old_val = lock->data[0];
107 g_assert(old_val < 'z');
109 new_val = old_val + 1;
110 if (file_lock_write(lock, &new_val, 1) == -1) {
111 g_fprintf(stderr, "file_lock_write: %s\n",
119 #define pipeget(fd, cp) \
120 (read((fd), (cp), 1) == 1)
122 #define pipeput(fd, s) \
123 g_assert(write((fd), s, 1) == 1);
126 locking_slave(int in_fd, int out_fd)
130 file_lock *lock = file_lock_new(TEST_FILENAME);
134 if (!pipeget(in_fd, &cmd))
138 case 'q': /* q = quit */
139 tu_dbg("slave: quitting\n");
140 file_lock_free(lock);
144 case 'l': /* l = try locking; reply with 'y' or 'n' */
146 rv = file_lock_lock(lock);
148 g_fprintf(stderr, "file_lock_lock: %s\n",
152 tu_dbg("slave: lock attempt => %s\n", (rv == 1)? "n" : "y");
153 pipeput(out_fd, (rv == 1)? "n" : "y");
158 case 'i': /* i = increment counter, reply with new value */
160 if (!inc_counter(lock))
162 tu_dbg("slave: inc'd to %c\n", lock->data[0]);
163 pipeput(out_fd, lock->data);
166 case 'u': /* u = try unlocking; reply with 'k' */
168 rv = file_lock_unlock(lock);
170 g_fprintf(stderr, "file_lock_unlock: %s\n",
174 tu_dbg("slave: unlocked\n");
175 pipeput(out_fd, "k");
186 locking_master(int in_fd, int out_fd)
188 file_lock *lock = file_lock_new(TEST_FILENAME);
192 /* start by locking here and incrementing the value */
193 rv = file_lock_lock(lock);
195 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
198 g_assert(rv != 1); /* not already locked */
199 tu_dbg("master: locked\n");
201 if (!inc_counter(lock))
204 g_assert(lock->data[0] == 'b');
205 tu_dbg("master: inc'd to b\n");
207 /* unlock and re-lock */
208 rv = file_lock_unlock(lock);
210 g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
213 tu_dbg("master: unlocked\n");
215 rv = file_lock_lock(lock);
217 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
220 g_assert(rv != 1); /* not already locked */
221 tu_dbg("master: locked\n");
224 g_assert(lock->data[0] == 'b');
226 g_assert(lock->data[0] == 'c');
227 tu_dbg("master: inc'd to c\n");
229 /* the slave should fail to get a lock now */
230 pipeput(out_fd, "l");
231 g_assert(pipeget(in_fd, &slaveres));
232 g_assert(slaveres == 'n');
234 /* and, finally unlock */
235 rv = file_lock_unlock(lock);
237 g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
240 tu_dbg("master: unlocked\n");
242 /* the slave should succeed now */
243 pipeput(out_fd, "l");
244 g_assert(pipeget(in_fd, &slaveres));
245 g_assert(slaveres == 'y');
247 pipeput(out_fd, "i");
248 g_assert(pipeget(in_fd, &slaveres));
249 g_assert(slaveres == 'd');
251 /* master shouldn't be able to lock now */
252 rv = file_lock_lock(lock);
254 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
257 g_assert(rv == 1); /* already locked */
258 tu_dbg("master: lock attempt failed (as expected)\n");
260 pipeput(out_fd, "i");
261 g_assert(pipeget(in_fd, &slaveres));
262 g_assert(slaveres == 'e');
264 /* get the slave to unlock */
265 pipeput(out_fd, "u");
266 g_assert(pipeget(in_fd, &slaveres));
267 g_assert(slaveres == 'k');
269 /* we should get a lock now */
270 rv = file_lock_lock(lock);
272 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
275 g_assert(rv != 1); /* not already locked */
276 tu_dbg("master: lock attempt succeeded\n");
278 g_assert(lock->data[0] == 'e');
280 /* leave it unlocked, just to see what happens */
286 test_intra_proc_locking_thd(gpointer *fdptr)
288 int *fds = (int *)fdptr;
289 locking_slave(fds[0], fds[1]);
294 test_intra_proc_locking(void)
297 int outpipe[2], inpipe[2];
301 unlink(TEST_FILENAME);
303 g_assert(pipe(outpipe) == 0);
304 g_assert(pipe(inpipe) == 0);
306 thd_fds[0] = outpipe[0];
307 thd_fds[1] = inpipe[1];
308 thd = g_thread_create((GThreadFunc)test_intra_proc_locking_thd, (gpointer)thd_fds, TRUE, NULL);
310 rv = locking_master(inpipe[0], outpipe[1]);
312 /* close the write end of the outgoing pipe, which should trigger an EOF on
313 * the slave if it's still running */
316 unlink(TEST_FILENAME);
318 /* caller will kill the remaining files */
324 test_inter_proc_locking(void)
326 int outpipe[2], inpipe[2];
330 unlink(TEST_FILENAME);
332 g_assert(pipe(outpipe) == 0);
333 g_assert(pipe(inpipe) == 0);
335 if ((pid = fork()) == 0) {
338 locking_slave(outpipe[0], inpipe[1]);
345 rv = locking_master(inpipe[0], outpipe[1]);
347 /* close the write end of the outgoing pipe, which should trigger an EOF on
348 * the slave if it's still running */
350 waitpid(pid, NULL, 0);
351 unlink(TEST_FILENAME);
353 /* caller will kill the remaining files */
359 main(int argc, char **argv)
361 static TestUtilsTest tests[] = {
362 TU_TEST(test_old_impls, 90),
363 TU_TEST(test_inter_proc_locking, 60),
364 TU_TEST(test_intra_proc_locking, 60),
369 return testutils_run_tests(argc, argv, tests);