about summary refs log tree commit homepage
path: root/t/mbox_lock.t
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2021-02-25 22:41:38 -1100
committerEric Wong <e@80x24.org>2021-02-26 16:50:50 -0400
commit3104d7492aa4aee07455dcad7449f786188afdf5 (patch)
tree037d7e28dadca739e6d48ec98e7fa08a4ac2327b /t/mbox_lock.t
parent5d31cff1f1b3d59e4c2be534183aeda3725a7649 (diff)
downloadpublic-inbox-3104d7492aa4aee07455dcad7449f786188afdf5.tar.gz
While this diverges from from mairix(1) behavior, it's the safer
option.  We'll follow Debian policy by supporting fcntl and
dotlocks by default (in that order).  Users who do not want
locking can use "--lock=none"

This will be used in a read-only capacity for watching
mailboxes for keyword updates via inotify or EVFILT_VNODE.
Diffstat (limited to 't/mbox_lock.t')
-rw-r--r--t/mbox_lock.t90
1 files changed, 90 insertions, 0 deletions
diff --git a/t/mbox_lock.t b/t/mbox_lock.t
new file mode 100644
index 00000000..3dc3b449
--- /dev/null
+++ b/t/mbox_lock.t
@@ -0,0 +1,90 @@
+#!perl -w
+# Copyright (C) 2021 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+use strict; use v5.10.1; use PublicInbox::TestCommon;
+use POSIX qw(_exit);
+use PublicInbox::DS qw(now);
+use Errno qw(EAGAIN);
+use_ok 'PublicInbox::MboxLock';
+my ($tmpdir, $for_destroy) = tmpdir();
+my $f = "$tmpdir/f";
+my $mbl = PublicInbox::MboxLock->acq($f, 1, ['dotlock']);
+ok(-f "$f.lock", 'dotlock created');
+undef $mbl;
+ok(!-f "$f.lock", 'dotlock gone');
+$mbl = PublicInbox::MboxLock->acq($f, 1, ['none']);
+ok(!-f "$f.lock", 'no dotlock with none');
+undef $mbl;
+
+eval {
+        PublicInbox::MboxLock->acq($f, 1, ['bogus']);
+        fail "should not succeed with `bogus'";
+};
+ok($@, "fails on `bogus' lock method");
+eval {
+        PublicInbox::MboxLock->acq($f, 1, ['timeout=1']);
+        fail "should not succeed with only timeout";
+};
+ok($@, "fails with only `timeout=' and no lock method");
+
+my $defaults = PublicInbox::MboxLock->defaults;
+is(ref($defaults), 'ARRAY', 'default lock methods');
+my $test_rw_lock = sub {
+        my ($func) = @_;
+        my $m = ["$func,timeout=0.000001"];
+        for my $i (1..2) {
+                pipe(my ($r, $w)) or BAIL_OUT "pipe: $!";
+                my $t0 = now;
+                my $pid = fork // BAIL_OUT "fork $!";
+                if ($pid == 0) {
+                        eval { PublicInbox::MboxLock->acq($f, 1, $m) };
+                        my $err = $@;
+                        syswrite $w, "E: $err";
+                        _exit($err ? 0 : 1);
+                }
+                undef $w;
+                waitpid($pid, 0);
+                is($?, 0, "$func r/w lock behaved as expected #$i");
+                my $d = now - $t0;
+                ok($d < 1, "$func r/w timeout #$i") or diag "elapsed=$d";
+                my $err = do { local $/; <$r> };
+                $! = EAGAIN;
+                my $msg = "$!";
+                like($err, qr/\Q$msg\E/, "got EAGAIN in child #$i");
+        }
+};
+
+my $test_ro_lock = sub {
+        my ($func) = @_;
+        for my $i (1..2) {
+                my $t0 = now;
+                my $pid = fork // BAIL_OUT "fork $!";
+                if ($pid == 0) {
+                        eval { PublicInbox::MboxLock->acq($f, 0, [ $func ]) };
+                        _exit($@ ? 1 : 0);
+                }
+                waitpid($pid, 0);
+                is($?, 0, "$func ro lock behaved as expected #$i");
+                my $d = now - $t0;
+                ok($d < 1, "$func timeout respected #$i") or diag "elapsed=$d";
+        }
+};
+
+SKIP: {
+        grep(/fcntl/, @$defaults) or skip 'File::FcntlLock not available', 1;
+        my $top = PublicInbox::MboxLock->acq($f, 1, $defaults);
+        ok($top, 'fcntl lock acquired');
+        $test_rw_lock->('fcntl');
+        undef $top;
+        $top = PublicInbox::MboxLock->acq($f, 0, $defaults);
+        ok($top, 'fcntl read lock acquired');
+        $test_ro_lock->('fcntl');
+}
+$mbl = PublicInbox::MboxLock->acq($f, 1, ['flock']);
+ok($mbl, 'flock acquired');
+$test_rw_lock->('flock');
+undef $mbl;
+$mbl = PublicInbox::MboxLock->acq($f, 0, ['flock']);
+$test_ro_lock->('flock');
+
+done_testing;