lib/PublicInbox/TestCommon.pm | 20 +++++++++++++------- t/ds-leak.t | 9 +++------ t/hl_mod.t | 9 ++------- t/httpd-corner.t | 11 ++++------- t/imapd.t | 1 - t/lei-daemon.t | 1 - t/lei-externals.t | 8 ++++---- t/lei-import-http.t | 3 +-- t/lei-mirror.t | 1 + t/lei-q-remote-import.t | 1 + t/lei.t | 4 +--- t/nntpd.t | 7 ++----- t/nodatacow.t | 10 ++++------ t/solver_git.t | 4 ++-- t/v2mirror.t | 6 ++---- t/v2reindex.t | 8 ++------ t/www_altid.t | 8 +++----- t/www_listing.t | 8 ++------ diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm index 628beaf1315f111f1fa897f5afc29f975eb32c0b..d8346673b34e5c0fe6c155de8ee90df99ef97c7c 100644 --- a/lib/PublicInbox/TestCommon.pm +++ b/lib/PublicInbox/TestCommon.pm @@ -18,7 +18,7 @@ @EXPORT = qw(tmpdir tcp_server tcp_connect require_git require_mods run_script start_script key2sub xsys xsys_e xqx eml_load tick have_xapian_compact json_utf8 setup_public_inboxes create_inbox tcp_host_port test_lei lei lei_ok $lei_out $lei_err $lei_opt - test_httpd xbail); + test_httpd xbail require_cmd); require Test::More; my @methods = grep(!/\W/, @Test::More::EXPORT); eval(join('', map { "*$_=\\&Test::More::$_;" } @methods)); @@ -85,6 +85,18 @@ %opt, ) or BAIL_OUT "failed to connect to $addr: $!"; $s->autoflush(1); $s; +} + +sub require_cmd ($;$) { + my ($cmd, $maybe) = @_; + require PublicInbox::Spawn; + my $bin = PublicInbox::Spawn::which($cmd); + return $bin if $bin; + $maybe ? 0 : plan(skip_all => "$cmd missing from PATH for $0"); +} + +sub have_xapian_compact () { + require_cmd($ENV{XAPIAN_COMPACT} || 'xapian-compact', 1); } sub require_git ($;$) { @@ -465,12 +477,6 @@ die "FAIL: ",join(' ', $key, @argv), ": $!\n"; } } PublicInboxTestProcess->new($pid, $tail_pid); -} - -sub have_xapian_compact () { - require PublicInbox::Spawn; - # $ENV{XAPIAN_COMPACT} is used by PublicInbox/Xapcmd.pm, too - PublicInbox::Spawn::which($ENV{XAPIAN_COMPACT} || 'xapian-compact'); } # favor lei() or lei_ok() over $lei for new code diff --git a/t/ds-leak.t b/t/ds-leak.t index 57d9cd723ed4b30e403d1a4c9cbe5d6a11069fc3..4c211639ed164b51d58ff147727804800cb2dee7 100644 --- a/t/ds-leak.t +++ b/t/ds-leak.t @@ -3,14 +3,11 @@ # Licensed the same as Danga::Socket (and Perl5) # License: GPL-1.0+ or Artistic-1.0-Perl # # -use strict; -use warnings; -use Test::More; -use PublicInbox::TestCommon; +use strict; use v5.10.1; use PublicInbox::TestCommon; use_ok 'PublicInbox::DS'; if ('close-on-exec for epoll and kqueue') { - use PublicInbox::Spawn qw(spawn which); + use PublicInbox::Spawn qw(spawn); my $pid; my $evfd_re = qr/(?:kqueue|eventpoll)/i; @@ -32,7 +29,7 @@ my $l = <$r>; is($l, undef, 'cloexec works and sleep(1) is running'); SKIP: { - my $lsof = which('lsof') or skip 'lsof missing', 1; + my $lsof = require_cmd('lsof', 1) or skip 'lsof missing', 1; my $rdr = { 2 => \(my $null) }; my @of = grep(/$evfd_re/, xqx([$lsof, '-p', $pid], {}, $rdr)); my $err = $?; diff --git a/t/hl_mod.t b/t/hl_mod.t index ffe9e784489cc32fdbbe6bcf2383c44ec3cd02d7..96878d5191dfa29197ebb8dc616c3a6a2c17b196 100644 --- a/t/hl_mod.t +++ b/t/hl_mod.t @@ -1,12 +1,7 @@ #!/usr/bin/perl -w # Copyright (C) 2019-2021 all contributors # License: AGPL-3.0+ -use strict; -use warnings; -use Test::More; -use PublicInbox::Spawn qw(which); -use PublicInbox::TestCommon; -use IO::Handle; # ->autoflush +use strict; use v5.10.1; use PublicInbox::TestCommon; use IO::Handle; # ->autoflush use Fcntl qw(:seek); eval { require highlight } or plan skip_all => "failed to load highlight.pm for $0"; @@ -30,7 +25,7 @@ my $lref = $hls->do_hl_lang(\$str, 'perl'); is($$ref, $$lref, 'do_hl_lang matches do_hl'); SKIP: { - my $w3m = which('w3m') or + my $w3m = require_cmd('w3m', 1) or skip('w3m(1) missing to check output', 1); my $cmd = [ $w3m, qw(-T text/html -dump -config /dev/null) ]; my $in = '
' . $$ref . '
'; diff --git a/t/httpd-corner.t b/t/httpd-corner.t index 296e1dc1abfa1b7416838a40f3a813c5ad270353..5dc5734e96d1cb77028641c1ca47e0ad20afe0e8 100644 --- a/t/httpd-corner.t +++ b/t/httpd-corner.t @@ -2,12 +2,9 @@ # Copyright (C) 2016-2021 all contributors # License: AGPL-3.0+ # note: our HTTP server should be standalone and capable of running # generic PSGI/Plack apps. -use strict; -use warnings; -use Test::More; +use strict; use v5.10.1; use PublicInbox::TestCommon; use Time::HiRes qw(gettimeofday tv_interval); -use PublicInbox::Spawn qw(which spawn popen_rd); -use PublicInbox::TestCommon; +use PublicInbox::Spawn qw(spawn popen_rd); require_mods(qw(Plack::Util Plack::Builder HTTP::Date HTTP::Status)); use Digest::SHA qw(sha1_hex); use IO::Handle (); @@ -303,7 +300,7 @@ is($body, sha1_hex($str), 'read expected body'); }; SKIP: { - my $curl = which('curl') or skip('curl(1) missing', 4); + my $curl = require_cmd('curl', 1) or skip('curl(1) missing', 4); my $base = 'http://'.tcp_host_port($sock); my $url = "$base/sha1"; my ($r, $w); @@ -606,7 +603,7 @@ }; SKIP: { skip 'only testing lsof(8) output on Linux', 1 if $^O ne 'linux'; - my $lsof = which('lsof') or skip 'no lsof in PATH', 1; + my $lsof = require_cmd('lsof', 1) or skip 'no lsof in PATH', 1; my $null_in = ''; my $rdr = { 2 => \(my $null_err), 0 => \$null_in }; my @lsof = xqx([$lsof, '-p', $td->{pid}], undef, $rdr); diff --git a/t/imapd.t b/t/imapd.t index 906b69266e888d4387bcea74c96e2adb562bc97a..bd8ad7e5162d90231f9c27bab1f7801a3c6f875a 100644 --- a/t/imapd.t +++ b/t/imapd.t @@ -7,7 +7,6 @@ use Test::More; use Time::HiRes (); use PublicInbox::TestCommon; use PublicInbox::Config; -use PublicInbox::Spawn qw(which); require_mods(qw(-imapd Mail::IMAPClient)); my $imap_client = 'Mail::IMAPClient'; my $can_compress = $imap_client->can('compress'); diff --git a/t/lei-daemon.t b/t/lei-daemon.t index b0c94a8745286fa0c5cf787785c6690862be332e..b60c7ce6dc4aa8277219c10e33d676d9c39162bb 100644 --- a/t/lei-daemon.t +++ b/t/lei-daemon.t @@ -3,7 +3,6 @@ # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; use Socket qw(AF_UNIX SOCK_SEQPACKET MSG_EOR pack_sockaddr_un); -use PublicInbox::Spawn qw(which); test_lei({ daemon_only => 1 }, sub { my $send_cmd = PublicInbox::Spawn->can('send_cmd4') // do { diff --git a/t/lei-externals.t b/t/lei-externals.t index 5e3c67bc638ed80ef6f9ff72cf82cc0354d24332..fed57789d05aa1bcd7abc69e0afdd40e0d6849e2 100644 --- a/t/lei-externals.t +++ b/t/lei-externals.t @@ -3,7 +3,6 @@ # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; use Fcntl qw(SEEK_SET); -use PublicInbox::Spawn qw(which); require_git 2.6; require_mods(qw(json DBD::SQLite Search::Xapian)); use POSIX qw(WTERMSIG WIFSIGNALED SIGPIPE); @@ -17,9 +16,10 @@ my $test_external_remote = sub { my ($url, $k) = @_; SKIP: { skip "$k unset", 1 if !$url; - state $curl = which('curl'); - $curl or skip 'no curl', 1; - which('torsocks') or skip 'no torsocks', 1 if $url =~ m!\.onion/!; + require_cmd 'curl', 1 or skip 'curl missing', 1; + if ($url =~ m!\.onion/!) { + require_cmd 'torsocks', 1 or skip 'no torsocks', 1; + } my $mid = '20140421094015.GA8962@dcvr.yhbt.net'; my @cmd = ('q', '--only', $url, '-q', "m:$mid"); lei_ok(@cmd, \"query $url"); diff --git a/t/lei-import-http.t b/t/lei-import-http.t index e9eec1f7e895089658ef97b25bbf668beefa742b..d113d47904f15e4f23a606c813e4afe89ea39141 100644 --- a/t/lei-import-http.t +++ b/t/lei-import-http.t @@ -2,9 +2,8 @@ #!perl -w # Copyright (C) 2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; -use PublicInbox::Spawn qw(which); require_mods(qw(lei -httpd)); -which('curl') or plan skip_all => "curl required for $0"; +require_cmd('curl'); my ($ro_home, $cfg_path) = setup_public_inboxes; my ($tmpdir, $for_destroy) = tmpdir; my $sock = tcp_server; diff --git a/t/lei-mirror.t b/t/lei-mirror.t index 4f4c49c18218e8d6c1902bc6ed35827eb2100e88..44acbe95bac6711c8658791b3022d5eae7771d91 100644 --- a/t/lei-mirror.t +++ b/t/lei-mirror.t @@ -4,6 +4,7 @@ # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; use PublicInbox::Inbox; require_mods(qw(-httpd lei)); +require_cmd('curl'); my $sock = tcp_server(); my ($tmpdir, $for_destroy) = tmpdir(); my $http = 'http://'.tcp_host_port($sock); diff --git a/t/lei-q-remote-import.t b/t/lei-q-remote-import.t index aaf56e2732de8b7a9a78e120f9e666fad02af552..9131c01bb6378f7b93f8d09a49653d735dfffee4 100644 --- a/t/lei-q-remote-import.t +++ b/t/lei-q-remote-import.t @@ -3,6 +3,7 @@ # Copyright (C) 2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; require_mods(qw(lei -httpd)); +require_cmd 'curl'; use PublicInbox::MboxReader; my ($ro_home, $cfg_path) = setup_public_inboxes; my $sock = tcp_server; diff --git a/t/lei.t b/t/lei.t index d1f1cbc018290cdbee765f52f84b9d0a2d81bb82..c8f475762153c05d58dc77fcdfa935472bc956ab 100644 --- a/t/lei.t +++ b/t/lei.t @@ -3,11 +3,9 @@ # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ use strict; use v5.10.1; use PublicInbox::TestCommon; use File::Path qw(rmtree); -use PublicInbox::Spawn qw(which); # 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, @_]) }; @@ -156,7 +154,7 @@ } lei_ok('sucks', \'yes, but hopefully less every day'); like($lei_out, qr/loaded features/, 'loaded features shown'); SKIP: { - skip 'no curl', 3 unless which('curl'); + skip 'no curl', 3 unless require_cmd('curl', 1); 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"); diff --git a/t/nntpd.t b/t/nntpd.t index 67205fe5e27006d1d6460ea18b13a8d9590a81bf..3c171a3b88b9fac5860ebfbac416eface8a8a0ee 100644 --- a/t/nntpd.t +++ b/t/nntpd.t @@ -1,10 +1,7 @@ #!perl -w # Copyright (C) 2015-2021 all contributors # License: AGPL-3.0+ -use strict; -use v5.10.1; -use PublicInbox::TestCommon; -use PublicInbox::Spawn qw(which); +use strict; use v5.10.1; use PublicInbox::TestCommon; require_mods(qw(DBD::SQLite)); use PublicInbox::Eml; use Socket qw(IPPROTO_TCP TCP_NODELAY); @@ -17,7 +14,7 @@ # t/nntpd-v2.t wraps this for v2 my $version = $ENV{PI_TEST_VERSION} || 1; require_git('2.6') if $version == 2; use_ok 'PublicInbox::Msgmap'; -my $lsof = which('lsof'); +my $lsof = require_cmd('lsof', 1); my $fast_idle = eval { require Linux::Inotify2; 1 } // eval { require IO::KQueue; 1 }; diff --git a/t/nodatacow.t b/t/nodatacow.t index 9b67c521ffab7ff94e7986735c47683982c89856..19247c109b0931b8340f4f75bc4d189bd5a5577a 100644 --- a/t/nodatacow.t +++ b/t/nodatacow.t @@ -1,11 +1,8 @@ #!perl -w # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ -use strict; -use Test::More; +use strict; use v5.10.1; use PublicInbox::TestCommon; use File::Temp 0.19; -use PublicInbox::TestCommon; -use PublicInbox::Spawn qw(which); use_ok 'PublicInbox::NDC_PP'; SKIP: { @@ -13,8 +10,9 @@ my $nr = 2; skip 'test is Linux-only', $nr if $^O ne 'linux'; my $dir = $ENV{BTRFS_TESTDIR}; skip 'BTRFS_TESTDIR not defined', $nr unless defined $dir; - skip 'chattr(1) not installed', $nr unless which('chattr'); - my $lsattr = which('lsattr') or skip 'lsattr(1) not installed', $nr; + require_cmd('chattr', 1) or skip 'chattr(1) not installed', $nr; + my $lsattr = require_cmd('lsattr', 1) or + skip 'lsattr(1) not installed', $nr; my $tmp = File::Temp->newdir('nodatacow-XXXX', DIR => $dir); my $dn = $tmp->dirname; diff --git a/t/solver_git.t b/t/solver_git.t index f5cc592c6a60822f641028c2c01df0718376c0ab..d5f4c4a02758d4ad8de142f59ef3461c9b067997 100644 --- a/t/solver_git.t +++ b/t/solver_git.t @@ -7,7 +7,7 @@ use PublicInbox::TestCommon; use Cwd qw(abs_path); require_git(2.6); use PublicInbox::ContentHash qw(git_sha); -use PublicInbox::Spawn qw(popen_rd which); +use PublicInbox::Spawn qw(popen_rd); require_mods(qw(DBD::SQLite Search::Xapian Plack::Util)); my $git_dir = xqx([qw(git rev-parse --git-dir)], undef, {2 => \(my $null)}); $? == 0 or plan skip_all => "$0 must be run from a git working tree"; @@ -270,7 +270,7 @@ my ($h, $p) = tcp_host_port($sock); my $url = "http://$h:$p"; local $ENV{PLACK_TEST_EXTERNALSERVER_URI} = $url; Plack::Test::ExternalServer::test_psgi(client => $client); - skip 'no curl', 1 unless which('curl'); + require_cmd('curl', 1) or skip 'no curl', 1; mkdir "$tmpdir/ext" // xbail "mkdir $!"; test_lei({tmpdir => "$tmpdir/ext"}, sub { diff --git a/t/v2mirror.t b/t/v2mirror.t index 2bb3238b3388d00e8157d4bde4c44908da7b9881..8bcffc29265a81cde1037e59f211b3b760726dc0 100644 --- a/t/v2mirror.t +++ b/t/v2mirror.t @@ -1,19 +1,17 @@ # Copyright (C) 2018-2021 all contributors # License: AGPL-3.0+ use strict; -use warnings; -use Test::More; +use v5.10.1; use PublicInbox::TestCommon; use File::Path qw(remove_tree); use Cwd qw(abs_path); require_git(2.6); +require_cmd('curl'); local $ENV{HOME} = abs_path('t'); # Integration tests for HTTP cloning + mirroring require_mods(qw(Plack::Util Plack::Builder HTTP::Date HTTP::Status Search::Xapian DBD::SQLite)); -use IO::Socket; -use POSIX qw(dup2); use_ok 'PublicInbox::V2Writable'; use PublicInbox::InboxWritable; use PublicInbox::Eml; diff --git a/t/v2reindex.t b/t/v2reindex.t index e9f2b73b2b9083060359a45300c2fc286f173853..cafe8648d1e8b0dd1275f6af884585402e5aee70 100644 --- a/t/v2reindex.t +++ b/t/v2reindex.t @@ -1,12 +1,9 @@ # Copyright (C) 2018-2021 all contributors # License: AGPL-3.0+ -use strict; -use warnings; -use Test::More; +use strict; use v5.10.1; use PublicInbox::TestCommon; use PublicInbox::Eml; use PublicInbox::ContentHash qw(content_digest); use File::Path qw(remove_tree); -use PublicInbox::TestCommon; require_git(2.6); require_mods(qw(DBD::SQLite Search::Xapian)); use_ok 'PublicInbox::V2Writable'; @@ -551,9 +548,8 @@ '--xapian-only works'); is($err, '', 'no errors from --xapian-only'); undef $for_destroy; SKIP: { - use PublicInbox::Spawn qw(which); skip 'only testing lsof(8) output on Linux', 1 if $^O ne 'linux'; - my $lsof = which('lsof') or skip 'no lsof in PATH', 1; + my $lsof = require_cmd('lsof', 1) or skip 'no lsof in PATH', 1; my $rdr = { 2 => \(my $null_err) }; my @d = grep(m!/xap[0-9]+/!, xqx([$lsof, '-p', $$], undef, $rdr)); is_deeply(\@d, [], 'no deleted index files') or diag explain(\@d); diff --git a/t/www_altid.t b/t/www_altid.t index 7c2b6b21a0591556cbf47ee3c54347a9ba1c3b88..94a2e807f8d7f3bd4bfd2ad0abf2e03ab34fbf5c 100644 --- a/t/www_altid.t +++ b/t/www_altid.t @@ -1,12 +1,10 @@ #!perl -w # Copyright (C) 2020-2021 all contributors # License: AGPL-3.0+ -use strict; -use v5.10.1; -use PublicInbox::TestCommon; +use strict; use v5.10.1; use PublicInbox::TestCommon; use PublicInbox::Config; -use PublicInbox::Spawn qw(which spawn); -which('sqlite3') or plan skip_all => 'sqlite3 binary missing'; +use PublicInbox::Spawn qw(spawn); +require_cmd('sqlite3'); require_mods(qw(DBD::SQLite HTTP::Request::Common Plack::Test URI::Escape Plack::Builder IO::Uncompress::Gunzip)); use_ok($_) for qw(Plack::Test HTTP::Request::Common); diff --git a/t/www_listing.t b/t/www_listing.t index 5f90139af65bd63f4bd1b667b1d03548c9ae6a5a..eb77969b5039e0b222f029386051e02643bf560a 100644 --- a/t/www_listing.t +++ b/t/www_listing.t @@ -2,11 +2,7 @@ #!perl -w # Copyright (C) 2019-2021 all contributors # License: AGPL-3.0+ # manifest.js.gz generation and grok-pull integration test -use strict; -use v5.10.1; -use Test::More; -use PublicInbox::Spawn qw(which); -use PublicInbox::TestCommon; +use strict; use v5.10.1; use PublicInbox::TestCommon; use PublicInbox::Import; use IO::Uncompress::Gunzip qw(gunzip); require_mods(qw(json URI::Escape Plack::Builder Digest::SHA HTTP::Tiny)); @@ -134,7 +130,7 @@ $td = start_script($cmd, $env, { 3 => $sock }); tiny_test($json, $host, $port, 1); undef $sock; - my $grok_pull = which('grok-pull') or + my $grok_pull = require_cmd('grok-pull', 1) or skip('grok-pull not available', 12); my ($grok_version) = (xqx([$grok_pull, "--version"]) =~ /(\d+)\.(?:\d+)(?:\.(\d+))?/);