From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-3.3 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00, NUMERIC_HTTP_ADDR,WEIRD_PORT shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 98D671FC0C for ; Sat, 6 Feb 2021 12:18:45 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 10/17] tests: split out lei-daemon.t from lei.t Date: Sat, 6 Feb 2021 12:18:37 +0000 Message-Id: <20210206121844.10979-11-e@80x24.org> In-Reply-To: <20210206121844.10979-1-e@80x24.org> References: <20210206121844.10979-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: This makes it easier for hackers to find daemon-specific tests and forces us to always test both daemon and oneshot mode. --- MANIFEST | 2 +- lib/PublicInbox/TestCommon.pm | 8 +- t/lei-daemon.t | 63 ++++++++++++ t/lei-oneshot.t | 8 -- t/lei.t | 177 ++++++++-------------------------- 5 files changed, 107 insertions(+), 151 deletions(-) create mode 100644 t/lei-daemon.t delete mode 100644 t/lei-oneshot.t diff --git a/MANIFEST b/MANIFEST index 000834cc..52dea385 100644 --- a/MANIFEST +++ b/MANIFEST @@ -354,9 +354,9 @@ t/init.t t/ipc.t t/iso-2202-jp.eml t/kqnotify.t +t/lei-daemon.t t/lei-externals.t t/lei-import.t -t/lei-oneshot.t t/lei.t t/lei_dedupe.t t/lei_external.t diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm index bb2cd7e6..c861dc5d 100644 --- a/lib/PublicInbox/TestCommon.pm +++ b/lib/PublicInbox/TestCommon.pm @@ -456,13 +456,15 @@ SKIP: { require PublicInbox::Spawn; state $lei_daemon = PublicInbox::Spawn->can('send_cmd4') || eval { require Socket::MsgHdr; 1 }; + # XXX fix and move this inside daemon-only before 1.7 release + skip <<'EOM', 1 unless $lei_daemon; +Socket::MsgHdr missing or Inline::C is unconfigured/missing +EOM $lei_opt = { 1 => \$lei_out, 2 => \$lei_err }; my $daemon_pid; my ($tmpdir, $for_destroy) = tmpdir(); SKIP: { - skip <<'EOM', 1 unless $lei_daemon; -Socket::MsgHdr missing or Inline::C is unconfigured/missing -EOM + skip 'TEST_LEI_ONESHOT set', 1 if $ENV{TEST_LEI_ONESHOT}; my $home = "$tmpdir/lei-daemon"; mkdir($home, 0700) or BAIL_OUT "mkdir: $!"; local $ENV{HOME} = $home; diff --git a/t/lei-daemon.t b/t/lei-daemon.t new file mode 100644 index 00000000..c55ba86c --- /dev/null +++ b/t/lei-daemon.t @@ -0,0 +1,63 @@ +#!perl -w +# Copyright (C) 2020-2021 all contributors +# License: AGPL-3.0+ +use strict; use v5.10.1; use PublicInbox::TestCommon; + +test_lei({ daemon_only => 1 }, sub { + my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/5.seq.sock"; + my $err_log = "$ENV{XDG_RUNTIME_DIR}/lei/errors.log"; + ok($lei->('daemon-pid'), 'daemon-pid'); + is($lei_err, '', 'no error from daemon-pid'); + like($lei_out, qr/\A[0-9]+\n\z/s, 'pid returned') or BAIL_OUT; + chomp(my $pid = $lei_out); + ok(kill(0, $pid), 'pid is valid'); + ok(-S $sock, 'sock created'); + is(-s $err_log, 0, 'nothing in errors.log'); + open my $efh, '>>', $err_log or BAIL_OUT $!; + print $efh "phail\n" or BAIL_OUT $!; + close $efh or BAIL_OUT $!; + + ok($lei->('daemon-pid'), 'daemon-pid'); + chomp(my $pid_again = $lei_out); + is($pid, $pid_again, 'daemon-pid idempotent'); + like($lei_err, qr/phail/, 'got mock "phail" error previous run'); + + ok($lei->(qw(daemon-kill)), 'daemon-kill'); + is($lei_out, '', 'no output from daemon-kill'); + is($lei_err, '', 'no error from daemon-kill'); + for (0..100) { + kill(0, $pid) or last; + tick(); + } + ok(-S $sock, 'sock still exists'); + ok(!kill(0, $pid), 'pid gone after stop'); + + ok($lei->(qw(daemon-pid)), 'daemon-pid'); + chomp(my $new_pid = $lei_out); + ok(kill(0, $new_pid), 'new pid is running'); + ok(-S $sock, 'sock still exists'); + + for my $sig (qw(-0 -CHLD)) { + ok($lei->('daemon-kill', $sig), "handles $sig"); + } + is($lei_out.$lei_err, '', 'no output on innocuous signals'); + ok($lei->('daemon-pid'), 'daemon-pid'); + chomp $lei_out; + is($lei_out, $new_pid, 'PID unchanged after -0/-CHLD'); + + if ('socket inaccessible') { + chmod 0000, $sock or BAIL_OUT "chmod 0000: $!"; + ok($lei->('help'), 'connect fail, one-shot fallback works'); + like($lei_err, qr/\bconnect\(/, 'connect error noted'); + like($lei_out, qr/^usage: /, 'help output works'); + chmod 0700, $sock or BAIL_OUT "chmod 0700: $!"; + } + unlink $sock or BAIL_OUT "unlink($sock) $!"; + for (0..100) { + kill('CHLD', $new_pid) or last; + tick(); + } + ok(!kill(0, $new_pid), 'daemon exits after unlink'); +}); + +done_testing; diff --git a/t/lei-oneshot.t b/t/lei-oneshot.t deleted file mode 100644 index 7688da5b..00000000 --- a/t/lei-oneshot.t +++ /dev/null @@ -1,8 +0,0 @@ -#!perl -w -# Copyright (C) 2020-2021 all contributors -# License: AGPL-3.0+ -use strict; -use v5.10.1; -use PublicInbox::TestCommon; -local $ENV{TEST_LEI_ONESHOT} = '1'; -require './t/lei.t'; diff --git a/t/lei.t b/t/lei.t index cfcdafb9..f789f63a 100644 --- a/t/lei.t +++ b/t/lei.t @@ -1,87 +1,56 @@ #!perl -w # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ -use strict; -use v5.10.1; -use Test::More; -use PublicInbox::TestCommon; -use PublicInbox::Config; +use strict; use v5.10.1; use PublicInbox::TestCommon; use File::Path qw(rmtree); use PublicInbox::Spawn qw(which); -my $req_sendcmd = 'Socket::MsgHdr or Inline::C missing or unconfigured'; -undef($req_sendcmd) if PublicInbox::Spawn->can('send_cmd4'); -eval { require Socket::MsgHdr; undef $req_sendcmd }; -require_git 2.6; -require_mods(qw(json DBD::SQLite Search::Xapian)); -my $opt = { 1 => \(my $out = ''), 2 => \(my $err = '') }; -my ($home, $for_destroy) = tmpdir(); -my $err_filter; -my $curl = which('curl'); -my $json = ref(PublicInbox::Config->json)->new->utf8->canonical; -my $lei = sub { - my ($cmd, $env, $xopt) = @_; - $out = $err = ''; - if (!ref($cmd)) { - ($env, $xopt) = grep { (!defined) || ref } @_; - $cmd = [ grep { defined && !ref } @_ ]; - } - my $res = run_script(['lei', @$cmd], $env, $xopt // $opt); - $err_filter and - $err = join('', grep(!/$err_filter/, split(/^/m, $err))); - $res; -}; -delete local $ENV{XDG_DATA_HOME}; -delete local $ENV{XDG_CONFIG_HOME}; -local $ENV{GIT_COMMITTER_EMAIL} = 'lei@example.com'; -local $ENV{GIT_COMMITTER_NAME} = 'lei user'; -local $ENV{XDG_RUNTIME_DIR} = "$home/xdg_run"; -local $ENV{HOME} = $home; -mkdir "$home/xdg_run", 0700 or BAIL_OUT "mkdir: $!"; -my $home_trash = [ "$home/.local", "$home/.config", "$home/junk" ]; +# this only tests the basic help/config/init/completion bits of lei; +# actual functionality is tested in other t/lei-*.t tests +my $curl = which('curl'); +my $home; +my $home_trash = []; my $cleanup = sub { rmtree([@$home_trash, @_]) }; -my $config_file = "$home/.config/lei/config"; -my $store_dir = "$home/.local/share/lei"; my $test_help = sub { ok(!$lei->(), 'no args fails'); is($? >> 8, 1, '$? is 1'); - is($out, '', 'nothing in stdout'); - like($err, qr/^usage:/sm, 'usage in stderr'); + is($lei_out, '', 'nothing in stdout'); + like($lei_err, qr/^usage:/sm, 'usage in stderr'); for my $arg (['-h'], ['--help'], ['help'], [qw(daemon-pid --help)]) { ok($lei->($arg), "lei @$arg"); - like($out, qr/^usage:/sm, "usage in stdout (@$arg)"); - is($err, '', "nothing in stderr (@$arg)"); + like($lei_out, qr/^usage:/sm, "usage in stdout (@$arg)"); + is($lei_err, '', "nothing in stderr (@$arg)"); } for my $arg ([''], ['--halp'], ['halp'], [qw(daemon-pid --halp)]) { ok(!$lei->($arg), "lei @$arg"); is($? >> 8, 1, '$? set correctly'); - isnt($err, '', 'something in stderr'); - is($out, '', 'nothing in stdout'); + isnt($lei_err, '', 'something in stderr'); + is($lei_out, '', 'nothing in stdout'); } ok($lei->(qw(init -h)), 'init -h'); - like($out, qr! \Q$home\E/\.local/share/lei/store\b!, + like($lei_out, qr! \Q$home\E/\.local/share/lei/store\b!, 'actual path shown in init -h'); ok($lei->(qw(init -h), { XDG_DATA_HOME => '/XDH' }), 'init with XDG_DATA_HOME'); - like($out, qr! /XDH/lei/store\b!, 'XDG_DATA_HOME in init -h'); - is($err, '', 'no errors from init -h'); + like($lei_out, qr! /XDH/lei/store\b!, 'XDG_DATA_HOME in init -h'); + is($lei_err, '', 'no errors from init -h'); ok($lei->(qw(config -h)), 'config-h'); - like($out, qr! \Q$home\E/\.config/lei/config\b!, + like($lei_out, qr! \Q$home\E/\.config/lei/config\b!, 'actual path shown in config -h'); ok($lei->(qw(config -h), { XDG_CONFIG_HOME => '/XDC' }), 'config with XDG_CONFIG_HOME'); - like($out, qr! /XDC/lei/config\b!, 'XDG_CONFIG_HOME in config -h'); - is($err, '', 'no errors from config -h'); + like($lei_out, qr! /XDC/lei/config\b!, 'XDG_CONFIG_HOME in config -h'); + is($lei_err, '', 'no errors from config -h'); }; my $ok_err_info = sub { my ($msg) = @_; - is(grep(!/^I:/, split(/^/, $err)), 0, $msg) or - diag "$msg: err=$err"; + is(grep(!/^I:/, split(/^/, $lei_err)), 0, $msg) or + diag "$msg: err=$lei_err"; }; my $test_init = sub { @@ -92,7 +61,7 @@ my $test_init = sub { $ok_err_info->('after idempotent init w/o args'); ok(!$lei->('init', "$home/x"), 'init conflict'); - is(grep(/^E:/, split(/^/, $err)), 1, 'got error on conflict'); + is(grep(/^E:/, split(/^/, $lei_err)), 1, 'got error on conflict'); ok(!-e "$home/x", 'nothing created on conflict'); $cleanup->(); @@ -104,36 +73,36 @@ my $test_init = sub { $cleanup->("$home/x"); ok(!$lei->('init', "$home/x", "$home/2"), 'too many args fails'); - like($err, qr/too many/, 'noted excessive'); + like($lei_err, qr/too many/, 'noted excessive'); ok(!-e "$home/x", 'x not created on excessive'); for my $d (@$home_trash) { my $base = (split(m!/!, $d))[-1]; ok(!-d $d, "$base not created"); } - is($out, '', 'nothing in stdout on init failure'); + is($lei_out, '', 'nothing in stdout on init failure'); }; my $test_config = sub { $cleanup->(); ok($lei->(qw(config a.b c)), 'config set var'); - is($out.$err, '', 'no output on var set'); + is($lei_out.$lei_err, '', 'no output on var set'); ok($lei->(qw(config -l)), 'config -l'); - is($err, '', 'no errors on listing'); - is($out, "a.b=c\n", 'got expected output'); + is($lei_err, '', 'no errors on listing'); + is($lei_out, "a.b=c\n", 'got expected output'); ok(!$lei->(qw(config -f), "$home/.config/f", qw(x.y z)), 'config set var with -f fails'); - like($err, qr/not supported/, 'not supported noted'); + like($lei_err, qr/not supported/, 'not supported noted'); ok(!-f "$home/config/f", 'no file created'); }; my $test_completion = sub { ok($lei->(qw(_complete lei)), 'no errors on complete'); - my %out = map { $_ => 1 } split(/\s+/s, $out); + my %out = map { $_ => 1 } split(/\s+/s, $lei_out); ok($out{'q'}, "`lei q' offered as completion"); ok($out{'add-external'}, "`lei add-external' offered as completion"); ok($lei->(qw(_complete lei q)), 'complete q (no args)'); - %out = map { $_ => 1 } split(/\s+/s, $out); + %out = map { $_ => 1 } split(/\s+/s, $lei_out); for my $sw (qw(-f --format -o --output --mfolder --augment -a --mua --mua-cmd --no-local --local --verbose -v --save-as --no-remote --remote --torsocks @@ -142,17 +111,17 @@ my $test_completion = sub { } ok($lei->(qw(_complete lei q --form)), 'complete q --format'); - is($out, "--format\n", 'complete lei q --format'); + is($lei_out, "--format\n", 'complete lei q --format'); for my $sw (qw(-f --format)) { ok($lei->(qw(_complete lei q), $sw), "complete q $sw ARG"); - %out = map { $_ => 1 } split(/\s+/s, $out); + %out = map { $_ => 1 } split(/\s+/s, $lei_out); for my $f (qw(mboxrd mboxcl2 mboxcl mboxo json jsonl concatjson maildir)) { ok($out{$f}, "got $sw $f as output format"); } } ok($lei->(qw(_complete lei import)), 'complete import'); - %out = map { $_ => 1 } split(/\s+/s, $out); + %out = map { $_ => 1 } split(/\s+/s, $lei_out); for my $sw (qw(--flags --no-flags --no-kw --kw --no-keywords --keywords)) { ok($out{$sw}, "$sw offered as `lei import' completion"); @@ -161,93 +130,23 @@ my $test_completion = sub { my $test_fail = sub { SKIP: { - skip $req_sendcmd, 3 if $req_sendcmd; + skip 'no curl', 3 unless which('curl'); $lei->(qw(q --only http://127.0.0.1:99999/bogus/ t:m)); is($? >> 8, 3, 'got curl exit for bogus URL'); $lei->(qw(q --only http://127.0.0.1:99999/bogus/ t:m -o), "$home/junk"); is($? >> 8, 3, 'got curl exit for bogus URL with Maildir'); - is($out, '', 'no output'); + is($lei_out, '', 'no output'); }; # /SKIP }; -my $test_lei_common = sub { +test_lei(sub { + $home = $ENV{HOME}; + $home_trash = [ "$home/.local", "$home/.config", "$home/junk" ]; $test_help->(); $test_config->(); $test_init->(); $test_completion->(); $test_fail->(); -}; - -if ($ENV{TEST_LEI_ONESHOT}) { - require_ok 'PublicInbox::LEI'; - # force sun_path[108] overflow, ($lei->() filters out this path) - my $xrd = "$home/1shot-test".('.sun_path' x 108); - local $ENV{XDG_RUNTIME_DIR} = $xrd; - $err_filter = qr!\Q$xrd!; - $test_lei_common->(); -} else { -SKIP: { # real socket - skip $req_sendcmd, 115 if $req_sendcmd; - local $ENV{XDG_RUNTIME_DIR} = "$home/xdg_run"; - my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/5.seq.sock"; - my $err_log = "$ENV{XDG_RUNTIME_DIR}/lei/errors.log"; - - ok($lei->('daemon-pid'), 'daemon-pid'); - is($err, '', 'no error from daemon-pid'); - like($out, qr/\A[0-9]+\n\z/s, 'pid returned') or BAIL_OUT; - chomp(my $pid = $out); - ok(kill(0, $pid), 'pid is valid'); - ok(-S $sock, 'sock created'); - - $test_lei_common->(); - is(-s $err_log, 0, 'nothing in errors.log'); - open my $efh, '>>', $err_log or BAIL_OUT $!; - print $efh "phail\n" or BAIL_OUT $!; - close $efh or BAIL_OUT $!; - - ok($lei->('daemon-pid'), 'daemon-pid'); - chomp(my $pid_again = $out); - is($pid, $pid_again, 'daemon-pid idempotent'); - like($err, qr/phail/, 'got mock "phail" error previous run'); - - ok($lei->(qw(daemon-kill)), 'daemon-kill'); - is($out, '', 'no output from daemon-kill'); - is($err, '', 'no error from daemon-kill'); - for (0..100) { - kill(0, $pid) or last; - tick(); - } - ok(-S $sock, 'sock still exists'); - ok(!kill(0, $pid), 'pid gone after stop'); - - ok($lei->(qw(daemon-pid)), 'daemon-pid'); - chomp(my $new_pid = $out); - ok(kill(0, $new_pid), 'new pid is running'); - ok(-S $sock, 'sock still exists'); - - for my $sig (qw(-0 -CHLD)) { - ok($lei->('daemon-kill', $sig), "handles $sig"); - } - is($out.$err, '', 'no output on innocuous signals'); - ok($lei->('daemon-pid'), 'daemon-pid'); - chomp $out; - is($out, $new_pid, 'PID unchanged after -0/-CHLD'); - - if ('socket inaccessible') { - chmod 0000, $sock or BAIL_OUT "chmod 0000: $!"; - ok($lei->('help'), 'connect fail, one-shot fallback works'); - like($err, qr/\bconnect\(/, 'connect error noted'); - like($out, qr/^usage: /, 'help output works'); - chmod 0700, $sock or BAIL_OUT "chmod 0700: $!"; - } - unlink $sock or BAIL_OUT "unlink($sock) $!"; - for (0..100) { - kill('CHLD', $new_pid) or last; - tick(); - } - ok(!kill(0, $new_pid), 'daemon exits after unlink'); - # success over socket, can't test without -}; # SKIP -} # else +}); done_testing;