2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
29 #include "testutils.h"
30 #include "glib-util.h"
33 extern amflock_impl_t *amflock_impls[];
35 #define TEST_FILENAME "./amflocktest.file"
37 /* Test all amflock implementations available for basic
43 amflock_impl_t **imp = amflock_impls;
44 char *resource = "rez";
48 /* set lnlock's lock directory to the current directory */
49 extern char *_lnlock_dir;
53 tu_dbg("Testing amflock-%s\n", (*imp)->impl_name);
55 for (lock_ro = 0; lock_ro < 2; lock_ro++) { /* false (0) or true (1) */
56 if (unlink(TEST_FILENAME) == -1 && errno != ENOENT) {
61 if ((fd = open(TEST_FILENAME, O_RDWR | O_CREAT | O_EXCL, 0600)) == -1) {
67 if ((*imp)->amroflock_impl(fd, resource) != 0) {
72 if ((*imp)->amflock_impl(fd, resource) != 0) {
78 if ((*imp)->amfunlock_impl(fd, resource) != 0) {
83 close(fd); /* ignore error */
84 unlink(TEST_FILENAME); /* ignore error */
87 fprintf(stderr, " PASS amflock-%s\n", (*imp)->impl_name);
96 * Test lock and write_and_unlock
99 inc_counter(file_lock *lock)
105 old_val = lock->data[0];
108 g_assert(old_val < 'z');
110 new_val = old_val + 1;
111 if (file_lock_write(lock, &new_val, 1) == -1) {
112 g_fprintf(stderr, "file_lock_write: %s\n",
120 #define pipeget(fd, cp) \
121 (read((fd), (cp), 1) == 1)
123 #define pipeput(fd, s) \
124 g_assert(write((fd), s, 1) == 1);
127 locking_slave(int in_fd, int out_fd)
131 file_lock *lock = file_lock_new(TEST_FILENAME);
135 if (!pipeget(in_fd, &cmd))
139 case 'q': /* q = quit */
140 tu_dbg("slave: quitting\n");
141 file_lock_free(lock);
145 case 'l': /* l = try locking; reply with 'y' or 'n' */
147 rv = file_lock_lock(lock);
149 g_fprintf(stderr, "file_lock_lock: %s\n",
153 tu_dbg("slave: lock attempt => %s\n", (rv == 1)? "n" : "y");
154 pipeput(out_fd, (rv == 1)? "n" : "y");
159 case 'i': /* i = increment counter, reply with new value */
161 if (!inc_counter(lock))
163 tu_dbg("slave: inc'd to %c\n", lock->data[0]);
164 pipeput(out_fd, lock->data);
167 case 'u': /* u = try unlocking; reply with 'k' */
169 rv = file_lock_unlock(lock);
171 g_fprintf(stderr, "file_lock_unlock: %s\n",
175 tu_dbg("slave: unlocked\n");
176 pipeput(out_fd, "k");
187 locking_master(int in_fd, int out_fd)
189 file_lock *lock = file_lock_new(TEST_FILENAME);
193 /* start by locking here and incrementing the value */
194 rv = file_lock_lock(lock);
196 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
199 g_assert(rv != 1); /* not already locked */
200 tu_dbg("master: locked\n");
202 if (!inc_counter(lock))
205 g_assert(lock->data[0] == 'b');
206 tu_dbg("master: inc'd to b\n");
208 /* unlock and re-lock */
209 rv = file_lock_unlock(lock);
211 g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
214 tu_dbg("master: unlocked\n");
216 rv = file_lock_lock(lock);
218 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
221 g_assert(rv != 1); /* not already locked */
222 tu_dbg("master: locked\n");
225 g_assert(lock->data[0] == 'b');
227 g_assert(lock->data[0] == 'c');
228 tu_dbg("master: inc'd to c\n");
230 /* the slave should fail to get a lock now */
231 pipeput(out_fd, "l");
232 g_assert(pipeget(in_fd, &slaveres));
233 g_assert(slaveres == 'n');
235 /* and, finally unlock */
236 rv = file_lock_unlock(lock);
238 g_fprintf(stderr, "file_lock_unlock: %s\n", strerror(errno));
241 tu_dbg("master: unlocked\n");
243 /* the slave should succeed now */
244 pipeput(out_fd, "l");
245 g_assert(pipeget(in_fd, &slaveres));
246 g_assert(slaveres == 'y');
248 pipeput(out_fd, "i");
249 g_assert(pipeget(in_fd, &slaveres));
250 g_assert(slaveres == 'd');
252 /* master shouldn't be able to lock now */
253 rv = file_lock_lock(lock);
255 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
258 g_assert(rv == 1); /* already locked */
259 tu_dbg("master: lock attempt failed (as expected)\n");
261 pipeput(out_fd, "i");
262 g_assert(pipeget(in_fd, &slaveres));
263 g_assert(slaveres == 'e');
265 /* get the slave to unlock */
266 pipeput(out_fd, "u");
267 g_assert(pipeget(in_fd, &slaveres));
268 g_assert(slaveres == 'k');
270 /* we should get a lock now */
271 rv = file_lock_lock(lock);
273 g_fprintf(stderr, "file_lock_lock: %s\n", strerror(errno));
276 g_assert(rv != 1); /* not already locked */
277 tu_dbg("master: lock attempt succeeded\n");
279 g_assert(lock->data[0] == 'e');
281 /* leave it unlocked, just to see what happens */
287 test_intra_proc_locking_thd(gpointer *fdptr)
289 int *fds = (int *)fdptr;
290 locking_slave(fds[0], fds[1]);
295 test_intra_proc_locking(void)
298 int outpipe[2], inpipe[2];
302 unlink(TEST_FILENAME);
304 g_assert(pipe(outpipe) == 0);
305 g_assert(pipe(inpipe) == 0);
307 thd_fds[0] = outpipe[0];
308 thd_fds[1] = inpipe[1];
309 thd = g_thread_create((GThreadFunc)test_intra_proc_locking_thd, (gpointer)thd_fds, TRUE, NULL);
311 rv = locking_master(inpipe[0], outpipe[1]);
313 /* close the write end of the outgoing pipe, which should trigger an EOF on
314 * the slave if it's still running */
317 unlink(TEST_FILENAME);
319 /* caller will kill the remaining files */
325 test_inter_proc_locking(void)
327 int outpipe[2], inpipe[2];
331 unlink(TEST_FILENAME);
333 g_assert(pipe(outpipe) == 0);
334 g_assert(pipe(inpipe) == 0);
336 if ((pid = fork()) == 0) {
339 locking_slave(outpipe[0], inpipe[1]);
346 rv = locking_master(inpipe[0], outpipe[1]);
348 /* close the write end of the outgoing pipe, which should trigger an EOF on
349 * the slave if it's still running */
351 waitpid(pid, NULL, 0);
352 unlink(TEST_FILENAME);
354 /* caller will kill the remaining files */
360 main(int argc, char **argv)
362 static TestUtilsTest tests[] = {
363 TU_TEST(test_old_impls, 90),
364 TU_TEST(test_inter_proc_locking, 60),
365 TU_TEST(test_intra_proc_locking, 60),
370 return testutils_run_tests(argc, argv, tests);