From 3ae5275eb187ed00bb83061a4d37a161bc8eb3e7 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 31 Dec 2020 13:51:32 +0000 Subject: ipc: generic IPC dispatch based on Storable I intend to use this with LeiStore when importing from multiple slow sources at once (e.g. curl, IMAP, etc). This is because over.sqlite3 can only have a single writer, and we'll have several slow readers running in parallel. Watch and SearchIdxShard should also be able to use this code in the future, but this will be proven with LeiStore, first. --- t/ipc.t | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ t/lei_store.t | 5 +++++ 2 files changed, 72 insertions(+) create mode 100644 t/ipc.t (limited to 't') diff --git a/t/ipc.t b/t/ipc.t new file mode 100644 index 00000000..f9c4024b --- /dev/null +++ b/t/ipc.t @@ -0,0 +1,67 @@ +#!perl -w +# Copyright (C) 2020 all contributors +# License: AGPL-3.0+ +use strict; +use v5.10.1; +use Test::More; +use PublicInbox::TestCommon; +require_ok 'PublicInbox::IPC'; +state $once = eval <<''; +package PublicInbox::IPC; +use strict; +sub test_array { qw(test array) } +sub test_scalar { 'scalar' } +sub test_scalarref { \'scalarref' } +sub test_undef { undef } +sub test_die { shift; die @_; 'unreachable' } +sub test_pid { $$ } +1; + +my $ipc = bless {}, 'PublicInbox::IPC'; +my @t = qw(array scalar scalarref undef); +my $test = sub { + my $x = shift; + for my $type (@t) { + my $m = "test_$type"; + my @ret = $ipc->ipc_do($m); + my @exp = $ipc->$m; + is_deeply(\@ret, \@exp, "wantarray $m $x"); + + $ipc->ipc_do($m); + + my $ret = $ipc->ipc_do($m); + my $exp = $ipc->$m; + is_deeply($ret, $exp, "!wantarray $m $x"); + } + my $ret = eval { $ipc->test_die('phail') }; + my $exp = $@; + $ret = eval { $ipc->ipc_do('test_die', 'phail') }; + my $err = $@; + my %lines; + for ($err, $exp) { + s/ line (\d+).*//s and $lines{$1}++; + } + is(scalar keys %lines, 1, 'line numbers match'); + is((values %lines)[0], 2, '2 hits on same line number'); + is($err, $exp, "$x die matches"); + is($ret, undef, "$x die did not return"); +}; +$test->('local'); + +SKIP: { + require_mods(qw(Storable), 16); + my $pid = $ipc->ipc_worker_spawn('test worker'); + ok($pid > 0 && kill(0, $pid), 'worker spawned and running'); + defined($pid) or BAIL_OUT 'no spawn, no test'; + is($ipc->ipc_do('test_pid'), $pid, 'worker pid returned'); + $test->('worker'); + { + my ($tmp, $for_destroy) = tmpdir(); + $ipc->ipc_lock_init("$tmp/lock"); + is($ipc->ipc_do('test_pid'), $pid, 'worker pid returned'); + } + $ipc->ipc_worker_stop; + ok(!kill(0, $pid) && $!{ESRCH}, 'worker stopped'); +} +$ipc->ipc_worker_stop; # idempotent +done_testing; diff --git a/t/lei_store.t b/t/lei_store.t index 03ab5af6..a189f897 100644 --- a/t/lei_store.t +++ b/t/lei_store.t @@ -85,4 +85,9 @@ for my $parallel (0, 1) { is_deeply(\@kw, [], 'set clobbers all'); } +SKIP: { + require_mods(qw(Storable), 1); + ok($lst->can('ipc_do'), 'ipc_do works if we have Storable'); +} + done_testing; -- cgit v1.2.3-24-ge0c7